Author Topic: How detect Mic Silence  (Read 857 times)

Luiz

  • Posts: 12
How detect Mic Silence
« on: 7 Sep '18 - 13:42 »
Hi,
 
Using RecordTest demo, IŽd like to start a recording and stop it and save the sound stream automatically when I detect microphone silence(no speaking on Mic).

I am trying to use google cloud speech to text API in interactive mode. That API needs I send a FLAC file sound. It receives the FLAC  and returns the text.

My approach is: a user start  to speak on Mic and the sound is saved into a stream. After, I detect a Mic silence during a time interval(2 seconds, for sample), I will stop the recording and save the stream to file. This file will sent to google API.


In the BASS DLL RecordTest sample, I have the next code:
* This is called while recording audio *)

Code: [Select]
function RecordingCallback(Handle: HRECORD; buffer: Pointer; length: DWORD; user: Pointer): boolean; stdcall;
var level:dword;
begin
   level:=BASS_ChannelGetLevel(Handle);
   Form1.Memo1.Lines.add(LoWord(level)+'-'+HiWord(level));

    // Copy new buffer contents to the memory buffer
Form1.WaveStream.Write(buffer^, length);
    // Allow recording to continue
Result := True;
end;


Is possible change  this code, maybe using a timer to achieve it?

Ian @ un4seen

  • Administrator
  • Posts: 21379
Re: How detect Mic Silence
« Reply #1 on: 7 Sep '18 - 14:35 »
I'm not a Delphi user, so I can't advise on the specifics of that, but you could try something like this:

Code: [Select]
BOOL recording = FALSE;
DWORD lastsound;
float threshold = 0.1; // adjust as needed for background noise

BOOL CALLBACK RecordProc(HRECORD handle, const void *buffer, DWORD length, void *user)
{
float level;
BASS_ChannelGetLevelEx(handle, &level, 0.1, BASS_LEVEL_MONO); // get the current level
if (!recording && level >= threshold) { // sound started
recording = TRUE;
// start recording here
}
if (recording) {
// store data here
if (level < threshold) { // too quiet
if (GetTickCount() - lastsound >= 2000) { // too quiet for 2 seconds
recording = FALSE;
// stop recording here
}
} else
lastsound = GetTickCount();
}
return TRUE;
}

Luiz

  • Posts: 12
Re: How detect Mic Silence
« Reply #2 on: 7 Sep '18 - 18:11 »
Thank you.
It help me too much.

From RecordTest Demo, Can someone show me how could I capture and save the audio stream as FLAC, 16 Bits file?

I have seen these functions in "BASSenc_FLAC.pas"
function BASS_Encode_FLAC_Start(handle:DWORD; options:PChar; flags:DWORD; proc:ENCODEPROCEX; user:Pointer): HENCODE; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; external bassencflacdll;
function BASS_Encode_FLAC_StartFile(handle:DWORD; options:PChar; flags:DWORD; filename:PChar): HENCODE; {$IFDEF MSWINDOWS}stdcall{$ELSE}cdecl{$ENDIF}; external bassencflacdll;

How could I use these functions to do it?

Regards, Luiz
« Last Edit: 7 Sep '18 - 22:54 by Luiz »

Ian @ un4seen

  • Administrator
  • Posts: 21379
Re: How detect Mic Silence
« Reply #3 on: 10 Sep '18 - 14:22 »
The code above could be modified something like this, to write FLAC files:

Code: [Select]
BOOL recording = FALSE;
DWORD lastsound;
float threshold = 0.1; // adjust as needed for background noise

BOOL CALLBACK RecordProc(HRECORD handle, const void *buffer, DWORD length, void *user)
{
float level;
BASS_ChannelGetLevelEx(handle, &level, 0.1, BASS_LEVEL_MONO); // get the current level
if (!recording && level >= threshold) { // sound started
recording = TRUE;
BASS_Encode_FLAC_StartFile(handle, NULL, 0, flacfilename); // start FLAC encoding
BASS_Encode_Write(handle, buffer, length); // send this data block to the encoder
}
if (recording) {
if (level < threshold) { // too quiet
if (GetTickCount() - lastsound >= 2000) { // too quiet for 2 seconds
recording = FALSE;
BASS_Encode_Stop(handle); // stop encoding
}
} else
lastsound = GetTickCount();
}
return TRUE;
}

