This project has moved. For the latest updates, please go here.

using a scroll bar to navigate true the mp3 file playing..in VB.NET

Mar 27, 2016 at 8:14 PM
There not many visual basic vb.net examples I can find...yet, I need the vb.net version...

I am trying to play mp3 and i like to use a progress bar that moves along with the playing time.
And I would like to be able to use the same progress bar to skip tru the song.

On my form application I got this so far:
Imports System.Data.OleDb
Imports NAudio.Wave

..
Public waveOut As WaveOut = New WaveOut
..
Public Sub Play_Sound(songname As String)
   On Error Resume Next 
    Dim mp3Reader As Mp3FileReader = New Mp3FileReader(songname)

    If waveOut.PlaybackState = PlaybackState.Playing Then
        waveOut.Stop()
        mp3Reader.Close()
    Else
        waveOut.Init(mp3Reader)
        waveOut.Play()

    End If
        SongLengthlabel.Text = mp3Reader.TotalTime.ToString("hh\:mm\:ss")

End Sub
..
When I call this code, with the mp3's filename the song plays: Play_Sound("c:\test.mp3")

Than to test i put the following code under a button:
     Dim test
    test = waveOut.GetPosition
    MsgBox(test)

Now the questions:
  1. the getposition returns a large number what does this represent and how can i convert it to actual time.
    the .ToString("hh\:mm\:ss") function like i used for the songlenthlabel, doesn't work here.
    1. How can I move the position of a mp3 playing to another position...in other words how to use the progress bar.
I did find an example in c# but simply converting the code doesn't work for me..
  1. Maybe I am getting this all wrong and you know of a better way?
Thanks
Mar 30, 2016 at 8:02 PM
Edited Mar 30, 2016 at 8:03 PM
I recommend to retrieve position information rather from source than from hardware using this code:
'Current time:
CurrentLenLabel.Text = New DateTime(mp3Reader.CurrentTime.Ticks).ToString("HH:mm:ss")

'Total time:
TotalLenLabel.Text = New DateTime(mp3Reader.TotalTime.Ticks).ToString("HH:mm:ss") 
Mar 30, 2016 at 8:16 PM
Yes, Freefall, but the problem is that I put the declaration of mp3reader in "Public Sub Play_Sound(songname As String)"
So after exiting this sub...the instance mp3reader is no longer accessable.
Mar 30, 2016 at 8:38 PM
What you search for, is an event that fires On playback position change. I use this code to raise a change when each sample is read:
'Declare on top:
Public WithEvents notify as NotifyingSampleProvider = Nothing
Public mp3Reader As Mp3FileReader = Nothing

'In your playback code:
Public Sub Play_Sound(songname As String)

    mp3Reader = New Mp3FileReader(songname)
    notify = New NotifyingSampleProvider(mp3Reader.ToSampleProvider)

    If waveOut.PlaybackState = PlaybackState.Playing Then
        waveOut.Stop()
        mp3Reader.Close()
    Else
        waveOut.Init(Notify)
        waveOut.Play()
    End If

End Sub

'Use the notify event to update your playback position with each processed sample.
'This Event is the most accurate and fires at your Mp3FileReader´s samplerate (usually 44100 times per second).
'For performance reasons you should better count for some samples till update,
'or your Form will redraw the labels 44100 times per second (overkill cpu waste)

Private SampleCounter as Integer = 0
Private Sub notify_Sample(ByVal sender As Object, ByVal e As NAudio.Wave.SampleEventArgs)
   SampleCounter += 1
   
   'For example wait 1024 samples till updating again.
   if SampleCounter >= 1024 then
     
     SampleCounter = 0

     'Current time:
     CurrentLenLabel.Text = New DateTime(mp3Reader.CurrentTime.Ticks).ToString("HH:mm:ss")

     'Total time:
     TotalLenLabel.Text = New DateTime(mp3Reader.TotalTime.Ticks).ToString("HH:mm:ss") 

   End If
End Sub
Mar 31, 2016 at 6:00 PM
Thanks Freefall,
Publicly declaring the mp3Reader does help me with some issues..thanks..However the code you give above is not working as the
Private Sub notify_Sample(.....) sub routine is never called uppon.. I put i breakpoint inside the sub to verify that it is not called uppon.
What am i missing?
Mar 31, 2016 at 6:05 PM
Edited Mar 31, 2016 at 6:06 PM
Ah sry, I forgot to add the handler there.

