Audio time resolution.

Feb 12, 2012 at 5:48 PM

When playing a wave file NAudio gets the time (current position) from the file reader which is cool but has one drawback.

For smooth playback it is better to have large buffers but that reduces the resolution of the current position (time).

Could we raise an event in the player when passing each buffer to the sound card to calculate the current position?

 

Cheers

 

Max

Coordinator
Feb 12, 2012 at 9:48 PM

It's a good question and NAudio does not have a standardised solution for this yet. The WaveOut class has GetPosition, which will return the waveOutGetPosition (in bytes), which should allow you to calculate more accurately where we are up to. I think it returns the number of bytes played since the last waveOutReset function. I might change the public API in the future (e.g. to return a TimeSpan instead of a long), but let me know how you get on with it. To support other output drivers like DirectSound, Wasapi and ASIO would need quite different implementations (and with ASIO, you tend to be working at much lower latencies anyway).

Mark

Feb 14, 2012 at 9:40 AM

Thanks again Mark this project is so cool.

I got it to work perfectly but there are a few things to consider

While waveout.position returns the total number of bytes it has passed to the sound card you can’t simply convert that to seconds and subtract that from the current time because it will not be accurate if you jump forward or backward in the audio file.

To overcome this I made a class that inherits from your wavefilereader and gave it a public property BytesRead.

Then override the Read function to count the totalbytes as they are read from the file

Excuse my VB. ;-)

 Public Overrides Function Read(array() As Byte, offset As Integer, cout As IntegerAs Integer 

        BytesRead += count

        Return MyBase.Read(array, offset, count)

 End Function

 

So now I can subtract the number of bytes processed from the number of bytes read to give me a true position.

I placed the following code into a timer to get a high resolution position display regardless of the size of the buffers being read from the file.

Dim span As TimeSpan = waveout1.CurrentTime

DisplayTime.Text = span.TotalSeconds - ((wavereader.BytesRead - waveout1.GetPosition) / waveout1.WaveFormat.AverageBytesPerSecond)

 Thanks again for all of your work with Naudio I love it and I like to pass on my modifications whenever I think you can use them.

Next step here might be for me to override the CurrentTime function to make it all a little more tidy.

Cheers

Max

Coordinator
Feb 17, 2012 at 7:15 PM

thanks Max, that is a good approach to override the WaveStream