unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, VclTee.TeeGDIPlus,
  VCLTee.TeEngine, Vcl.ExtCtrls, VCLTee.TeeProcs, VCLTee.Chart, math,
  VCLTee.Series;

  function Init(Secure: String; Owner: String) : Integer; external 'MLib.dll' name 'Init';
  function GetDeviceList(var devPlayList, devRecordList, devUsbList: TStringList) : Integer;  external 'MLib.dll' name 'GetDeviceList';
  function SetDevice(playDev, recDev, usbDev: String): Integer;  external 'MLib.dll' name 'SetDevice';
  function DelayFinder(qChannels, mesUnit, timeShift: integer; freqMask: array of byte; var resLeft, resRight: array of double): integer;  external 'MLib.dll' name 'DelayFinder';
  function RtaMeasure(Octave: integer; var octaveRes, freqRes: array of double): integer; external 'MLib.dll' name 'RtaMeasure';

const
  MEASURE_ERROR = 6;
  SET_DEV_ERROR = 5;
  LIC_ERROR = 4;
  LIC_ERROR_1 = 3;
  LIC_ERROR_2 = 2;
  TIME_ERROR = 1;
  SUCCESS = 0;

  K = 16000;

type
  TForm1 = class(TForm)
    GroupBox1: TGroupBox;
    cbbPlayDev: TComboBox;
    btnGetDevList: TButton;
    Label3: TLabel;
    Label5: TLabel;
    cbbRecDev: TComboBox;
    gbLic: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    edLicSec: TEdit;
    edOwner: TEdit;
    btnCheckLic: TButton;
    Label4: TLabel;
    cbbUsbAudioDev: TComboBox;
    btnSetDev: TButton;
    GroupBox2: TGroupBox;
    cbbChannels: TComboBox;
    Label6: TLabel;
    Label7: TLabel;
    cbbFreqStart: TComboBox;
    cbbFreqEnd: TComboBox;
    Label8: TLabel;
    cbbUnit: TComboBox;
    lblTimeShift: TLabel;
    sbTimeShift: TScrollBar;
    btnStart: TButton;
    chrtGraph1: TChart;
    Series1: TLineSeries;
    chrtGraph2: TChart;
    Series2: TLineSeries;
    chrtGraphDiff: TChart;
    Series3: TLineSeries;
    Label9: TLabel;
    cbbFreqRate: TComboBox;
    Label10: TLabel;
    cbbMesType: TComboBox;
    cbbOctaves: TComboBox;
    procedure btnCheckLicClick(Sender: TObject);
    procedure btnGetDevListClick(Sender: TObject);
    procedure btnSetDevClick(Sender: TObject);
    procedure sbTimeShiftChange(Sender: TObject);
    procedure btnStartClick(Sender: TObject);
    procedure cbbChannelsChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure cbbMesTypeChange(Sender: TObject);
  private
    { Private declarations }
    tmpChannels: integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnCheckLicClick(Sender: TObject);
var
  res: Integer;
  cDir: string;
  sl: TStringList;
begin
  res := Init(edLicSec.Text, edOwner.Text);
  if (res = SUCCESS) then
  begin
    Application.MessageBox('License OK!', 'Test License', MB_OK or MB_ICONINFORMATION);
    try
      sl := TStringList.Create();
      sl.Add(edLicSec.Text);
      sl.Add(edOwner.Text);
      cDir := GetCurrentDir() + '\opt.sic';
      sl.SaveToFile(cDir);
    finally
      sl.Free();
    end;
  end
  else if (res = LIC_ERROR_1) then Application.MessageBox('License ERROR 1!', 'Test License', MB_OK or MB_ICONERROR)
  else if (res = LIC_ERROR_2) then Application.MessageBox('License ERROR 2!', 'Test License', MB_OK or MB_ICONERROR)
  else  Application.MessageBox('License FAILED!', 'Time License expired!', MB_OK or MB_ICONERROR);
end;

procedure TForm1.btnGetDevListClick(Sender: TObject);
var
  valid: Integer;
  playDev, recDev, usbDev: TStringList;
  i: integer;
