4

I am trying to program a simple Babymonitor for Windows (personal use). The babymonitor should just detect the dB level of the microphone and triggers at a certain volume.

After some research, I found the Bass.dll library and came across it's function BASS_ChannelGetLevel, which is great but seems to have limitations and doesn't fit my needs (Peak equals to a DWORD value).

In the examples I found a livespec example which is "almost" what I need. The example uses BASS_ChannelGetData, but I don't quite know how to handle the returned array...

I want to keep it as simple as possible: Detect the volume from the microphone as dB or any other value (e.g. value 0-MAXINT).

How can this be done with the Bass.dll library?

Ben
  • 3,380
  • 2
  • 44
  • 98
  • 2
    Check [this](http://stackoverflow.com/questions/5951819/how-to-listen-to-microphone-and-detect-sound-loudness-in-delphi-7) – aring Oct 30 '16 at 09:58
  • @aring I did check it out, however the return value is limited to DWORD... – Ben Oct 30 '16 at 10:07
  • 4
    `DWORD` is a 32 bit unsigned value. What is wrong with that? You said you could work with a value between `0` and `MaxInt`, so why not a `DWORD`? Heck, even if it were an 8-bit `Byte`or 8-bit `Shortint`, you just have to scale it. I don't quite see your problem. – Rudy Velthuis Oct 30 '16 at 12:34
  • @RudyVelthuis How could I scale it? Even when I whisper into the microphone it's already at the limit... – Ben Oct 30 '16 at 17:47
  • 1
    The you need to find a way to lower the recording volume so you can detect the peaks. – whosrdaddy Oct 30 '16 at 18:41
  • 1
    If it is already at the limit if you whisper, it is `High(DWORD)`, which is twice `MaxInt`, so that is not the problem of the DLL, it is the problem of your sound source. – Rudy Velthuis Oct 31 '16 at 14:09
  • 1
    @BenjaminWeiss If whispering already reaches limit, then I guess you might need to adjust (lower) your microphone volume in your soundcard settings. Also make sure that you disable microphone auto level adjustment feature (sometimes called as microphone auto gain) of your sound card. This feature is useful so that you don't need to talk directly into microphone all the time because if your mouth isn't facing directly to the microphone your speech would be recorded at lower volume due the fact that the sound that is coming from your mouth is directional. – SilverWarior Oct 31 '16 at 15:48

2 Answers2

3

The BASS_ChannelGetLevel returns the value that is capped to 0dB (return value is 32768 in this case). If you adjust your source level (lower microphone level in sound card settings) then it will work just fine.

Another way, if you want to get uncapped value is to use the BASS_ChannelGetLevelEx function instead: it returns floating point levels, where 1 is maximum (0dB) value that corresponds to BASS_ChannelGetLevel's 32767, but it can exceed 1 to detect sound levels above 0dB which is what you may need.

I also suggest you to monitor sound level for a while: trigger only if certain level exists for 2-3 seconds at least (this way you will exclude false alarms).

djsoft
  • 1,051
  • 8
  • 19
  • I managed it to make it work with the Ex function. Exactly what I was looking for! Thank you very much! – Ben Oct 31 '16 at 20:13
1

Here is how you obtain the db level given an input stream handle (streamHandle):

var peak = (double)Bass.BASS_ChannelGetLevel(streamHandle);
var decibels = 20 * Math.Log10(peak / Int32.MaxValue);

Alternatively, you can use the following to get the RMS (average) peak. To get the RMS value, you have to pass in a sample length into BASS_ChannelGetLevel. I'm using 20 milliseconds here but you can play with the value to see which works best for your needs.

var decibels = 0m;
var channelCount = 2; //Assuming two channels
var sampleLengthMS = 20f;
var rmsLevels = new float[channelCount];
var rmsObtained = Bass.BASS_ChannelGetLevel(streamHandle, rmsLevels, sampleLengthMS / 1000f, BASSLevel.BASS_LEVEL_RMS);

if (rmsObtained)
     decibels = 20*Math.Log10(rmsLevels[0]);   //using first channel (index 0) but you can get both if needed.
else
     Console.WriteLine(Bass.BASS_ErrorGetCode());

Hope this helps.

John
  • 235
  • 4
  • 10