Change this:
Private Sub notify_Sample(ByVal sender As Object, ByVal e As NAudio.Wave.SampleEventArgs)
To this:
Private Sub notify_Sample(ByVal sender As Object, ByVal e As NAudio.Wave.SampleEventArgs) handles notify.Sample
Mar 31, 2016 at 6:22 PM
Edited Mar 31, 2016 at 7:12 PM
Thanks man! That fixed it... Thanks for your help, not many VB examples out there..most is C#

In addition to your code i was able to add a slider that follows the time progress
'to follow the the timeline with a moving slider
TrackPosition.Minimum = 0
TrackPosition.Maximum = mp3Reader.TotalTime.TotalSeconds
TrackPosition.Value = mp3Reader.CurrentTime.TotalSeconds

Than....I run into the next question..
I can move the slider by hand to another position in time...how can i make the song that is playing follow..
I tried

mp3Reader.Position = TrackPosition.Value
But that just restarts the song from the beginning and it does not move in time
any suggestions?


** update ** I figured out it does work but the value i get from the slider is to low number....trackposition.value give a number in seconds or so while the mp2reader.position gives ticks ..so its a conversion issue
Mar 31, 2016 at 8:09 PM
Edited Mar 31, 2016 at 8:50 PM
Got it al to work
here is my working code.
'Declare on top:
Imports NAudio.Wave
Imports NAudio.Wave.SampleProviders
'Declare on top in class mainapp ( for my case)
Public waveOut As WaveOut = New WaveOut
Public WithEvents notify as NotifyingSampleProvider = Nothing
Public mp3Reader As Mp3FileReader = Nothing
Public conversionTick_ms As Decimal 'need this for slider

Public Sub Play_Sound(songname As String)

    mp3Reader = New Mp3FileReader(songname)
    notify = New NotifyingSampleProvider(mp3Reader.ToSampleProvider)

    If waveOut.PlaybackState = PlaybackState.Playing Then
        waveOut.Stop()
        mp3Reader.Close()
    Else
        waveOut.Init(Notify)
        waveOut.Play()
     conversionTick_ms = (mp3Reader.Position / mp3Reader.CurrentTime.TotalMilliseconds) 'need this for slider
    End If

End Sub

'Use the notify event to update your playback position with each processed sample.
'This Event is the most accurate and fires at your Mp3FileReader´s samplerate (usually 44100 times per second).
'For performance reasons you should better count for some samples till update,
'or your Form will redraw the labels 44100 times per second (overkill cpu waste)

Private SampleCounter as Integer = 0
Private Sub notify_Sample(ByVal sender As Object, ByVal e As NAudio.Wave.SampleEventArgs) handles notify.Sample
   SampleCounter += 1
   
   'For example wait 1024 samples till updating again.
   if SampleCounter >= 1024 then
     
     SampleCounter = 0

     'Current time:
     CurrentLenLabel.Text = New DateTime(mp3Reader.CurrentTime.Ticks).ToString("HH:mm:ss")

     'Total time:
     TotalLenLabel.Text = New DateTime(mp3Reader.TotalTime.Ticks).ToString("HH:mm:ss") 
'trackposition is the name of the slider(trackbar)
            TrackPosition.Minimum = 0
            TrackPosition.Maximum = mp3Reader.TotalTime.TotalMilliseconds
            TrackPosition.Value = mp3Reader.CurrentTime.TotalMilliseconds

   End If
End Sub

'Than i added an event that runs when the position of the slider is changed manualy:
    Private Sub Button6_Click_1(sender As Object, e As EventArgs) Handles Button6.Click
       'before changing the position of the mp3, convert milliseconds to ticks... 1ms is approx 176.4 ticks
        mp3Reader.Position = TrackPosition.Value * conversionTick_ms 
    End Sub

The one concern i have, is the conversion i have to make that converts the value of the slider ( ms) to ticks , in the last part of the code... maybe there is an easier way?
Apr 1, 2016 at 12:09 AM
Edited Apr 1, 2016 at 12:11 AM
Actually there is an easier way. But as it seems you want to try to program a full audio player, I recommend you look at the source code of mine.

Although the article is outdated by far (v61, newest version is v108), you find all the basics in there. Also written in VB .NET.