begin
//1
  try
    valid := GetDeviceList(playDev, recDev, usbDev);
    if (valid = LIC_ERROR) then Application.MessageBox('License INVALID!!!','Error',MB_OK or MB_ICONERROR)
    else if (valid = SUCCESS) then
    begin
      cbbPlayDev.Items.Clear();
      for i := 0 to playDev.Count - 1 do cbbPlayDev.Items.Add(playDev[i]);
      cbbPlayDev.ItemIndex := 0;

      cbbRecDev.Items.Clear();
      cbbRecDev.Items.Add('none');
      for i := 0 to recDev.Count - 1 do cbbRecDev.Items.Add(recDev[i]);
      cbbRecDev.ItemIndex := 0;

      cbbUsbAudioDev.Items.Clear();
      for i := 0 to usbDev.Count - 1 do cbbUsbAudioDev.Items.Add(usbDev[i]);
      cbbUsbAudioDev.ItemIndex := 0;

      Application.MessageBox(PChar(String.Format('Number of devices detected: %d',
                             [cbbPlayDev.Items.Count + cbbRecDev.Items.Count + cbbUsbAudioDev.Items.Count - 1])),'Information',MB_OK or MB_ICONINFORMATION);
    end;
  finally
    if (Assigned(playDev)) then playDev.Free();
    if (Assigned(recDev)) then recDev.Free();
    if (Assigned(usbDev)) then usbDev.Free();
  end;
end;

procedure TForm1.btnSetDevClick(Sender: TObject);
var
  valid: Integer;
begin
// 2
  valid := SetDevice(cbbPlayDev.Text, cbbRecDev.Text, cbbUsbAudioDev.Text);
  if (valid = LIC_ERROR) then Application.MessageBox('License INVALID!!!','Error',MB_OK or MB_ICONERROR)
  else if (valid = SET_DEV_ERROR) then Application.MessageBox('Set device ERROR!!!','Error',MB_OK or MB_ICONEXCLAMATION)
  else Application.MessageBox('Devices have been successfully set!','Information',MB_OK or MB_ICONINFORMATION);

end;

procedure TForm1.btnStartClick(Sender: TObject);
var
  i, bg, ed, rate, rtd: integer;
  freqRange: array of byte;
  resLeft, resRight, octaveRes, freqRes: array of double;
begin
  try
    if (cbbMesType.ItemIndex = 0) then
    begin
      SetLength(freqRange, K);
      bg := StrToInt(cbbFreqStart.Text);
      ed := StrToInt(cbbFreqEnd.Text);
      rate := cbbFreqRate.ItemIndex + 1;
      rtd := rate;

      for i := 0 to (K - 1) do
        begin
          freqRange[i] := 0;
          if (i >= bg) and (i <= ed) then
          begin
            if (rtd = rate) then freqRange[i] := 1;
          end;
          dec(rtd);
          if (rtd = 0) then rtd := rate;
        end;
    end;

    Screen.Cursor := crHourGlass;
    Application.ProcessMessages();
    if (cbbMesType.ItemIndex = 0) then
    begin
      SetLength(resLeft, K);
      SetLength(resRight, K);
      i := DelayFinder(cbbChannels.ItemIndex + 1, cbbUnit.ItemIndex, sbTimeShift.Position, freqRange, resLeft, resRight);
    end else
    begin
      SetLength(octaveRes, 8192); // Посчитать размер массива в зависимости от числа октав или определить максимум
      SetLength(freqRes, 8192); // Посчитать размер массива в зависимости от числа октав или определить максимум
      i := RtaMeasure(cbbOctaves.ItemIndex, octaveRes, freqRes);
    end;

    if (i = LIC_ERROR) then Application.MessageBox('License INVALID!!!','Error',MB_OK or MB_ICONERROR)
    else if (i = SET_DEV_ERROR) then Application.MessageBox('Set device ERROR!!!','Error',MB_OK or MB_ICONEXCLAMATION)
    else if (i = MEASURE_ERROR) then Application.MessageBox('Measure ERROR!!!','Error',MB_OK or MB_ICONEXCLAMATION)
    else
    begin
      // Обработка успешного измерения
      chrtGraph1.Series[0].Clear();
      chrtGraph2.Series[0].Clear();
      chrtGraphDiff.Series[0].Clear();
      if (cbbMesType.ItemIndex = 0) then
      begin
        for i := 0 to Length(resLeft) - 1 do
        begin
          if (freqRange[i] <> 0) then chrtGraph1.Series[0].AddXY(i + 1, resLeft[i]);
        end;
        if (cbbChannels.ItemIndex = 1) then
        begin
          for i := 0 to Length(resRight) - 1 do
          begin
            if (freqRange[i] <> 0) then chrtGraph2.Series[0].AddXY(i + 1, resRight[i]);
          end;
          for i := 0 to min(Length(resRight) - 1, Length(resLeft) - 1)  do
          begin
            if (freqRange[i] <> 0) then chrtGraphDiff.Series[0].AddXY(i + 1, resLeft[i] - resRight[i]);
          end;
        end;
      end else
      begin
        // Обработаем результат октав
        for i := 0 to Length(octaveRes) - 1 do
        begin
          if (freqRes[i] = 0) then break;          
          chrtGraph1.Series[0].AddXY(freqRes[i], octaveRes[i]);
        end;
      end;

      Application.MessageBox('Measurement complete!','Information',MB_OK or MB_ICONINFORMATION);
    end;

  finally
    Screen.Cursor := crDefault;
    SetLength(freqRange, 0);
    SetLength(resLeft, 0);
    SetLength(resRight, 0);
    SetLength(octaveRes, 0);
  end;
