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

An Event to Fire to Dispose?

Dec 28, 2015 at 12:43 AM
Edited Dec 28, 2015 at 12:46 AM
My app is playing really short audio samples and I can't really use a "stop" button to dispose of the reader. My thought was to run a timer and then parse a property to dispose once a file is finished playing but there doesn't seem to be any event or property that triggers in that case with ASIO out.

Even after the file is done playing the "Playing" property is still true. I expected it to be false, that it would automatically "stop" at the end of the file, so that my timer could parse that property and automatically dispose of it.

Any idea? Thanks.
Jan 1, 2016 at 2:09 PM
I´d suggest you subscribe to the PlaybackStopped Event and dispose there.
Jan 2, 2016 at 5:01 PM
Edited Jan 3, 2016 at 3:27 PM
Thanks. I think I have it sorted. If you don't mind, look over this code and tell me if you think there are any memory leaks or potential issues there.

I playback the audio with this class code below. Because my app is triggering really short files it uses shared public vars for the object references to track and dispose of them on every trigger cycle and to also allow the main form to dispose of any leftover objects on quit, like if a user quit the application while audio was playing. Not sure if the PlaybackStopped event would trigger in that case.

Also, looking at volume, it appears to be obsolete, I need another way.
    ' Keep class level references to the current objects for disposal
    ' Public so that the main form can dispose of any objects on shut down
    Public Shared CurrentWave As NAudio.Wave.WaveOutEvent
    Public Shared CurrentStream As WaveFileReader

    Public Sub Play_Sound(Filename As String, ByVal Audio_Device_Output As Integer,
                          Optional ByVal Volume As Single = Nothing)

        ' Always stop and dispose on new playback trigger
        ' only ever allow playing one sound at a time
        If CurrentWave IsNot Nothing Then
            If CurrentWave.PlaybackState = PlaybackState.Playing Then
                ' this triggers disposal of current objects
                CurrentWave.Stop()
            End If
        End If

        ' create a new stream object
        Dim Stream = New WaveFileReader(Filename)

        ' reference the stream object so we can easily dispose of it later
        CurrentStream = Stream

        ' load the audio file 
        Dim Reader = New WaveFileReader(Filename)
        Dim Wave = New NAudio.Wave.WaveOutEvent
        CurrentWave = Wave
        AddHandler Wave.PlaybackStopped, AddressOf PlaybackStopping
        ' set the correct output device index
        CurrentWave.DeviceNumber = Audio_Device_Output
        ' **** this is obsolete, find another way
        If Not Volume = Nothing Then CurrentWave.Volume = Volume
        Try
            CurrentWave.Init(Reader)
            CurrentWave.Play()
        Catch ex As Exception
            MsgBox("The selected audio device may already be in use by another application." & vbNewLine & vbNewLine & "Error: " & ex.Message, vbOKOnly + vbInformation, "Play File")
        End Try
        '================================================================

    End Sub
On stop, the following code triggers which disposes of the objects via their references. The sender object is the correct reference there for the WaveOut object. If I use the var reference CurWave there it disposes the wrong object... so this seems to work.
Private Sub PlaybackStopping(sender As Object, e As NAudio.Wave.StoppedEventArgs)
        ' if current WaveEvent object is instanced
        If sender IsNot Nothing Then
            ' if currrent WaveEvent is playing
            If sender.playbackstate = sender.PlaybackState.Playing Then
                ' stop the wave out device
                sender.stop()
                ' stop / null the UI meters when stopping playback
                ' volume meters are run from a timer in the main form
                Main.VolumeMeter1.Amplitude = 0
                Main.VolumeMeter2.Amplitude = 0
            End If

            ' dispose objects on every stop or re-trigger cycle
            CurrentStream.Dispose()
            ' sender should always be CurrentWave so
            ' this reference should always dispose of it
            sender.Dispose()
        End If