This project has moved and is read-only. For the latest updates, please go here.

Play position

Feb 22, 2012 at 3:03 PM

Hi, I'm using NAudio's WaveViewer control to show waveform of a file. I can play this file. But now I want to make an indicator which shows which part of wave is currently being played.

I'll try to make myself clearer.

Imagine that you have WaveViewer. You click PLAY button, and then the file is being played. What's more, you can see a vertical line(on waveViewer) that moves while the file is played. It indicates a current position. I hope you know what I mean. I just don't know how to obtain current position of played file. All the changes in WaveViewer I'm gonna do by myself. But how do I know, what sample is currently being played?

 

Feb 22, 2012 at 3:21 PM

The simplest way is to have a timer that fires say 10 times a second, and uses the CurrentPosition property of the WaveFileReader/Mp3FileReader to find out where we are up to. There are more accurate ways using the waveOutGetposition API, but this is usually fine for most applications.

Feb 24, 2012 at 10:20 AM
Edited Feb 24, 2012 at 10:22 AM

OK, I have done this, but this method is rather slow. While playing, I can hear something like ticks. This is my code.

(These ticks are only when I draw the line. The line is drawn on WaveViewer. In other words WaveViewer is parent of the line).

//indicatorTimer is a dispatcherTimer with interval set to 100
//indicator is Microsoft.VisualBasic.PowerPacks.LineShape

private void indicatorTimer_Tick(object sender, EventArgs args)
{
    if (indicator.Visible)
    {
        int ms = (waveStream.CurrentTime.Minutes * 60 * 1000) + (waveStream.CurrentTime.Seconds * 1000) + waveStream.CurrentTime.Milliseconds;
        int x = (ms * (waveStream.WaveFormat.SampleRate / 1000)) / samplesPerPixel;
        DrawIndicator(x);
        lastX = x;
    }

    if (OnPlayProgress != null) OnPlayProgress(this, waveStream.CurrentTime);
    if (waveStream.TotalTime == waveStream.CurrentTime) indicatorTimer.Stop();
}

private void DrawIndicator(int x)
{
    indicator.X1 = x;
    indicator.X2 = x;
}

//in OnPlayProgressEvent I have only one line of code:
timeLabel.Text = String.Format("{0:00}:{1:00}", currentTime.Minutes, currentTime.Seconds);


Feb 24, 2012 at 10:35 AM

how are you setting the interval? should be using TimeSpan.FromMilliseconds(100); Try 500ms as well if you are still getting perf issues

Also what is your OnPlayProgress handler doing?

you can optimise ms calcualtion by using

waveStream.CurrentTime.TotalMilliseconds
Feb 24, 2012 at 11:06 AM

Interval is set in constructor, and timer is stopped.

indicatorTimer.Interval = TimeSpan

.FromMilliseconds(100);

With interval set to 500 performance is so much better. But now I suffer from lack of indicator smoothness ;)
I've changed my calculating as you said. I'm new in C# and didn't know what TotalMiliseconds actually returns.

OnPlayProgress handler is just as I wrote:
timeLabel.Text = String.Format("{0:00}:{1:00}", currentTime.Minutes, currentTime.Seconds);

It looks like client will have to chose: smoothnes or no ticks.

Feb 24, 2012 at 11:40 AM

I'm surprised this is hurting performance that badly. What buffer durations are you using and what IWaveOut implementer?

Feb 24, 2012 at 12:40 PM

What are buffer durations?
I don't use any IWaveOut. Just WaveStream(WaveFileRader) and DirectSoundOut

Feb 26, 2012 at 5:44 PM

you can set buffer sizes on DirectSoundOut, but I suspect you are using the default. You might need to use a profiler to find out what is taking the most time

Mar 9, 2012 at 11:53 AM

Do you mean PrimarySoundBuffer or SecondaryBuffer? Or something else?

Mar 10, 2012 at 9:44 AM

No, I mean that in DirectSoundOut, you can specify a latency in milliseconds in the constructor, which controls the buffer size. The default is 40, so try 100 or 200.

Apr 24, 2012 at 12:06 PM

Now, I'm using WaveOut. I noticed that it has DesiredLatency property default set to 300. So I tried higher values. Even 2000. In the beginning everything seems to hear good, although the indicator "started" somewhere in the half o the track and then it showed up somewhere at the end. Track length was about 4 seconds. In about half of the track, output "cut" some part.

To make myself more clear, let say that my record was: "One two three four five six seven eight nine ten" and lasts about 4, 5 seconds.

I can hear smething like "One two three four five eight ten"
The higher latency, the more weird output ;)
I didn't get rid off this tick, although they are not so frequent as they were. In latency about 2000 there is really smooth output(about 2 or 3 ticks), but there is this "cut". Now I'm using 400 latency. What can I do more?

Apr 26, 2012 at 5:01 PM

If you are getting weird playback problems, use the WaveFileWriter to dump your output waveprovider to a WAV file and then check that the WAV file has the audio you expect. That will tell you whether the problem is generating the output or playing it back.