Author Topic: How can I simply get microphone volume data using Lazarus?  (Read 212 times)

fbenites

  • Posts: 4
Part of my application in Lazarus specifies an event when someone screams.
I'm using Lazarus and have no clue how to simply get mic activity.

I'm trying to use some examples to start from, but having headaches troubleshooting RecordStart declaration:

 Incompatible type for arg no. 4: Got "<address of function(LongWord;Pointer;LongWord;LongWord):Boolean;StdCall>", expected "<procedure variable type of function(LongWord;Pointer;LongWord;Pointer):LongBool;StdCall>"

program rec;
uses Windows, Bass;

(* This function called while recording audio *)
function RecordingCallback(h:HRECORD; b:Pointer; l,u: DWord): boolean; stdcall;
 var level:dword;
 begin
  level:=BASS_ChannelGetLevel(h);
  write(''#13,LoWord(level),'-',HiWord(level),'         ');
  Result := True;
 end;

begin
  BASS_RecordInit(-1);
  BASS_RecordStart(44100, 2, 0, @RecordingCallback, nil);
  Readln;
  BASS_RecordFree;
end.

Chris

  • Posts: 1853
Quote
Incompatible type for arg no. 4: Got "<address of function(LongWord;Pointer;LongWord;LongWord):Boolean;StdCall>", expected "<procedure variable type of function(LongWord;Pointer;LongWord;Pointer):LongBool;StdCall>"
As the Error tell you.........
 Argument 4 of the Callback is wrong......must be a Pointer so must look like this
Code: [Select]
function RecordingCallback(h:HRECORD; b:Pointer; l:DWORD;u: Pointer): boolean; stdcall;
« Last Edit: 5 Jul '18 - 00:25 by Chris »

Ian @ un4seen

  • Administrator
  • Posts: 21124
Besides the correction mentioned by Chris, I would suggest moving the BASS_ChannelGetLevel call output of the RecordingCallback function and instead call it in a timer to get the level as often as you want.

fbenites

  • Posts: 4
Now receiving:
1- "project1.lpr(15,33) Error: Wrong number of parameters specified for call to "RecordingCallback"" and
2- "project1.lpr(5,10) Error: Found declaration: RecordingCallback(LongWord;Pointer;LongWord;Pointer):Boolean; StdCall;"

Thanx for the advice... As soon as compilation goes right, I promess to study about the optimization.

Any aditional tip so far?


Chris

  • Posts: 1853
Hi the Problem is you are working with Lazarus. Lazurus is nearly Delphi but not the Same.
Boolean and Bool/Longbool is a little bit different.
In Delphi The Compiler will set the correct Bool/boolean/Longbool automatically, but not Lazarus.
As you see in the Orginal Bass helpfile the correct return of a RecordProc must be a bool/LongBool
The Problem is the Longbool,
So the correct Callback Definition in Lazarus must be


Code: [Select]
function RecordingCallback(Handle: HRECORD; buffer: Pointer; length: DWord;user: Pointer): LongBool; stdcall;
begin
  Result := True;
end;

By the way if you only want catch the Level then there is there is no Callback needed and you can pass it as nil.
Code: [Select]
BASS_RecordStart(44100, 2, 0, nil, nil);
The Recordcallback can be usefull if you want to write WaveData from the Recording.....(take a look in the Bass / Delphi Folder the Record Example
« Last Edit: 5 Jul '18 - 21:06 by Chris »

Ian @ un4seen

  • Administrator
  • Posts: 21124
In this case of just wanting the level, I would actually recommend keeping the RECORDPROC callback, as it will allow you to call BASS_ChannelGetLevel however often you like. Without the RECORDPROC, the BASS_ChannelGetLevel call would be taking data out of the recording buffer, so there could be a backlog of data (adding latency) if it isn't called frequently enough, or it could run out of data sometimes (so no level reading) if called too frequently.

fbenites

  • Posts: 4
Finally it worked.
Thank you so much, Guys.

You're really suportive for those ramping up the knowledge of the library.

Just to let you know, here in Brazil we have a very popular game called "Stop" , where categories of stuff (cities, cars brand, fruits, etc...) are selected. We then draw a letter and who fill all the categories first with the letter initial, shouts "Stop!". and that's my need to access the mic came from.

bye

fbenites

  • Posts: 4
I'm struggling trying to adapt the code to my form...
Let us say I'll pass as nil, no callback.
Where can I get the level do my trigger in the loop below?:

//loop
begin
BASS_RecordInit(-1);
  level:=BASS_RecordStart(44100, 2, 0, nil, nil);
  writeln(level);
  delay(1000);
  BASS_RecordFree;
  end;   

Ian @ un4seen

  • Administrator
  • Posts: 21124
BASS_RecordStart gives you a recording channel handle, which you can use in a BASS_ChannelGetLevel call to get the level. You can't get the level directly from BASS_RecordStart. So you need to move the BASS_RecordStart and BASS_RecordFree calls out of the loop, and add a BASS_ChannelGetLevel call in there.

As I mentioned earlier, if you don't use a RECORDPROC then you will need to take some care in the rate of BASS_ChannelGetLevel calls. BASS_ChannelGetLevel processes up to 20ms of data, so your "delay" should be below that to avoid a build-up of data in the recording buffer. You may prefer to use BASS_ChannelGetLevelEx instead, which can process up to 1 second of data in a single call. Please see the BASS_ChannelGetLevelEx documentation for details on that.

Chris

  • Posts: 1853
Hi here is a little small working Lazarus Example (recording and show the Levels) written with a 64 Bit Lazarus Version.
If you have a 32 Bit Lazarus Version you must change the include (64Bit Bass.dll) with a (32Bit Bass.dll).
This example use a simple TTimer to show The Levels.
By the way is your Program a Console or a Gui Program?

 
« Last Edit: 11 Jul '18 - 11:38 by Chris »