Jump to content

Recommended Posts

Posted

hi, 
I made a software for managing dtmf tones. 
For the moment the pc audio output is connected to an Arduino with an mt8870 module which decodes the tone and returns the correct value via serial. 
I wanted to make sure not to use external hardware and so I tried with the bass.dll library to read the microphone input. 
I can read the volume and interpret the data, but I haven't found a way to handle the dtmfs. 
Searching the internet I found a project with source in Delphi and C++ with examples to import a library called DTMFScanner.dll (https://www.3delite.hu/Object Pascal Developer Resources/download.html#dtmf)
the DTMFScannerLibrary.h file is attached to this post.
There are examples on how to use the external library with Delphi too
I tried to modify an example of the bass library to integrate the request for the DTMFScanner.dll library but it always returns the value 0. 
I'm afraid I'm using the wrong library recall method
This is my script:
 

#include 'Bass.au3'
#include <WinAPICOM.au3>
#include <WinAPIConv.au3>
#include <Array.au3>

Global $hStream, $iLong, $nLeft, $nRight, $iColor

Global $ID_GUI = GUICreate('BASS Audio Levels', 190, 200, -1, -1, Default, 0x00000008)
GUICtrlCreateLabel('L', 52, 20, 34, 22)
GUICtrlCreateLabel('R', 82, 20, 34, 22)
Global $ProgressBarL = GUICtrlCreateProgress(50, 40, 14, 100, 0x04)
Global $ProgressBarR = GUICtrlCreateProgress(80, 40, 14, 100, 0x04)
Global $InputL = GUICtrlCreateLabel('', 50, 150, 34, 22)
Global $InputR = GUICtrlCreateLabel('', 80, 150, 34, 22)

Global $DtmlDLL
Global $parameters = DllStructCreate("ptr FileName; dword Channel; float Treshold; int Thread; int64 User; ptr DetectCallback")
Global $inputChannel = 3    ;<------- my mic input

Global $result1

GUISetOnEvent(-3, '_Exit')
Opt('GUIOnEventMode', 1)
GUISetState(@SW_SHOW, $ID_GUI)

_BASS_Startup(@ScriptDir & '\Bass.dll')
If @error Then Exit MsgBox(16, 'BASS Function Error', 'EC1')
_BASS_Init(16, -1, 44100, 0, 'NULL')
If @error Then Exit MsgBox(16, 'BASS Function Error', 'EC2')
_BASS_RecordInit(-1)
If @error Then Exit MsgBox(16, 'BASS Function Error', 'EC3')
; choose input. I use n.3 in this moment
_BASS_RecordSetInput($inputChannel, $BASS_INPUT_TYPE_WAVE, 1)
;~ Global $hStream = _BASS_RecordStart(44100, 2, 0, 0)
Global $hStream = _BASS_RecordStart(44100, 2, $BASS_SAMPLE_FLOAT);_WinAPI_MakeLong(0, 10))
If @error Then Exit MsgBox(16, 'BASS Function Error', 'EC4')
_BASS_ChannelPlay($hStream, True)
If @error Then Exit MsgBox(16, 'BASS Function Error', 'EC5')

