unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, bass, Vcl.StdCtrls, DTMFScannerLibrary;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button2: TButton;
    Label2: TLabel;
    Edit2: TEdit;
    ComboBoxInput: TComboBox;
    Label1: TLabel;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  protected
    procedure WndProc(var Message: TMessage); override;
  public
    { Public declarations }
    procedure ListDevices;
  end;

Const
    MSG_DTMF_DETECTED = WM_USER * 4 + 111;

var
  Form1: TForm1;
  Counter: Integer;

implementation

{$R *.dfm}

procedure TForm1.ListDevices;
var
    Device: AnsiString;
    Count: Integer;
    Info: BASS_DEVICEINFO;
begin
    ComboBoxInput.Items.Clear;
    Count := 0;
    while BASS_RecordGetDeviceInfo(count, Info) do begin
        Device := Info.name;
        ComboBoxInput.Items.Add(String(Device));
        Inc(Count);
    end;
    ComboBoxInput.ItemIndex := - 1;
    ComboBoxInput.Text := 'Select...';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    BASS_Init(- 1, 44100, 0, Handle, nil);
    ListDevices;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
    BASS_Free;
end;

procedure TForm1.WndProc(var Message: TMessage);
begin
    case Message.Msg of
        MSG_DTMF_DETECTED: begin
            Form1.Memo1.Lines.Append('Tone detected: ' + Char(Message.WParam));
        end;
    else inherited WndProc(Message);
    end;
end;

function DetectCallback(DTMF: Integer; Status: TDTElementType; Position: Single; User: UInt64): Integer; stdcall;
begin
    //* List only new detections
    if Status = dtetStart then begin
        //* This callback is called from a thread, no UI access is allowed in threads so send the params to the main thread
        PostMessage(Form1.Handle, MSG_DTMF_DETECTED, wParam(DTMF), 0);
        Inc(Counter);
    end;
    Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
    //* Freeing the channel handle automatically terminates the scanning thread
    BASS_RecordFree;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
    Parameters: TDTMFScannerParameters;
    ChannelInput: HRecord;
begin
    //StopProcessing := False;
    BASS_RecordFree;
    BASS_RecordInit(ComboBoxInput.ItemIndex);
    //* Always use BASS_SAMPLE_FLOAT flag
    ChannelInput := BASS_RecordStart(11025, 1, BASS_SAMPLE_FLOAT, nil, nil);
    Counter := 0;
    Parameters.FileName := nil;
    Parameters.Channel := ChannelInput;
    Parameters.Treshold := StrToFloat(Edit2.Text);
    Parameters.Thread := True;
    Parameters.User := 0;
    Parameters.DetectCallback := DetectCallback;
    DTMFScan(Parameters);
end;

end.