Luiz

  • Posts: 12
Re: How detect Mic Silence
« Reply #4 on: 10 Sep '18 - 14:33 »
Thank you very much.

How could I modify your code to encode to Memory Stream instead of a file in:
Quote
                BASS_Encode_FLAC_StartFile(handle, NULL, 0, flacfilename); // start FLAC encoding
      BASS_Encode_Write(handle, buffer, length); // send this data block to the encoder
It seems I have to use: BASS_Encode_FLAC_Start(handle:DWORD; options:PChar; flags:DWORD; proc:ENCODEPROCEX; user:Pointer): HENCODE;
Could you post a sample?

Luiz

  • Posts: 12
Re: How detect Mic Silence
« Reply #5 on: 10 Sep '18 - 15:03 »
I have translated your code to delphi as:

Code: [Select]
var flacfilename:string='output.flac';
var FlacStream:TMemoryStream;
function RecordingCallback(Handle: HRECORD; buffer: Pointer; length: DWORD; user: Pointer): boolean; stdcall;
var level:single;
begin
BASS_ChannelGetLevelEx(handle, @level, 0.1, BASS_LEVEL_MONO); // get the current level
if (not recording and (level >= threshold)) then begin // sound started
   recording := TRUE;
   // start recording here
   BASS_Encode_FLAC_StartFile(handle, nil, 0, Pchar(flacfilename)); // start FLAC encoding
   BASS_Encode_Write(handle, buffer, length); // send this data block to the encoder
  end;
if (recording) then begin
// store data here
    if (level < threshold) then begin // too quiet
if (GetTickCount() - lastsound >= 2000) then begin // too quiet for 2 seconds
    //stop recording here
            recording := FALSE;
            BASS_Encode_Stop(handle); // stop encoding
        FlacStream.LoadFromFile(flacfilename);
end
end else
lastsound := GetTickCount();
  end;
  // Allow recording to continue
result:= TRUE;
end;

The problem is that the flac file is not created correctly. It create a file with name   "o" in folder without extension. I expect a file with name 'output.flac'.
And, if I try  to load the flac file to a stream  as
Code: [Select]
FlacStream.LoadFromFile(flacfilename); I have an exception saying the file not exists.
And, may you modify the sample to create the flac in memory stream?
« Last Edit: 10 Sep '18 - 15:17 by Luiz »

Ian @ un4seen

  • Administrator
  • Posts: 21379
Re: How detect Mic Silence
« Reply #6 on: 10 Sep '18 - 16:23 »
How could I modify your code to encode to Memory Stream instead of a file in:
Quote
                BASS_Encode_FLAC_StartFile(handle, NULL, 0, flacfilename); // start FLAC encoding
      BASS_Encode_Write(handle, buffer, length); // send this data block to the encoder
It seems I have to use: BASS_Encode_FLAC_Start(handle:DWORD; options:PChar; flags:DWORD; proc:ENCODEPROCEX; user:Pointer): HENCODE;
Could you post a sample?

I'm not a Delphi user myself, so I'm afraid I can't really advise on writing a memory stream, but your ENCODEPROCEX callback function should basically seek to the "offset" and then write the provided data. A little example can be found in the ENCODEPROCEX documentation.

The problem is that the flac file is not created correctly. It create a file with name   "o" in folder without extension. I expect a file with name 'output.flac'.

Adding the BASS_UNICODE flag to the BASS_Encode_FLAC_StartFile call should fix that (modern Delphi uses Unicode strings by default).

Luiz

  • Posts: 12
Re: How detect Mic Silence
« Reply #7 on: 10 Sep '18 - 20:26 »
Thank you so much.
I managed  to create the flac encoded  directly to a Stream instead of a file.

Now. I am trying to get the time duration of the encoded stream as:
Code: [Select]
      TotalTime := BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetLength(handle, BASS_POS_BYTE));
      ms:=Trunc(TotalTime*1000);
But it  doesnŽt work. Any help, please?

I translate to delphi as:

Code: [Select]
function FlacCallback(Handle: HENCODE; channel:DWORD;buffer: Pointer; length: DWORD; oofset: QWORD; user: Pointer): boolean; stdcall;
begin
    // Copy new buffer contents to the memory buffer
  FlacStream.Write(buffer^, length);
    // Allow recording to continue
Result := True;
end;
function RecordingCallback(Handle: HRECORD; buffer: Pointer; length: DWORD; user: Pointer): boolean; stdcall;
var level,totaltime:single;
     ms:Integer;
     chdecoded:HENCODE;
begin
    BASS_ChannelGetLevelEx(handle, @level, 0.1, BASS_LEVEL_MONO); // get the current level

    if (not recording and (level >= threshold) and Form1.MicAtivo) then begin // sound started
         recording := TRUE;
         // start recording here
         PostMessage(Form1.Handle,WM_GRAVANDO,1,0);
         BASSEnc_FLAC.BASS_Encode_FLAC_Start(handle, 0, BASS_ENCODE_FP_AUTO or BASS_UNICODE, @FlacCallBack, nil);
         BASS_Encode_Write(handle, buffer, length); // send this data block to the encoder
    end;
    if (recording) then begin
      TotalTime := BASS_ChannelBytes2Seconds(handle, BASS_ChannelGetLength(handle, BASS_POS_BYTE));
      ms:=Trunc(TotalTime*1000);
      PostMessage(Form1.Handle,WM_GRAVANDO,2,ms);


      if (level < threshold) then begin // too quiet
        if (GetTickCount() - lastsound >= TIME_MS_QUIET) then begin // too quiet for 2 seconds
              //stop recording here
               recording := FALSE;
               PostMessage(Form1.Handle,WM_GRAVANDO,0,0);
               BASS_Encode_Stop(handle); // stop encoding
               //send to google recognize
               PostMessage(Form1.Handle,WM_RESTART_RECOG,0,0);
        end
      end else  begin
            if (GetTickCount() - lastsound >= 60*1000) then begin // too quiet two min - to prevent memory overflow with Memory Stream too Large
              //stop recording here
               recording := FALSE;
               PostMessage(Form1.Handle,WM_GRAVANDO,0,0);
               BASS_Encode_Stop(handle); // stop encoding
               //send to google recognize
               PostMessage(Form1.Handle,WM_RESTART_RECOG,0,0);
            end;
            lastsound := GetTickCount();
      end
    end;
   // Allow recording to continue
    result:= TRUE;
end;
« Last Edit: 11 Sep '18 - 13:38 by Luiz »

Ian @ un4seen

  • Administrator
  • Posts: 21379
Re: How detect Mic Silence
« Reply #8 on: 11 Sep '18 - 13:52 »
Recording channels don't have a defined length (ie. you can record for any amount of time), so BASS_ChannelGetLength doesn't apply. You can use BASS_ChannelGetPosition instead to get the current position.

Luiz

  • Posts: 12
Re: How detect Mic Silence
« Reply #9 on: 11 Sep '18 - 14:37 »
Recording channels don't have a defined length (ie. you can record for any amount of time), so BASS_ChannelGetLength doesn't apply. You can use BASS_ChannelGetPosition instead to get the current position.
Ok, Thank you.

How about the flac audio stream created?
Is possible I know your total duration without play the stream into callback?

I am trying wihout sucesss:
 
Code: [Select]
  ....
   ....
   if (recording) then begin
            pchan := BASS_FLAC_StreamCreateFile(True, FlacStream.Memory, 0, FlacStream.Size, BASS_STREAM_DECODE);
            //get duration
            seg := Trunc(bass.BASS_ChannelBytes2Seconds(pchan, bass.BASS_ChannelGetLength(pchan, 0)));
            BASS_Encode_Stop(pchan);
            BASS_StreamFree(pchan);


Regards, Luiz
« Last Edit: 11 Sep '18 - 16:00 by Luiz »

Ian @ un4seen

  • Administrator
  • Posts: 21379
Re: How detect Mic Silence
« Reply #10 on: 11 Sep '18 - 15:57 »
You can use BASS_Encode_GetCount (with BASS_ENCODE_COUNT_IN) to get how much data has been sent to the encoder.

Luiz

  • Posts: 12
Re: How detect Mic Silence
« Reply #11 on: 12 Sep '18 - 14:03 »
Thank you Mr Ian.