While _BASS_ChannelIsActive($hStream)
    ;********************************* VUMETER WITH BASS.DLL *******************************************************
    $iLong = _BASS_ChannelGetLevel($hStream)
    $nLeft = _BASS_LoWord($iLong) / 32768 * 100
    $nRight = _BASS_HiWord($iLong) / 32768 * 100
    $nLeft = Round($nLeft)
    $nRight = Round($nRight)
    ;
    $iColor = 0xFFFFFF
    If $nLeft > 99 Then $iColor = 0xFF0000
    GUICtrlSetColor($ProgressBarL, $iColor)
    $iColor = 0xFFFFFF
    If $nRight > 99 Then $iColor = 0xFF0000
    GUICtrlSetColor($ProgressBarR, $iColor)
    ;
    GUICtrlSetData($ProgressBarL, $nLeft)
    GUICtrlSetData($ProgressBarR, $nRight)
    GUICtrlSetData($InputL, $nLeft); <-- Left numeric audio level
    GUICtrlSetData($InputR, $nRight); <-- Right numeric audio level
    ;
    Sleep(10)

    ;********************************* LOAD EXTERNAL DTMFScanner.dll *******************************************************
    $DtmlDLL = DllOpen("DTMFScanner.dll")
    if @error then
        ConsoleWrite("DTMFScanner.dll Load Error!!" & @CRLF)
    Else
        ConsoleWrite("DTMFScanner external Funcion ok" & @CRLF)
        $parameters = DllStructCreate("ptr FileName; dword Channel; float Treshold; int Thread; int64 User; ptr DetectCallback")
        DllStructSetData($parameters, "FileName", DllStructCreate("wchar[260]"))
        DllStructSetData($parameters, "Channel", $inputChannel)
        DllStructSetData($parameters, "Treshold", 0.5)
        DllStructSetData($parameters, "Thread", 0)
        DllStructSetData($parameters, "User", 0)
        DllStructSetData($parameters, "DetectCallback", "DetectCallback")
        $result = DllCall($DtmlDLL, "int", "DTMFScan", "ptr", DllStructGetPtr($parameters))
        if @error then ConsoleWrite("error = " & @error & @CRLF)
        DllClose($DtmlDLL)
        ConsoleWrite("DTMF = " & $result[0] & " - other returned values (I don't know which ones): " &  ($result[1]) & @CRLF)
    EndIf
    Sleep(40)
WEnd

Func _Exit()
    _BASS_RecordFree()
    _BASS_Free()
    GUIDelete($ID_GUI)
    Exit
EndFunc

DTMFScannerLibrary.h:

//********************************************************************************************************************************
//*                                                                                                                              *
//*     DTMF Scanner Library 1.0.4.25 © 3delite 2023                                                                             *
//*     See DTMF Scanner Library ReadMe.txt for details.                                                                         *
//*                                                                                                                              *
//* Licenses available for usege of this library:                                                                                *
//* Freeeware License: €15                                                                                                       *
//*     http://www.shareit.com/product.html?productid=301011183                                                                  *
//* Shareware License: €25                                                                                                       *
//*     http://www.shareit.com/product.html?productid=301011182                                                                  *
//* Commercial License: €125                                                                                                     *
//*     http://www.shareit.com/product.html?productid=301011181                                                                  *
//*                                                                                                                              *
//*     https://www.3delite.hu/Object%20Pascal%20Developer%20Resources/DTMFScannerLibrary.html                                   *
//*                                                                                                                              *
//* If you have any questions or enquiries please mail: 3delite@3delite.hu                                                       *
//*                                                                                                                              *
//* Good coding! :)                                                                                                              *
//* 3delite                                                                                                                      *
//********************************************************************************************************************************

#pragma once

#ifdef _WIN32 // Windows
//* .dll file name
#define FILENAME_DLL_DTMF_SCANNER_LIBRARY		"DTMFScanner.dll"
#define DTMFSLIBCALL __stdcall

//* Exported function names (Windows)
#define NAME_DTMFScan			"DTMFScan"

#endif

//*	Error codes
#define DTMFSL_OK                       		= 0
#define DTMFSL_ERROR                    		= 1

#ifdef _WIN32
#include <wtypes.h>
typedef unsigned __int64 QWORD;
#else
#include <stdint.h>
#define WINAPI
#define CALLBACK
typedef uint8_t BYTE;
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef uint64_t QWORD;
typedef void* HANDLE;
#ifndef __OBJC__
typedef int BOOL;
#endif
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#endif

typedef enum
{
	dtetStart		= 0,
	dtetContinuing	= 1,
	dtetEnd			= 2
} TDTElementType;

//* Callback
typedef int(DTMFSLIBCALL *TDetectCallback)(int DTMF, TDTElementType Status, float Position, QWORD User);

typedef struct {
	LPWSTR FileName;
	DWORD Channel;
	float Treshold;
	BOOL Thread;
	QWORD User;
	TDetectCallback DetectCallback;
} *PDTMFScannerParameters, TDTMFScannerParameters;

//* Exported functions
typedef int(DTMFSLIBCALL* t_DTMFScan)(TDTMFScannerParameters* Parameters);

