This project has moved. For the latest updates, please go here.

Sound detection

Feb 18, 2010 at 5:14 AM

Hi,

I have used the example (here) in my program, and its working great.

However, I would like to implement a "record on sound detected" function.

So is there any way to get the amplitude or threshold of the sound, as I want to "record" the sound only if it is over a certain limit? 

 

Need some guidance, as I am new to the sound stuff.

Editor
Feb 18, 2010 at 8:24 PM

Hi Becoz,

You will need to monitor what is happening through the source that you want to record until you find the event in the audio stream which will trigger your recording. So if you are looking to record audio data (from here on in I will refer to this as saving the audio data, it's an important distinction) you will still need to capture (aka record) the data from the audio stream, check if the event has occurred (the volume level on the stream coming in) and then decide if you want to save the data. If you don't want to save the data then you trow it away and check the next block.

Think of it like recording a concert. Your going to still be listing to the concert and the concert is still going to be playing even if your not recording (i.e. saving) the data that you hear. So effectively what you want to do is not to stop recording the data but to stop saving it until an event you are looking for occurs.

To answer the part about the event, being the level of the volume, look at the sample code provided in the application with NAudio, there is a peak meter there which you could reuse the code from to help you identify when a peak level has been reached.

~DSebJ

Feb 19, 2010 at 7:44 AM
Edited Feb 19, 2010 at 7:45 AM

Hi DSebJ,

I have devised an alternative solution after referencing some of the code samples from Coding4Fun.com. Below is the method that I will call before saving. If the method returns true, it means that it is over thethreshold limit.

After amiring my code for a few minutes, I discovered a new problem. I want to implement "recording" using multiple microphones. Is there anyway to differenciate the different microphones, or come up with a list of available microphones?

private double AudioThresh = 0.8;
private double AudioThresh2 = 0.09;

private bool ProcessData(WaveInEventArgs e)
        {
            bool result = false;

            bool Tr = false;
            double Sum2 = 0;
            int Count = e.BytesRecorded / 2;
            for (int index = 0; index < e.BytesRecorded; index += 2)
            {
                double Tmp = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
                Tmp /= 32768.0;
                Sum2 += Tmp * Tmp;
                if (Tmp > AudioThresh)
                    Tr = true;
            }
            Sum2 /= Count;

            // If the Mean-Square is greater than a threshold, set a flag to indicate that noise has happened
            if (Tr || Sum2 > AudioThresh2)
            {
                result = true;
            }
            else
            {
                result = false;
            }

            return result;
        }

Thanks in advance,

BecoZ

Mar 6, 2010 at 8:25 PM

Hi everybody,
After a week of search I 've found this post.
I've the same problem like becos, I need to make an interrupt at each peak on my audio stream.
I don't need to record only listening micro, I need to detect a peak every second on a silent stream.
I've VS2005 and the sample are in VS2008 in think I try to use it but it is to complex for my application .
Thanks for your help

DECORME Sébastien

Mar 7, 2010 at 5:54 AM
Edited Mar 7, 2010 at 5:57 AM

 

To sdecorme,

I am not sure what you mean by this part of your post:

"I need to make an interrupt at each peak on my audio stream."

However, if you want to detect a sound that is louder or higher in pitch as compared to the normal environment noise (even in a complete silent place,there are still sounds), I have a code snippet that might help.

 

//edit the value of the variable accordingly
double AudioThresh = 0.02


//When button Test is clicked, start listening for sound
private void btnTest_Click(object sender, EventArgs e)
{
	waveInStream = new WaveIn(44100, 2);
	waveInStream.DataAvailable += new EventHandler<WaveInEventArgs>(waveInStream_DataAvailable);

	waveInStream.StartRecording();

}

//Handler for the sound listener
private void waveInStream_DataAvailable(object sender, WaveInEventArgs e)
{

	bool result = ProcessData(e);
	if (result)
	{
		MessageBox.Show("peak in sound?");
	}
	else
	{
		//no peak in sound
	}


}


//calculate the sound level based on the AudioThresh
private bool ProcessData(WaveInEventArgs e)
{
	bool result = false;

	bool Tr = false;
	double Sum2 = 0;
	int Count = e.BytesRecorded / 2;
	for (int index = 0; index < e.BytesRecorded; index += 2)
	{
		double Tmp = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
		Tmp /= 32768.0;
		Sum2 += Tmp * Tmp;
		if (Tmp > AudioThresh)
			Tr = true;
	}
	Sum2 /= Count;

	// If the Mean-Square is greater than a threshold, set a flag to indicate that noise has happened
	if (Tr || Sum2 > AudioThresh)
	{
		result = true;
	}
	else
	{
		result = false;
	}
	return result;
}

 

The AudioThresh variable determines the threshold for the calculation. If the computed result in the ProcessData method is greater than AudioThresh, it means that there is a rise in sound levels (therefore, a peak). For my own implementation, I usually sets AudioThresh to a value between 0.02 and 0.03 in a normal environment where no music is played, no one is talking, no sudden noise (well, you get the idea).

 

Do indicate if this post helped, so that future programmers who encounter this problem can simply read this thread instead of spawning a new topic.

 

Hope I helped,

BecoZ

 

 

Mar 7, 2010 at 12:09 PM

Thanks becoz,
I've done it , it works but I've precision problem .
The peak is recorded on a silent channel , I use it to make synchronisation between the video/audio stream and a serial data emission.
Is there a way to know what is the delay between the  sound peak and the peak detection ?
How is generated the WaveInEventArgs ? apparently it is a buffer  because of the sum in the processdata.
Is it possible to accelerate the acquisition rate ?

Thanks you

Mar 7, 2010 at 2:19 PM

"I've done it , it works but I've precision problem ."

If you have a precision problem because you are using threshold values instead of frequency or amplitude, you will have better luck coding in c++, as they have such codes over there, and no one has ported them to c# yet(to my knowledge).

"Is there a way to know what is the delay between the  sound peak and the peak detection ?"

I have used this method of sound detection, in which I will save the sound to an audio file when a peak is detected, and only stops if there are no sounds that are over the threshold for 3 seconds. I can say that its quite accurate, as everything I said is recorded,with no parts missing.

"How is generated the WaveInEventArgs ? apparently it is a buffer  because of the sum in the processdata."

If you debug your project, you will be able to see that the sound is captured and stored as byte[]. The processdata method is a method created by me to calculate the average size of the byte[], so as to see if the sound level exeeds the threshold.

"Is it possible to accelerate the acquisition rate ?"

WaveIn does not allow you to change the rate. It will invoke the handler whenever there is data(sound) available.

Mar 7, 2010 at 9:21 PM

Thanks for all this precision


How can I select on wich channel I want to work , I try
waveInStream = new WaveIn(44100, 1);
and
waveInStream = new WaveIn(44100, 2);
but it make no difference .

What the byte[] means exactly, is there any documentation about this array , and how it work .
Maybe my problem came from the byte[] decoding , I found some noise that sould no be on the audio stream.

Thanks

Apr 15, 2010 at 2:04 PM

hi !

I have to do a C# application to detect sound on the microphone , and when the sound is detected ,to play a message.I 've already writen the part of playing the message , but now I have to detect the moment when to inject that message.I don't know...i think an ideea could be to capture from the sound card , and when I detect changes in the audio signal it means that sound appeares in the microphone and then i can call the playing function.But I need some help in writing the C# code. So...can anybody help me with this?

Thanks , Catalina

Apr 15, 2010 at 2:20 PM

What the byte[] means exactly, is there any documentation about this array , and how it work.

 I am not sure if there are any documentation about this array. However, you can try searching with keywords such as "WaveIn API".

 

I have to detect the moment when to inject that message...

 In my example above, I have already set the condition

//Handler for the sound listener
private void waveInStream_DataAvailable(object sender, WaveInEventArgs e)
{

	bool result = ProcessData(e);
	if (result)
	{
		MessageBox.Show("peak in sound?");
	}
	else
	{
		//no peak in sound
	}


}

If the result is true, it means sound is detected. So just put you code inside the if.
If your playing of a message means playing a sound, do note that the sound you played can be picked up by the sound detection function.
Apr 15, 2010 at 2:37 PM

Hi again !

yes, playing a message is playing a sound.In fact the message was a text message that I converted into speech with SAPI. That voice message has to be injected in a call when somebody answers the phone.The part with dialing the number is done (I used a modem for this) ,the part with the voice message is done too...I just need to detect when somebody answered the phone.My coordinator teacher told me that in order to know when to play the message(in fact the sound) I have to capture sound from the sound card and when I detect changes in the audio signal it means that the call was answered so I can play the message.So..I will try to use your example...maybe it will help me.If you have any ideea and you want to help me...it would be great.

Thanks !

 

Apr 15, 2010 at 2:54 PM

...when I detect changes in the audio signal...

Well, I have no idea how you will want to detect when a person have picked up the phone. My suggestion will be to determine the threshold such that it will not detect the dialing sound.

 

My coordinator teacher...

Wow, does this mean you are doing a school project? I am glad I helped you someway or another, as I am also a student at a local polytechnic, and have done sound detection as one of the many modules in my final year school project. We students should help each other,lol.

Apr 15, 2010 at 2:59 PM

Yes, I am doing my diploma project. I am student at a technical university too.Well...I hope I will find something to help me.I will try to use your example above,maybe it's good for me too :).

Jul 9, 2010 at 8:39 PM

Maybe someone could help with a conversion to vb.net. How do I get the value from or call it. I am new to this and working on a simple project (I think) that will detect audio from my sound card.

 

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Imports NAudio.Wave
Imports System.Diagnostics

Public Class Form1
    Private AudioThresh As Double = 0.09
    Private waveInStream As WaveInStream
    Private WaveIn As WaveIn
    'When button Test is clicked, start listening for sound

    Private Sub btnTest_Click(ByVal sender As Object, ByVal e As EventArgs)
        'waveInStream = WaveIn(44100, 1)
        AddHandler waveInStream.DataAvailable, AddressOf waveInStream_DataAvailable
        'waveInStream.StartRecording()
    End Sub

    'Handler for the sound listener
    Private Sub waveInStream_DataAvailable(ByVal sender As Object, ByVal e As WaveInEventArgs)
        Dim result As Boolean = ProcessData(e)
        If result Then
            MessageBox.Show("peak in sound?")
            'no peak in sound
        Else
        End If
    End Sub

    'calculate the sound level based on the AudioThresh
    Private Function ProcessData(ByVal e As WaveInEventArgs) As Boolean
        Dim result As Boolean = False
        Dim Tr As Boolean = False
        Dim Sum2 As Double = 0
        Dim Count As Integer = e.BytesRecorded / 2
        For index As Integer = 0 To e.BytesRecorded - 1 Step 2
            Dim Tmp As Double = CShort((e.Buffer(index + 1) << 8) Or e.Buffer(index + 0))
            Tmp /= 32768.0
            Sum2 += Tmp * Tmp
            If Tmp > AudioThresh Then
                Tr = True
            End If
        Next
        Sum2 /= Count
        ' If the Mean-Square is greater than a threshold, set a flag to indicate that noise has happened
        If Tr OrElse Sum2 > AudioThresh Then
            result = True
            MsgBox("yes")

        Else
            result = False
            MsgBox("no")

        End If
        Return result
    End Function

End Class

Feb 17, 2014 at 1:30 PM
Hi guys, this example is good and working.

But I need to make a comparasion a little more precise instead of comparing against that "over a certain limit" be compared to a stored sound? say a specific tone of a short duration?, how could it?

And instead of listening to the microphone, I hear a WAVE file previously stored?

It would be a sound recognition but not VOICE
Feb 19, 2014 at 2:56 PM
nobody???
Coordinator
Feb 24, 2014 at 8:43 AM
comparing two recorded sounds is very difficult. For example, if the polarity is reversed, or one is timeshifted a few ms, or one is at a slightly different speed, then most comparison algorithms will say the sounds are completely different, even though they will sound almost identical to the human ear.