Reputation: 33
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
Upvotes: 1
Views: 1017
Reputation: 33
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());
}
}
Upvotes: 1