#ifdef __cplusplus
extern "C" {
#endif

	static HMODULE DTMFScannerLibraryDLLHandle = NULL;
	BOOL DTMFScannerLibraryDLLLoaded = FALSE;

	t_DTMFScan DTMFScan = NULL;

#ifdef __cplusplus
}
#endif

BOOL InitDTMFScannerLibrary()
{
	DTMFScannerLibraryDLLHandle = LoadLibrary(FILENAME_DLL_DTMF_SCANNER_LIBRARY);
	if (NULL != DTMFScannerLibraryDLLHandle)
	{
		DTMFScan = (t_DTMFScan)GetProcAddress(DTMFScannerLibraryDLLHandle, NAME_DTMFScan);
		if (NULL == DTMFScan)
		{
			DTMFScannerLibraryDLLLoaded = FALSE;
			}
		else
		{
			DTMFScannerLibraryDLLLoaded = TRUE;
		}
	}

	return DTMFScannerLibraryDLLLoaded;
}

BOOL FreeDTMFScannerLibrary()
{
	if (NULL != DTMFScannerLibraryDLLHandle)
	{
		DTMFScannerLibraryDLLLoaded = !FreeLibrary(DTMFScannerLibraryDLLHandle);
	}
	return !DTMFScannerLibraryDLLLoaded;
}

DTMFScannerLibrary.pas:

//********************************************************************************************************************************
//*                                                                                                                              *
//*     DTMF Scanner Library 1.0.4.25 © 3delite 2023                                                                             *
//*     See DTMF Scanner Library ReadMe.txt for details.                                                                         *
//*                                                                                                                              *
//* Licenses available for usege of this library:                                                                                *
//* Freeeware License: €15                                                                                                       *
//*     http://www.shareit.com/product.html?productid=301011183                                                                  *
//* Shareware License: €25                                                                                                       *
//*     http://www.shareit.com/product.html?productid=301011182                                                                  *
//* Commercial License: €125                                                                                                     *
//*     http://www.shareit.com/product.html?productid=301011181                                                                  *
//*                                                                                                                              *
//*     https://www.3delite.hu/Object%20Pascal%20Developer%20Resources/DTMFScannerLibrary.html                                   *
//*                                                                                                                              *
//* If you have any questions or enquiries please mail: 3delite@3delite.hu                                                       *
//*                                                                                                                              *
//* Good coding! :)                                                                                                              *
//* 3delite                                                                                                                      *
//********************************************************************************************************************************

unit DTMFScannerLibrary;

interface

type
    TDTElementType = (dtetStart, dtetContinuing, dtetEnd);

type
    TDetectCallback = function(DTMF: Integer; Status: TDTElementType; Position: Single; User: UInt64): Integer; stdcall;

type
    PDTMFScannerParameters = ^TDTMFScannerParameters;
    TDTMFScannerParameters = record
        FileName: PChar;
        Channel: Cardinal;
        Treshold: Single;
        Thread: LongBool;
        User: Int64;
        DetectCallback: TDetectCallback;
    end;

    function DTMFScan(var Parameters: TDTMFScannerParameters): Integer; stdcall; external 'DTMFScanner.dll';

implementation

end.

Delphi Example:

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.

the return in debug is always 0 and another values that change:

DTMFScanner external Funcion ok
DTMF = 0 - other returned values (I don't know which ones): 0x02642090
DTMFScanner external Funcion ok
DTMF = 0 - other returned values (I don't know which ones): 0x02642748
DTMFScanner external Funcion ok
DTMF = 0 - other returned values (I don't know which ones): 0x02643A58
DTMFScanner external Funcion ok
DTMF = 0 - other returned values (I don't know which ones): 0x02642860
DTMFScanner external Funcion ok
DTMF = 0 - other returned values (I don't know which ones): 0x02642748
DTMFScanner external Funcion ok
DTMF = 0 - other returned values (I don't know which ones): 0x02643BE8

Any idea to implement the DTMFScanner.dll?

Thankyou very much!

Marco

bass.dll DTMFScanner.dll Bass.au3 DTMFScannerLibrary.h Unit1.pas DTMFScannerLibrary.pas

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...