Pergunta

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?

Foi útil?

Solução

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;
}

Outras dicas

Here is an example that moves the WaveIn logic to a background thread. It should give you enough to start. Please check the documentation for a complete example that includes the background thread cancellation.

    //CLAP
private float bigValue;
WaveIn waveIn;
private double MaxValue;

private BackgroundWorker worker;

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;

        // You'll need to handle the thread cancellation
        // when the user clicks the button again

    worker = new BackgroundWorker();

    worker.WorkerReportsProgress = true;
    worker.WorkerSupportsCancellation = true;

    worker.DoWork += (s, e) =>
    {
        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();
    };

    worker.ProgressChanged += (s, e) =>
    {
        SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
        MessageBox.Show("Did you Clap?");
    };

     worker.RunWorkerAsync();
}

//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)
            {
                worker.ReportProgress(0);
                break;
            }
        }
    }
}

So in the end I went with a different way than both suggested answers.

        private float bigValue;
    WaveIn waveIn;
    private double MaxValue;
    private void button1_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs 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();
    }

    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;
        for (int i = 0; i <= 100; i++)
        {
        }

        //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();
    }

    int i = 0;

    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();
                    if (IsOdd(i))
                    {
                        button1.IsEnabled = false;
                    }
                    else
                    {
                        button1.IsEnabled = true;
                    }
                    MessageBox.Show("Did you Clap?");
                    i++;
                }
            }
        }
    }
    public static bool IsOdd(int value)
    {
        return value % 2 != 0;
    }
}

The first load event sets it off. The second one goes back in forth between button on and button off using the IsEnabled event. The on and off are acheived by and if statement choosing between an odd number and even.

That is how I achieved this infinite loop.

NOTE: This way probably isn't the most efficient way but it got the job done. Also I left the (Open Window) code out of this answer.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top