unit AsioSetDlgWin;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ClipBrd, Buttons, ComCtrls, StdCtrls,
  _MDXWinINI;

type
  TAsioSetDlg = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    ControlPanelBtn: TButton;
    DriverIndexLst: TComboBox;
    DriverInfoMemo: TMemo;
    LeftChLst: TComboBox;
    RightChLst: TComboBox;
    SaveClipboardBtn: TButton;
    LatencyBufferLbl: TLabel;
    LatencyBufferBar: TTrackBar;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    OKBtn: TBitBtn;
    CancelBtn: TBitBtn;
    Label7: TLabel;
    procedure ControlPanelBtnClick(Sender: TObject);
    procedure LatencyBufferBarChange(Sender: TObject);
    procedure OKBtnClick(Sender: TObject);
    procedure CancelBtnClick(Sender: TObject);
    procedure DriverIndexLstChange(Sender: TObject);
    procedure LeftChLstChange(Sender: TObject);
    procedure RightChLstChange(Sender: TObject);
    procedure SaveClipboardBtnClick(Sender: TObject);
  private
    { Private 宣言 }
    CAsioINI:TOutAsioINI;
    LBMin,LBMax,LBPref,LBGran:integer;
    Changing:boolean;
    procedure ChangeEnabled(DriverIndex:integer);
  public
    { Public 宣言 }
    procedure SetCreate;
  end;

var
  AsioSetDlg: TAsioSetDlg;

implementation

uses _Asio_Moonlight,_const;

{$R *.dfm}

procedure TAsioSetDlg.SetCreate;
begin
  if OutAsio=nil then OutAsio:=TOutAsio.Create;
  OKBtn.Enabled:=ASIO_GetOpenAsioLoaded;

  CAsioINI:=OutAsioINI;

  Changing:=True;
  ChangeEnabled(CAsioINI.DriverIndex);
  Changing:=False;

  LatencyBufferBarChange(nil);
end;

procedure TAsioSetDlg.ControlPanelBtnClick(Sender: TObject);
begin
  OutASIO.OpenSetting(CAsioINI.DriverIndex);

  Changing:=True;
  ChangeEnabled(CAsioINI.DriverIndex);
  Changing:=False;
end;

procedure TAsioSetDlg.ChangeEnabled(DriverIndex:integer);
var
  cnt:integer;
  chmsg:string;
begin
  DriverIndexLst.Clear;
  for cnt:=0 to OutASIO.DriverListCount-1 do begin
    DriverIndexLst.Items.Add(OutASIO.DriverList[cnt].name);
  end;

  DriverInfoMemo.Text:=OutAsio.GetDriverInfo(DriverIndex);

//  GetDriverInfoした後はOutASIO.ChannelInfo[]も更新されている。

  LeftChLst.Clear;
  RightChLst.Clear;
  for cnt:=0 to OutASIO.ChannelCount-1 do begin
    with OutASIO.ChannelInfo[cnt] do begin
      chmsg:='ch'+inttostr(channel)+':'+ASIO_ChannelTypeToString(vType)+' ['+name+']';
    end;
    LeftChLst.Items.Add(chmsg);
    RightChLst.Items.Add(chmsg);
  end;

  DriverIndexLst.ItemIndex:=CAsioINI.DriverIndex;
  LeftChLst.ItemIndex:=CAsioINI.LeftCh;
  RightChLst.ItemIndex:=CAsioINI.RightCh;

  OutASIO.GetBufferSize(CAsioINI.DriverIndex,LBMin,LBMax,LBPref,LBGran);

  if (CAsioINI.LatencyBuffer<LBMin) or (LBMax<CAsioINI.LatencyBuffer) then begin
    CAsioINI.LatencyBuffer:=LBPref;
  end;

  LatencyBufferBar.Position:=LBMin;
  LatencyBufferBar.Max:=LBMin;
  LatencyBufferBar.Min:=LBMin-1;
  LatencyBufferBar.Max:=LBMax;
  LatencyBufferBar.Position:=CAsioINI.LatencyBuffer;
  LatencyBufferBar.Frequency:=LBGran;
end;

procedure TAsioSetDlg.OKBtnClick(Sender: TObject);
var
  lb:integer;
  lvt,rvt:integer;
  useMSB,useFlortLSB,useInt24LSB,useNotSupport:boolean;
  procedure CheckChType(outtype:integer);
  begin
    useMSB:=False;
    useFlortLSB:=False;
    useInt24LSB:=False;
    useNotSupport:=False;

    case outtype of
      ASIOSTInt16MSB: useMSB:=True;
      ASIOSTInt24MSB: useMSB:=True;
      ASIOSTInt32MSB: useMSB:=True;
      ASIOSTFloat32MSB: useMSB:=True;
      ASIOSTFloat64MSB: useMSB:=True;

      ASIOSTInt32MSB16: useMSB:=True;
      ASIOSTInt32MSB18: useMSB:=True;
      ASIOSTInt32MSB20: useMSB:=True;
      ASIOSTInt32MSB24: useMSB:=True;

      ASIOSTInt16LSB: begin end;
      ASIOSTInt24LSB: useInt24LSB:=True;
      ASIOSTInt32LSB: begin end;
      ASIOSTFloat32LSB: useFlortLSB:=True;
      ASIOSTFloat64LSB: useFlortLSB:=True;

      ASIOSTInt32LSB16: useNotSupport:=True;
      ASIOSTInt32LSB18: useNotSupport:=True;
      ASIOSTInt32LSB20: useNotSupport:=True;
      ASIOSTInt32LSB24: useNotSupport:=True;
    end;
  end;
