locked
How to play sounds not in background? RRS feed

  • Question

  • Hello.

     I want to have a background music and to when a button is clicked to play another sound. But My.Computer.Audio.Play only plays sounds in background, that will stop the music. Maybe using SoundPlayer.. but how to use it?

    Thanks.


    Greetings

    Friday, June 3, 2016 5:57 PM

Answers

  •  As has been mentioned,  the Media.MediaPlayer can be used to do this,  however there are other methods that can be used but,  they will require a bit more code to build a sound player class.  Below is a stripped down version of a class i designed for Game Sounds which can play several sounds at one time.  For example,  some background music that will keep looping at the same time the user is blasting the enemy with a Machine Gun.

     If you want to test it out,  you can create a new Form project and add a Class to it named MultiSoundPlayer.  Then use the code below for it.

    Imports System.Runtime.InteropServices
    
    Public Enum MCI_NOTIFY As Integer
        SUCCESSFUL = &H1 'the sound ended by playing all the way to the end
        SUPERSEDED = &H2 'the sound ended because of another mciSendString command being executed on the sound
        ABORTED = &H4 'the sound ended because the Stop method was called
        FAILURE = &H8 'the sound failed
    End Enum
    
    Public Class MultiSoundPlayer
        Inherits NativeWindow
    
        Public Event SoundEnded(ByVal SndName As String, ByVal Msg As MCI_NOTIFY)
        Private Snds As New Dictionary(Of String, String)
        Private sndcnt As Integer = 0
        Private Const MM_MCINOTIFY As Integer = &H3B9
        Private Const WM_NCDESTROY As Integer = &H82
    
        <DllImport("winmm.dll", EntryPoint:="mciSendStringW")>
        Private Shared Function mciSendStringW(<MarshalAs(UnmanagedType.LPTStr)> ByVal lpszCommand As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszReturnString As System.Text.StringBuilder, ByVal cchReturn As UInteger, ByVal hwndCallback As IntPtr) As Integer
        End Function
    
        Public Sub New(ByVal ParentForm As Form)
            If ParentForm Is Nothing Then Throw New Exception("The ParentForm can not be Nothing")
            Dim cp As New CreateParams With {.Parent = ParentForm.Handle}
            Me.CreateHandle(cp)
        End Sub
    
        Public Function AddSound(ByVal SoundName As String, ByVal SndFilePath As String) As Boolean
            If SoundName.Trim = "" Or Not IO.File.Exists(SndFilePath) Then Return False
            If mciSendStringW("open " & Chr(34) & SndFilePath & Chr(34) & " alias " & "Snd_" & sndcnt.ToString, Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Snds.Add(SoundName, "Snd_" & sndcnt.ToString)
            sndcnt += 1
            Return True
        End Function
    
        Public Function Play(ByVal SoundName As String) As Boolean
            If Not Snds.ContainsKey(SoundName) Then Return False
            mciSendStringW("seek " & Snds.Item(SoundName) & " to start", Nothing, 0, IntPtr.Zero)
            If mciSendStringW("play " & Snds.Item(SoundName) & " notify", Nothing, 0, Me.Handle) <> 0 Then Return False
            Return True
        End Function
    
        Public Function [Stop](ByVal SoundName As String) As Boolean
            If Not Snds.ContainsKey(SoundName) Then Return False
            If mciSendStringW("stop " & Snds.Item(SoundName), Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Return True
        End Function
    
        Public Sub CloseAndClearSounds()
            For Each aliasname As String In Snds.Values
                mciSendStringW("close " & aliasname, Nothing, 0, IntPtr.Zero)
            Next
            sndcnt = 0
            Snds.Clear()
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As Message)
            If m.Msg = WM_NCDESTROY Then
                Me.CloseAndClearSounds()
                Me.ReleaseHandle()
            End If
            MyBase.WndProc(m)
            If m.Msg = MM_MCINOTIFY Then
                Dim sn As String = Snds.ElementAt((m.LParam.ToInt32 - 1)).Key
                RaiseEvent SoundEnded(sn, CType(m.WParam.ToInt32, MCI_NOTIFY))
            End If
        End Sub
    End Class
    


     

     Then you can add 1 Button to the Form and use the code below for the Form.  You will need to change the paths to some (.wav  or  .mp3) sound files on your computer.  You can add as many sounds as you want, within reason that is.

    Public Class Form1
        Private WithEvents Player As MultiSoundPlayer 'declare a MultiSoundPlayer class using the WithEvents keyword so you can access the SoundEnded event

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Player = New MultiSoundPlayer(Me) 'create a new instance of the MultiSoundPlayer class and pass this form as the Parent

            'add each sound you want to the Player by specifying a Unique Name for each sound and the full path to the sound file
            Player.AddSound("Music", "C:\Test\Sounds\BackgroundMusic.mp3")
            Player.AddSound("Machine Gun", "C:\Test\Sounds\MachineGun.wav")
            Player.AddSound("Crazy Laugh", "C:\Test\Sounds\CrazyLaugh.wav")

            Player.Play("Music") 'start playing the background music while the form loads
        End Sub

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Player.Play("Crazy Laugh") 'start laughing crazily....
            Player.Play("Machine Gun") 'as you blast the enemy with the machine gun.
        End Sub

        Private Sub Player_SoundEnded(SndName As String, Msg As MCI_NOTIFY) Handles Player.SoundEnded
            'if the name of the sound that is ending is the name of the background music and the Msg is SUCCESSFUL, then replay the music or start another.
            If SndName = "Music" AndAlso Msg = MCI_NOTIFY.SUCCESSFUL Then
                Player.Play("Music")
            End If
        End Sub
    End Class
     

     


    If you say it can`t be done then i`ll try it

    Friday, June 3, 2016 9:52 PM
  • If you are looking to play sounds at the same time then see the below link:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/c29877ef-1466-49fd-a508-ec7e9b664237/play-sound-in-background-play-another-sound?forum=vbgeneral


    Paul ~~~~ Microsoft MVP (Visual Basic)

    Friday, June 3, 2016 7:08 PM
  • You can also take a look at the example used in this codeplex project.  If you factor out the "game engine" you can reuse most of that code, or use it as a template for creating your own audio player class.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, June 3, 2016 7:39 PM

All replies

  • If you are looking to play sounds at the same time then see the below link:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/c29877ef-1466-49fd-a508-ec7e9b664237/play-sound-in-background-play-another-sound?forum=vbgeneral


    Paul ~~~~ Microsoft MVP (Visual Basic)

    Friday, June 3, 2016 7:08 PM
  • You can also take a look at the example used in this codeplex project.  If you factor out the "game engine" you can reuse most of that code, or use it as a template for creating your own audio player class.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, June 3, 2016 7:39 PM
  •  As has been mentioned,  the Media.MediaPlayer can be used to do this,  however there are other methods that can be used but,  they will require a bit more code to build a sound player class.  Below is a stripped down version of a class i designed for Game Sounds which can play several sounds at one time.  For example,  some background music that will keep looping at the same time the user is blasting the enemy with a Machine Gun.

     If you want to test it out,  you can create a new Form project and add a Class to it named MultiSoundPlayer.  Then use the code below for it.

    Imports System.Runtime.InteropServices
    
    Public Enum MCI_NOTIFY As Integer
        SUCCESSFUL = &H1 'the sound ended by playing all the way to the end
        SUPERSEDED = &H2 'the sound ended because of another mciSendString command being executed on the sound
        ABORTED = &H4 'the sound ended because the Stop method was called
        FAILURE = &H8 'the sound failed
    End Enum
    
    Public Class MultiSoundPlayer
        Inherits NativeWindow
    
        Public Event SoundEnded(ByVal SndName As String, ByVal Msg As MCI_NOTIFY)
        Private Snds As New Dictionary(Of String, String)
        Private sndcnt As Integer = 0
        Private Const MM_MCINOTIFY As Integer = &H3B9
        Private Const WM_NCDESTROY As Integer = &H82
    
        <DllImport("winmm.dll", EntryPoint:="mciSendStringW")>
        Private Shared Function mciSendStringW(<MarshalAs(UnmanagedType.LPTStr)> ByVal lpszCommand As String, <MarshalAs(UnmanagedType.LPWStr)> ByVal lpszReturnString As System.Text.StringBuilder, ByVal cchReturn As UInteger, ByVal hwndCallback As IntPtr) As Integer
        End Function
    
        Public Sub New(ByVal ParentForm As Form)
            If ParentForm Is Nothing Then Throw New Exception("The ParentForm can not be Nothing")
            Dim cp As New CreateParams With {.Parent = ParentForm.Handle}
            Me.CreateHandle(cp)
        End Sub
    
        Public Function AddSound(ByVal SoundName As String, ByVal SndFilePath As String) As Boolean
            If SoundName.Trim = "" Or Not IO.File.Exists(SndFilePath) Then Return False
            If mciSendStringW("open " & Chr(34) & SndFilePath & Chr(34) & " alias " & "Snd_" & sndcnt.ToString, Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Snds.Add(SoundName, "Snd_" & sndcnt.ToString)
            sndcnt += 1
            Return True
        End Function
    
        Public Function Play(ByVal SoundName As String) As Boolean
            If Not Snds.ContainsKey(SoundName) Then Return False
            mciSendStringW("seek " & Snds.Item(SoundName) & " to start", Nothing, 0, IntPtr.Zero)
            If mciSendStringW("play " & Snds.Item(SoundName) & " notify", Nothing, 0, Me.Handle) <> 0 Then Return False
            Return True
        End Function
    
        Public Function [Stop](ByVal SoundName As String) As Boolean
            If Not Snds.ContainsKey(SoundName) Then Return False
            If mciSendStringW("stop " & Snds.Item(SoundName), Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Return True
        End Function
    
        Public Sub CloseAndClearSounds()
            For Each aliasname As String In Snds.Values
                mciSendStringW("close " & aliasname, Nothing, 0, IntPtr.Zero)
            Next
            sndcnt = 0
            Snds.Clear()
        End Sub
    
        Protected Overrides Sub WndProc(ByRef m As Message)
            If m.Msg = WM_NCDESTROY Then
                Me.CloseAndClearSounds()
                Me.ReleaseHandle()
            End If
            MyBase.WndProc(m)
            If m.Msg = MM_MCINOTIFY Then
                Dim sn As String = Snds.ElementAt((m.LParam.ToInt32 - 1)).Key
                RaiseEvent SoundEnded(sn, CType(m.WParam.ToInt32, MCI_NOTIFY))
            End If
        End Sub
    End Class
    


     

     Then you can add 1 Button to the Form and use the code below for the Form.  You will need to change the paths to some (.wav  or  .mp3) sound files on your computer.  You can add as many sounds as you want, within reason that is.

    Public Class Form1
        Private WithEvents Player As MultiSoundPlayer 'declare a MultiSoundPlayer class using the WithEvents keyword so you can access the SoundEnded event

        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Player = New MultiSoundPlayer(Me) 'create a new instance of the MultiSoundPlayer class and pass this form as the Parent

            'add each sound you want to the Player by specifying a Unique Name for each sound and the full path to the sound file
            Player.AddSound("Music", "C:\Test\Sounds\BackgroundMusic.mp3")
            Player.AddSound("Machine Gun", "C:\Test\Sounds\MachineGun.wav")
            Player.AddSound("Crazy Laugh", "C:\Test\Sounds\CrazyLaugh.wav")

            Player.Play("Music") 'start playing the background music while the form loads
        End Sub

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Player.Play("Crazy Laugh") 'start laughing crazily....
            Player.Play("Machine Gun") 'as you blast the enemy with the machine gun.
        End Sub

        Private Sub Player_SoundEnded(SndName As String, Msg As MCI_NOTIFY) Handles Player.SoundEnded
            'if the name of the sound that is ending is the name of the background music and the Msg is SUCCESSFUL, then replay the music or start another.
            If SndName = "Music" AndAlso Msg = MCI_NOTIFY.SUCCESSFUL Then
                Player.Play("Music")
            End If
        End Sub
    End Class
     

     


    If you say it can`t be done then i`ll try it

    Friday, June 3, 2016 9:52 PM
  • In

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
    _Player1.Open(New Uri("c:\windows\media\Windows Logon Sound.wav"))
    
    _Player1.Play()
    
    End Sub
    How do I refer to a resource file?



    Greetings

    Saturday, June 4, 2016 6:39 PM
  • In

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    
    _Player1.Open(New Uri("c:\windows\media\Windows Logon Sound.wav"))
    
    _Player1.Play()
    
    End Sub
    How do I refer to a resource file?



    Greetings


    You will have to save the resource to temporary file first if you use the MediaPlayer method.

    Paul ~~~~ Microsoft MVP (Visual Basic)

    Saturday, June 4, 2016 7:28 PM