end;

procedure TForm1.cbbChannelsChange(Sender: TObject);
var
  w, h: integer;
begin
  if (cbbChannels.ItemIndex = 0) then
  begin
    chrtGraph2.Visible := false;
    chrtGraphDiff.Visible := false;
    chrtGraph1.Width := self.Width - 28;
    chrtGraph1.Height := self.Height - GroupBox2.Top - GroupBox2.Height - 50;
  end else
  begin
    chrtGraph2.Visible := true;
    chrtGraphDiff.Visible := true;
    w := (self.Width div 2) - 28;
    chrtGraph1.Width := w;
    chrtGraph2.Width := w + 14;
    chrtGraphDiff.Width := self.Width - 28;
    h := ((self.Height - GroupBox2.Top - GroupBox2.Height) div 2) - 50;
    chrtGraph1.Height := h;
    chrtGraph2.Height := h;
    chrtGraphDiff.Height := h;
    chrtGraph2.Left := chrtGraph1.Left + chrtGraph1.Width + 14;
    chrtGraph2.Top := chrtGraph1.Top;
    chrtGraphDiff.Top := chrtGraph1.Top + chrtGraph1.Height + 14;
  end;
end;

procedure TForm1.cbbMesTypeChange(Sender: TObject);
begin
//1
  if (cbbMesType.ItemIndex = 0) then
  begin
    Label7.Caption := 'Frequency range:';
    cbbFreqStart.Visible := true;
    cbbFreqEnd.Visible := true;
    cbbOctaves.Visible := false;
    Label6.Visible := true;
    Label8.Visible := true;
    Label9.Visible := true;
    lblTimeShift.Visible := true;
    sbTimeShift.Visible := true;
    cbbChannels.Visible := true;
    cbbChannels.ItemIndex := tmpChannels;
    cbbUnit.Visible := true;
    cbbChannelsChange(cbbChannels);
    cbbFreqRate.Visible := true;
    chrtGraph1.Title.Text[0] := 'Delay Graph Left';
  end else
  begin
    Label7.Caption := 'Octaves:';
    cbbFreqStart.Visible := false;
    cbbFreqEnd.Visible := false;
    cbbOctaves.Visible := true;
    Label6.Visible := false;
    Label8.Visible := false;
    Label9.Visible := false;
    lblTimeShift.Visible := false;
    sbTimeShift.Visible := false;
    cbbUnit.Visible := false;
    cbbFreqRate.Visible := false;
    tmpChannels := cbbChannels.ItemIndex;
    cbbChannels.ItemIndex := 0;
    cbbChannelsChange(cbbChannels);
    cbbChannels.Visible := false;
    chrtGraph1.Title.Text[0] := 'RTA Octaves';
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  sl: TStringList;
  cDir: string;
begin
  cbbChannelsChange(cbbChannels);
  sl := TStringList.Create();
  try
    cDir := GetCurrentDir() + '\opt.sic';
    if (FileExists(cDir)) then
    begin
      sl.LoadFromFile(cDir);
      if (sl.Count > 1) then
      begin
        edLicSec.Text := sl[0];
        edOwner.Text := sl[1];
      end;
    end;
  finally
    sl.Free();
  end;
end;

procedure TForm1.FormResize(Sender: TObject);
begin
  cbbChannelsChange(cbbChannels);
end;

procedure TForm1.sbTimeShiftChange(Sender: TObject);
begin
  lblTimeShift.Caption := string.Format('Time shift: %d msec.',[sbTimeShift.Position]);
end;

end.
