Search code examples
.netaudioplayback

VB.NET (2008) Playing Sound


I've been working on a program which has this feature of allowing the user to select a WAV sound for the program to play.

Since this feature is placed on the options dialogue, I wanted this to happen:

1) Click the button

2) The button changes the image from A to B and the sound is played

a) The user doesn't like the sound and wants to stop it - clicks again and goes to 3)

3) The sound reaches the end and the image comes back to A.

My main objective is to allow the user to interrupt the sound at any time (on step 2 a).

I've tried two methods:

Dim p as New Media.SoundPlayer

p.SoundLocation = fn 'Where fn is the FileName, the WAV location
p.Play

This works out fine, except I can't detect when the sound reaches its end, even when I tried to use p.Stream.Length and p.Stream.Position it returns an error, because it was actually null, and when it wasn't (I tried My.Computer.Audio.Play with the WAV represented by a Stream) those properties had the same value even before the sound had stopped.

After this, I tried:

My.Computer.Audio.Play(fn,AudioPlayMode.WaitToComplete)

But what happens, as I suspected, is that the program freezes until the sound ends, disabling the user to interrupt it or do anything at all.

Fortunately, System.Media.SoundPlayer allows you to declare it with events, like this:

Private WithEvents p as System.Media.SoundPlayer

Even though, none of those events are useful to do what I need.

Any suggestions? Thanks in advance


Solution

  • Here's a solution using the mciSendString() API which allows you to PLAY and CANCEL a WAV file, while also giving you a notification that the WAV file has COMPLETED playing:

    Imports System.Runtime.InteropServices
    Public Class Form1
    
        Private PlayingWav As Boolean = False
        Private Const MM_MCINOTIFY As Integer = 953
    
        <DllImport("winmm.dll")> _
        Private Shared Function mciSendString( _
            ByVal command As String, _
            ByVal buffer As System.Text.StringBuilder, _
            ByVal bufferSize As Integer, _
            ByVal hwndCallback As IntPtr _
            ) As Integer
        End Function
    
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            If Not PlayingWav Then
                PlayWavFile(TextBox1.Text)
            Else
                StopWavFile()
            End If
        End Sub
    
        Public Sub PlayWavFile(ByVal WavFilePath As String)
            Dim cmd As String = "open " & Chr(34) & WavFilePath & Chr(34) & " type waveaudio alias wav"
            If mciSendString(cmd, Nothing, 0, IntPtr.Zero) = 0 Then
                PlayingWav = True
                Button1.Text = "Stop"
                mciSendString("play wav notify", Nothing, 0, Me.Handle)
            Else
                MessageBox.Show(WavFilePath, "Error Loading Wav", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End If
        End Sub
    
        Public Sub StopWavFile()
            mciSendString("close wav", Nothing, 0, IntPtr.Zero)
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
            Select Case m.Msg
                Case MM_MCINOTIFY
                    WavStopped()
    
            End Select
            MyBase.WndProc(m)
        End Sub
    
        Private Sub WavStopped()
            PlayingWav = False
            Button1.Text = "Play"
        End Sub
    
    End Class