Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NAudio playing a sine wave for x milliseconds using C#

I am using NAudio to play a sinewave of a given frequency as in the blog post Playback of Sine Wave in NAudio. I just want the sound to play() for x milliseconds and then stop.

I tried a thread.sleep, but the sound stops straightaway. I tried a timer, but when the WaveOut is disposed there is a cross-thread exception.

I tried this code, but when I call beep the program freezes.

public class Beep
{
    public Beep(int freq, int ms)
    {
        SineWaveProvider32 sineWaveProvider = new SineWaveProvider32();
        sineWaveProvider.Amplitude = 0.25f;
        sineWaveProvider.Frequency = freq;

        NAudio.Wave.WaveOut waveOut = new NAudio.Wave.WaveOut(WaveCallbackInfo.FunctionCallback());
        waveOut.Init(sineWaveProvider);
        waveOut.Play();
        Thread.Sleep(ms);
        waveOut.Stop();
        waveOut.Dispose();
    }
}

public class SineWaveProvider32 : NAudio.Wave.WaveProvider32
{
    int sample;

    public SineWaveProvider32()
    {
        Frequency = 1000;
        Amplitude = 0.25f; // Let's not hurt our ears
    }

    public float Frequency { get; set; }
    public float Amplitude { get; set; }

    public override int Read(float[] buffer, int offset, int sampleCount)
    {
        int sampleRate = WaveFormat.SampleRate;
        for (int n = 0; n < sampleCount; n++)
        {
            buffer[n + offset] = (float)(Amplitude * Math.Sin((2 * Math.PI * sample * Frequency) / sampleRate));
            sample++;
            if (sample >= sampleRate)
                sample = 0;
        }
   }
like image 638
amcashcow Avatar asked Mar 30 '11 11:03

amcashcow


1 Answers

The SineWaveProvider32 class doesn't need to indefinitely provide audio. If you want the beep to have a maximum duration of a second (say), then for mono 44.1 kHz, you need to provide 44,100 samples. The Read method should return 0 when it has no more data to supply.

To make your GUI thread not block, you need to get rid of Thread.Sleep, waveOut.Stop and Dispose, and simply start playing the audio (you may find window callbacks more reliable than function).

Then, when the audio has finished playing, you can close and clean up the WaveOut object.

like image 193
Mark Heath Avatar answered Nov 04 '22 01:11

Mark Heath