begin
  if LatencyBufferBar.Min=LatencyBufferBar.Position then begin
    lb:=LBPref;
    end else begin
    lb:=(LatencyBufferBar.Position div LBGran)*LBGran;
  end;

  if lb<LBPref then begin
    if MessageDlg('警告！レイテンシがドライバ推奨値未満に設定されています。'+CRLF+'重すぎて応答無しになって再起動を余儀なくされるかもしれません。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;

  if (LeftChLst.ItemIndex<0) or (RightChLst.ItemIndex<0) then begin
    if MessageDlg('左右の出力チャネルが割り当てられていません。'+CRLF+CRLF+'設定画面に戻ります。',mtWarning,[mbYes],0)=mrYes then exit;
  end;

  with OutASIO do begin
    lvt:=ChannelInfo[LeftChLst.ItemIndex].vType;
    rvt:=ChannelInfo[RightChLst.ItemIndex].vType;
    if lvt<>rvt then begin
      if MessageDlg('左右チャネルの出力フォーマットが別々になっています。'+CRLF+'対応できなくもないのですが余り意味が無さそうなので非対応です。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
    end;
  end;

  CheckChType(lvt);
  if useMSB=True then begin
    if MessageDlg('左チャネルがMSBシリーズの出力フォーマットになっています。'+CRLF+'仕様がよくわからないので対応していません。すいません…。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;
  if useFlortLSB=True then begin
    if MessageDlg('左チャネルが浮動小数点LSBシリーズの出力フォーマットになっています。'+CRLF+'一応音は出るようになっていますが未確認です。'+CRLF+'大きなノイズが出る可能性が高いので、テストするときは必ずボリュームを０にしてから再生して下さい。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;
  if useInt24LSB=True then begin
    if MessageDlg('左チャネルがInt24LSBの出力フォーマットになっています。'+CRLF+'たぶん音が出ると思います…。'+CRLF+'大きなノイズが出る可能性が高いので、テストするときは必ずボリュームを０にしてから再生して下さい。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;
  if useNotSupport=True then begin
    if MessageDlg('左チャネルが未サポートの出力フォーマットになっています。'+CRLF+'仕様がよくわからないので対応していません。すいません…。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;

  CheckChType(rvt);
  if useMSB=True then begin
    if MessageDlg('右チャネルがMSBシリーズの出力フォーマットになっています。'+CRLF+'仕様がよくわからないので対応していません。すいません…。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;
  if useFlortLSB=True then begin
    if MessageDlg('右チャネルが浮動小数点LSBシリーズの出力フォーマットになっています。'+CRLF+'一応音は出るようになっていますが未確認です。'+CRLF+'大きなノイズが出る可能性が高いので、テストするときは必ずボリュームを０にしてから再生して下さい。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;
  if useInt24LSB=True then begin
    if MessageDlg('右チャネルがInt24LSBの出力フォーマットになっています。'+CRLF+'たぶん音が出ると思います…。'+CRLF+'大きなノイズが出る可能性が高いので、テストするときは必ずボリュームを０にしてから再生して下さい。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;
  if useNotSupport=True then begin
    if MessageDlg('右チャネルが未サポートの出力フォーマットになっています。'+CRLF+'仕様がよくわからないので対応していません。すいません…。'+CRLF+CRLF+'設定画面に戻りますか？',mtWarning,[mbYes,mbNo],0)=mrYes then exit;
  end;

  with OutAsioINI do begin
    DriverIndex:=DriverIndexLst.ItemIndex;
    LeftCh:=LeftChLst.ItemIndex;
    RightCh:=RightChLst.ItemIndex;
    LatencyBuffer:=lb;
  end;

  AsioSetDlg.Visible:=False;
end;

procedure TAsioSetDlg.CancelBtnClick(Sender: TObject);
begin
  OutAsioINI:=CAsioINI;
  AsioSetDlg.Visible:=False;
end;

procedure TAsioSetDlg.DriverIndexLstChange(Sender: TObject);
begin
  if Changing=True then exit;

  Changing:=True;
  CAsioINI.DriverIndex:=DriverIndexLst.ItemIndex;
  ChangeEnabled(CAsioINI.DriverIndex);
  Changing:=False;
end;

procedure TAsioSetDlg.LeftChLstChange(Sender: TObject);
begin
  if Changing=True then exit;

  Changing:=True;
  CAsioINI.LeftCh:=LeftChLst.ItemIndex;
  Changing:=False;
end;

procedure TAsioSetDlg.RightChLstChange(Sender: TObject);
begin
  if Changing=True then exit;

  Changing:=True;
  CAsioINI.RightCh:=RightChLst.ItemIndex;
  Changing:=False;
end;

procedure TAsioSetDlg.LatencyBufferBarChange(Sender: TObject);
var
  lb:integer;
begin
  if Changing=True then exit;

  Changing:=True;

  if LatencyBufferBar.Min=LatencyBufferBar.Position then begin
    lb:=LBPref;
    end else begin
    lb:=(LatencyBufferBar.Position div LBGran)*LBGran;
  end;

  CAsioINI.LatencyBuffer:=lb;
  LatencyBufferLbl.Caption:='レイテンシバッファ '+inttostr(lb)+'samples.';

  Changing:=False;
end;

procedure TAsioSetDlg.SaveClipboardBtnClick(Sender: TObject);
begin
  ClipBoard.AsText:=DriverInfoMemo.Text;
end;

end.
