0
votes

I'm wanting to open a wave file and play it back while plotting it's amplitude and frequency response on charts.

I have a function that takes arrays of bytes or floats and does this for me.

What I am trying to do is sample the audio from the last time I sampled it pass an array of floats representing that time to the function.

I'm trying to use an ISampleProvider with it's read method for this but I just can't seem to get it to work. The first read works perfectly but then the thread crashes on subsequent reads (occasionally it crashes on the first read also).

This is how I'm setting up the audio, the file plays just fine:

                _waveOut = new WaveOutEvent();
                _waveReader = new WaveFileReader(_cncFilePath.Substring(0, _cncFilePath.Length - 4) + "wav");
                _waveOutSampleProvider = new SampleChannel(_waveReader, true);
                _waveOut.Init(_waveOutSampleProvider);
                _waveOut.Play();

This is running on a 100ms timer, it will work perfectly for the first tick, the second will crash, the lock stays on and all other calls get backed up until the whole program crashes.

    private void WavOutChartTimeInterrupt(object waveReader)
    {
        lock (AudioLock) //todo add skipto code, use audio lock to do it.
        {
            try
            {
                var curPos = _waveOut.GetPositionTimeSpan(); //get currentPos
                if (curPos <= AudioCurrentPosition)
                {
                    AudioCurrentPosition = curPos;
                    return;
                }
                var bufferLength = (curPos - AudioCurrentPosition);
                var samplesSec = _waveOutSampleProvider.WaveFormat.SampleRate;
                var channels = _waveOut.OutputWaveFormat.Channels;
                var length = (int) (bufferLength.TotalSeconds * samplesSec * channels) % (samplesSec * channels);
                var wavOutBuffer = new float[length];
                _waveOutSampleProvider.Read(wavOutBuffer, 0, length);

                AudioCurrentPosition = curPos; //update for vCNC with where we are
            }
            catch (Exception e)
            {
                string WTF = e.StackTrace;

                throw new ArgumentException(@"Wave out buffer crashed" + e.StackTrace.ToString());
            }
        }

Stack Trace added (hope I did it correctly)

at NAudio.Wave.WaveFileReader.Read(Byte[] array, Int32 offset, Int32 count)\r\n       
at NAudio.Wave.SampleProviders.Pcm16BitToSampleProvider.Read(Single[] buffer, Int32 offset, Int32 count)\r\n       
at NAudio.Wave.SampleProviders.MeteringSampleProvider.Read(Single[] buffer, Int32 offset, Int32 count)\r\n 
at NAudio.Wave.SampleProviders.VolumeSampleProvider.Read(Single[] buffer, Int32 offset, Int32 sampleCount)\r\n   
at RecordCNC.Form1.WavOutChartTimeInterrupt(Object waveReader) in C:\\Cloud\\ITRI\\Visual Studio\\RecordCNC\\RecordCNC\\Form1.cs:line 715

Haydan

1
Do you have a stack trace / exception data from the crash?SynerCoder
Can you post e.ToString(), than we can also see the exception type.SynerCoder
Ah yes I think you have enabled me to solve my own problem, I wasn't ensuring the read length was a multiple of the block align! (thought I was but I wasn't) e.ToString() was must be multiple of block align...Haydan Tompkins
Added this to code and it seems to be working perfect now - "length -= length % (blockAlign / channels);"Haydan Tompkins
Could you post your solution as an answer, then you can accept your own solution. This way when other people have the same problem they can find your solution.SynerCoder

1 Answers

0
votes

The issue was that I wasn't correctly checking the length of the buffer I was requesting. Buffers always have to be a multiple of block align.

    private void WavOutChartTimeInterrupt(object waveReader)
{
    lock (AudioLock) //todo add skipto code, use audio lock to do it.
    {
        try
        {
            var curPos = _waveOut.GetPositionTimeSpan(); //get currentPos
            if (curPos <= AudioCurrentPosition)
            {
                AudioCurrentPosition = curPos;
                return;
            }
            var bufferLength = (curPos - AudioCurrentPosition);
            var samplesSec = _waveOutSampleProvider.WaveFormat.SampleRate;
            var channels = _waveOut.OutputWaveFormat.Channels;
            var length = (int) (bufferLength.TotalSeconds * samplesSec * channels) % (samplesSec * channels);
            length -= length% (blockAlign / channels);  //<- THIS FIXED IT
            var wavOutBuffer = new float[length];
            _waveOutSampleProvider.Read(wavOutBuffer, 0, length);

            AudioCurrentPosition = curPos; //update for vCNC with where we are
        }
        catch (Exception e)
        {
            string WTF = e.StackTrace;

            throw new ArgumentException(@"Wave out buffer crashed" + e.StackTrace.ToString());
        }
    }