Search code examples
c#wpfaudionaudio

Window Refresh Audio


So i'm in a bit of a problem, i'm coding a clap sensor, that hears when someone claps and executes a certain command.

        //CLAP
    private float bigValue;
    WaveIn waveIn;
    private double MaxValue;
    private void button1_Loaded(object sender, RoutedEventArgs e)
    {
                    if (Convert.ToInt16(textBox1.Text) > 100)
        {
            MessageBox.Show("Invalid Value");
            return;
        }
        else
            MaxValue = Convert.ToDouble(textBox1.Text) / 100;
        bigValue = 0;
        waveIn = new WaveIn();
        int waveInDevices = waveIn.DeviceNumber;

        //Get Device Count
        for ( int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
        {
            WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
        }
        waveIn.DeviceNumber = 0;
        waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
        int sampleRate = 8000;
        int channels = 1;
        waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
        waveIn.StartRecording();
    }

    //CLAP
    void waveIn_DataAvailable(object sender, WaveInEventArgs e)
    {
        for (int index = 0; index < e.BytesRecorded; index += 2)
        {
            short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);

            float sample32 = sample / 32768f;
            label1.Content = sample32.ToString();
            if (bigValue < sample32)
            {
                bigValue = sample32;
                label2.Content = bigValue.ToString();
                if (bigValue > MaxValue)
                {
                    waveIn.StopRecording();
                    SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
                    MessageBox.Show("Did you Clap?");
                }
            }
        }
    }

The code itself works as is, but I need it to be able to reset itself as many times as I need. This program basically listens for a clap and wakes up the monitor and starts it up. The program breaks any time I add in another "waveIn.StartRecording();"

Any ideas on how I could refresh the page or make it listen for ever?


Solution

  • What basically your code is doing is opening waveIn to receive audio data, then examining the data for loud samples. When it receives a sample that exceeds a threshold it then stops listening and issues the command.

    As written, the code stops after the first large sample is detected. No more audio data is received, etc. Probably not what you want. Instead you need to refine your clap detection so that it will stop processing the incoming data for a period of time - a few seconds say - after it detects the first big sample. Don't stop receiving the audio data, just stop reacting to it.

    Add a DataTime field to your class that records the timestamp of the last clap detection. At the start of your waveIn_DataAvailable method check if the elapsed time since the last detection is less than your silence time, and if so just return without processing the audio block. When you detect a large enough sample, fire off the event and update the last clap detection field.

    Something like this:

    DateTime LastDetection = DateTime.Now.AddMinutes(-1);
    
    void waveIn_DataAvailable(object sender, WaveInEventArgs e)
    {
        if (LastDetection.AddSeconds(3) >= DateTime.Now)
            return;
        if (DetectClap(e.Buffer))
        {
            LastDetection = DateTime.Now;
            SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
            MessageBox.Show("Clap detected.");
        }
    }
    
    bool DetectClap(byte[] audiobytes)
    {
        for (int i = 0; i < audiobytes.Length; i += 2)
        {
            float sample32 = (float)((short)((audiobytes[0] << 8) | audiobytes[1]))/32768f;
            if (sample32 > MaxValue)
                return true;
        }
        return false;
    }