locked
Play multiple audio files at once visual basic RRS feed

  • 问题

  • Hi

    I'm making a virtual piano in Visual Basic,VB.NET, Visual Studio Community 2013. However I found a problem. I've been using the function "My.Computer.Audio.Play(My.Resources.C, AudioPlayMode.Background)" to play a certain note, but then if I want to play another note it just cuts the sound of the previous, when what I wanted was to play the two notes at the same time.

    Isn't there any function that allows to play an entire audio file until the end?

    Thanks in advance

    2015年2月19日 19:41

答案

  • Hi,

     If all you want to be able to do is to Play multiple sounds at the same time and you want each one to play to the end even when starting another sound then here is a small class you can add to your program to do this. It is a class i made for playing multiple game sounds that i stripped out all functionality except for Adding and Playing multiple sounds. If you need more functionality like Pausing, Stopping, and Volume control of each sound then it needs to be reworked to include that too.

     However, as with most every method you will find to play sound files, the files will have to be on the hard drive. You can just keep them in a folder on the hard drive instead of adding them to the Resources. If you really want them in the resources then you will have to do more work to write them back to the hard drive first.

     This code will play (.wav) or (.mp3) audio files. You can add the class to you project by clicking (Project) on the VB menu and selecting (Add Class). Name it (MultiSounds.vb) and then copy this class code to the new class.

    Imports System.Runtime.InteropServices
    
    Public Class MultiSounds
        Private Snds As New Dictionary(Of String, String)
        Private sndcnt As Integer = 0
    
        <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 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), Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Return True
        End Function
    End Class
     

     Then in your Form you can use it like this. When you add a sound you specify a Name you want to refer to the sound as in the first parameter and the full path and name to the sound file in the second parameter. That is shown in the Form Load event. One thing to note is that you can not use the same Name twice.

     Then to Play the sound you specify the Name of the sound you want to play. The Name is the Name you gave it when you added the sound.

    Public Class Form1
        Private Snds As New MultiSounds
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Snds.AddSound("Note A", "C:\Test\Sound Folder\E Key.wav")
            Snds.AddSound("Note G", "C:\Test\Sound Folder\G Key.wav")
            Snds.AddSound("Note B", "C:\Test\Sound Folder\B Key.wav")
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Snds.Play("Note A")
        End Sub
    
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Snds.Play("Note G")
        End Sub
    
        Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
            Snds.Play("Note B")
        End Sub
    End Class


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

    2015年2月20日 17:00

全部回复

  • An entire audio file would not be a single note would it? My.Computer.Audio.Play is for playing audio files of type .Wav I believe.

    Other players can not play directly from resources and require a file to be written to disk first typically.

    Even then trying to exactly coincide two different players to begin at the exact same moment, assuming your two files are the same length in time, so they play together may be difficult.


    La vida loca

    2015年2月19日 23:31
  • This seems to work in some fashion after each Windows Media Player has begun playing a file from Disk as I suppose each will then have buffered data ready maybe.

    Anyhow the initial loop creates 88 Windows Media Players, to represent 88 piano keys, which are never displayed or added as controls to a Form. They are all added to a List(Of WMPLib.WindowsMediaPlayer). And the index is 0 to 87 to use them from the List.

    I used Audacity (which is free) to create four 1 minute long MP3 files of 300, 500, 700 and 900 hertz sine waves. And the first four WMP's in the List are provided a single file each for their playlist as each WMP is only suppose to ever play one tone.

    All of the WMP's are started in the load event as that seems to get them to access their files and I suppose buffer some data. They play for about 5 seconds and then the Timer shuts them all off. That time could be shortened significantly I'm sure. Anyhow without doing this then the first time a Button is selected there is a delay between the selection of the Button and its WMP playing a tone probably because the WMP has to access the file on disk and I suppose has no buffered data in it yet.

    Option Strict On
    
    Imports WMPLib  ' Project, Add Reference, Com, Type Libraries, Windows Media Player
    
    Public Class Form1
    
        Dim WMPList As New List(Of WMPLib.WindowsMediaPlayer)
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
            For i = 1 To 88
                WMPList.Add(New WMPLib.WindowsMediaPlayer)
            Next
            WMPList(0).currentPlaylist.appendItem(WMPList(0).newMedia("C:\Users\John\Desktop\Tones\ThreeHundred.MP3"))
            WMPList(1).currentPlaylist.appendItem(WMPList(1).newMedia("C:\Users\John\Desktop\Tones\FiveHundred.MP3"))
            WMPList(2).currentPlaylist.appendItem(WMPList(2).newMedia("C:\Users\John\Desktop\Tones\SevenHundred.MP3"))
            WMPList(3).currentPlaylist.appendItem(WMPList(3).newMedia("C:\Users\John\Desktop\Tones\NineHundred.MP3"))
            For i = 0 To 87
                WMPList(i).controls.play()
            Next
            Timer1.Interval = 5000
            Timer1.Start()
        End Sub
    
        Private Sub Button1_MouseDown(sender As Object, e As MouseEventArgs) Handles Button1.MouseDown
            WMPList(0).controls.play()
        End Sub
    
        Private Sub Button1_MouseUp(sender As Object, e As MouseEventArgs) Handles Button1.MouseUp
            Try
                WMPList(0).controls.currentPosition = 0
                WMPList(0).controls.stop()
            Catch ex As Exception
            End Try
        End Sub
    
        Private Sub Button2_MouseDown(sender As Object, e As MouseEventArgs) Handles Button2.MouseDown
            WMPList(1).controls.play()
        End Sub
    
        Private Sub Button2_MouseUp(sender As Object, e As MouseEventArgs) Handles Button2.MouseUp
            Try
                WMPList(1).controls.currentPosition = 0
                WMPList(1).controls.stop()
            Catch ex As Exception
            End Try
        End Sub
    
        Private Sub Button3_MouseDown(sender As Object, e As MouseEventArgs) Handles Button3.MouseDown
            WMPList(2).controls.play()
        End Sub
    
        Private Sub Button3_MouseUp(sender As Object, e As MouseEventArgs) Handles Button3.MouseUp
            Try
                WMPList(2).controls.currentPosition = 0
                WMPList(2).controls.stop()
            Catch ex As Exception
            End Try
        End Sub
    
        Private Sub Button4_MouseDown(sender As Object, e As MouseEventArgs) Handles Button4.MouseDown
            WMPList(3).controls.play()
        End Sub
    
        Private Sub Button4_MouseUp(sender As Object, e As MouseEventArgs) Handles Button4.MouseUp
            Try
                WMPList(3).controls.currentPosition = 0
                WMPList(3).controls.stop()
            Catch ex As Exception
            End Try
        End Sub
    
        Private Sub Button5_MouseDown(sender As Object, e As MouseEventArgs) Handles Button5.MouseDown
            WMPList(0).controls.play()
            WMPList(1).controls.play()
            WMPList(2).controls.play()
            WMPList(3).controls.play()
        End Sub
    
        Private Sub Button5_MouseUp(sender As Object, e As MouseEventArgs) Handles Button5.MouseUp
            Try
                WMPList(0).controls.currentPosition = 0
                WMPList(1).controls.currentPosition = 0
                WMPList(2).controls.currentPosition = 0
                WMPList(3).controls.currentPosition = 0
                WMPList(0).controls.stop()
                WMPList(1).controls.stop()
                WMPList(2).controls.stop()
                WMPList(3).controls.stop()
            Catch ex As Exception
            End Try
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Timer1.Stop()
    
            For i = 0 To 87
                WMPList(i).controls.currentPosition = 0
                WMPList(i).controls.stop()
            Next
    
        End Sub
    
    End Class




    La vida loca

    2015年2月20日 2:16
  • Hi

    I'm making a virtual piano in Visual Basic,VB.NET, Visual Studio Community 2013. However I found a problem. I've been using the function "My.Computer.Audio.Play(My.Resources.C, AudioPlayMode.Background)" to play a certain note, but then if I want to play another note it just cuts the sound of the previous, when what I wanted was to play the two notes at the same time.

    Isn't there any function that allows to play an entire audio file until the end?

    Thanks in advance

    I would try using Direct Play.


    “If you want something you've never had, you need to do something you've never done.”

    Don't forget to mark helpful posts and answers ! Answer an interesting question? Write a new article about it! My Articles
    *This post does not reflect the opinion of Microsoft, or its employees.

    2015年2月20日 2:46
  • Hi

    I'm making a virtual piano in Visual Basic,VB.NET, Visual Studio Community 2013. However I found a problem. I've been using the function "My.Computer.Audio.Play(My.Resources.C, AudioPlayMode.Background)" to play a certain note, but then if I want to play another note it just cuts the sound of the previous, when what I wanted was to play the two notes at the same time.

    Isn't there any function that allows to play an entire audio file until the end?

    Thanks in advance

    I would try using Direct Play.


    “If you want something you've never had, you need to do something you've never done.”

    Don't forget to mark helpful posts and answers ! Answer an interesting question? Write a new article about it! My Articles
    *This post does not reflect the opinion of Microsoft, or its employees.


    This says it's deprecated Microsoft.DirectX.DirectPlay but with MS it's possible that it's not deprecated just moved to some other namespace maybe.

    La vida loca

    2015年2月20日 4:31
  • Hi,

     If all you want to be able to do is to Play multiple sounds at the same time and you want each one to play to the end even when starting another sound then here is a small class you can add to your program to do this. It is a class i made for playing multiple game sounds that i stripped out all functionality except for Adding and Playing multiple sounds. If you need more functionality like Pausing, Stopping, and Volume control of each sound then it needs to be reworked to include that too.

     However, as with most every method you will find to play sound files, the files will have to be on the hard drive. You can just keep them in a folder on the hard drive instead of adding them to the Resources. If you really want them in the resources then you will have to do more work to write them back to the hard drive first.

     This code will play (.wav) or (.mp3) audio files. You can add the class to you project by clicking (Project) on the VB menu and selecting (Add Class). Name it (MultiSounds.vb) and then copy this class code to the new class.

    Imports System.Runtime.InteropServices
    
    Public Class MultiSounds
        Private Snds As New Dictionary(Of String, String)
        Private sndcnt As Integer = 0
    
        <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 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), Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Return True
        End Function
    End Class
     

     Then in your Form you can use it like this. When you add a sound you specify a Name you want to refer to the sound as in the first parameter and the full path and name to the sound file in the second parameter. That is shown in the Form Load event. One thing to note is that you can not use the same Name twice.

     Then to Play the sound you specify the Name of the sound you want to play. The Name is the Name you gave it when you added the sound.

    Public Class Form1
        Private Snds As New MultiSounds
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Snds.AddSound("Note A", "C:\Test\Sound Folder\E Key.wav")
            Snds.AddSound("Note G", "C:\Test\Sound Folder\G Key.wav")
            Snds.AddSound("Note B", "C:\Test\Sound Folder\B Key.wav")
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Snds.Play("Note A")
        End Sub
    
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
            Snds.Play("Note G")
        End Sub
    
        Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
            Snds.Play("Note B")
        End Sub
    End Class


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

    2015年2月20日 17:00
  • Thanks a lot for your help, IronRazerz.

    However, I couldn't run the code. I get an error saying:

    "Snds' is not declared. It may be inaccessible due to its protection level."

    Do you have any idea of why this happens and what can I do to fix it?

    Thanks in advance

    2015年2月22日 22:55
  • Thanks a lot for your help, IronRazerz.

    However, I couldn't run the code. I get an error saying:

    "Snds' is not declared. It may be inaccessible due to its protection level."

    Do you have any idea of why this happens and what can I do to fix it?

    Thanks in advance


     What line or lines is it giving you this error on ? Please show your full code if possible.

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

    2015年2月23日 0:26
  • I get an error everytime I use Snds. For example with just this sample of code:

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Snds.AddSound("NoteA", "‪C:\Music_Notes\A.wav")
    
        End Sub
    
    End Class

     I get an error saying:""Snds' is not declared. It may be inaccessible due to its protection level."

    I heard of some bug in VS2013 that displayed this error. Is it related to that or a totally different thing? 

    2015年2月23日 16:21
  • I get an error everytime I use Snds. For example with just this sample of code:

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Snds.AddSound("NoteA", "‪C:\Music_Notes\A.wav")
    
        End Sub
    
    End Class

     I get an error saying:""Snds' is not declared. It may be inaccessible due to its protection level."

    I heard of some bug in VS2013 that displayed this error. Is it related to that or a totally different thing? 

    I don't see this in your code "Private Snds As New MultiSounds" or anywhere that Snds was declared. So how can you use it in your Form Load event if it's not declared anywhere?

    Have you ever declared a variable? Like "Dim This As Integer = 0"? That would declare the variable "This".

    Do you realize why IronRazerz provided two sets of code in his post? Did you bother following the instructions on how to use it? If you don't know much and then don't follow instructions how can you expect your code to work by leaving things out of it?


    La vida loca

    2015年2月23日 17:16
  • Hi,

     As Mr. Monkeyboy pointed out you did not declare Snds as was shown in my example. Your code should look like this.

    Public Class Form1
        Private Snds As New MultiSounds 'you need to declare Snds as a new MultiSounds class
    
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
            Snds.AddSound("NoteA", "‪C:\Music_Notes\A.wav")
    
        End Sub
    
    End Class


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

    2015年2月23日 17:33
  • Ray,

    Great, tested and does what it should do.


    Success
    Cor

    2015年2月23日 17:56
  • Ray,

    Great, tested and does what it should do.


    Success
    Cor

     Thanks Cor.  It is a really striped down version of a small class for Game Sounds i wrote a while ago because of all the questions about playing multiple sounds at one time we get. There are several ways to do it like using the MediaPlayer as you pointed out but, you know me, i love playing with API`s.   8)

     EDIT - I thought i saw a post that you mentioned the MediaPlayer. Ether you removed it or i am imagining things.  8()


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

    2015年2月23日 18:29

  •  EDIT - I thought i saw a post that you mentioned the MediaPlayer. Ether you removed it or i am imagining things.  8()


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

    Removed

    Success
    Cor

    2015年2月23日 18:55
  • Thanks I managed to correct that mistake.

    But now, when I run the program and click on the buttons it doesn't play any sound. What can be the cause?

    2015年2月23日 23:26
  • I can`t see your code so i don`t know. You need to post your whole code.

     Also, make sure your MultiSounds class code looks exactly the same as i posted above. Make sure your sound file exists and that your volume is turned up too.

     The AddSound function will return True or False to tell you if the sound was opened and added successfully. Try checking the return value to see what it is.


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

    2015年2月24日 0:03
  • So I am curious... I started to use this code on my own piano that I am creating, and it works very well. There were a few features I was hoping to add, such as stopping all sound happening rather than waiting for the notes to taper off. I understand that when using the my.computer.audio.play built into vb you can also use my.computer.audio.stop. Is there a way I can stop the audio using this code? I am not exactly sure how to if you can. Thanks
    2015年12月31日 17:51
  • tedw1662,

       I am not sure if you are asking about my code or not,  when you ask a question you should use an "@ PersonName" so we know who you are talking to.  However,  if you are asking me then yes,  you can change the MultiSounds class code as shown below to add a Stop function to it.

     You can then start the sound as you already do.

    Play("SoundName")

     Then you can stop it using the Stop function.

    Stop("SoundName")

    Imports System.Runtime.InteropServices
    
    Public Class MultiSounds
        Private Snds As New Dictionary(Of String, String)
        Private sndcnt As Integer = 0
    
        <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 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), Nothing, 0, IntPtr.Zero) <> 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
    End Class

     


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

    2015年12月31日 18:42
  • @ IronRazerz

    Thanks for your help, and thanks for clarifying responses. I just joined the forums so it's much appreciated.

    2015年12月31日 21:34
  • @ IronRazerz

    Thanks for your help, and thanks for clarifying responses. I just joined the forums so it's much appreciated.


     You`re Welcome.   8)

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

    2015年12月31日 21:44
  • @ IronRazerz

    Actually, I do have one more question about the mutlisounds class, if you wouldn't mind. While making my piano App I created buttons that are pressed when certain keys are pressed. In doing so I have made it so that the specific note plays when the key is pressed. While holding the button though, there is a slight delay before the note starts repeating rapidly. Is there any way to configure the coding so when I press the button once and hold it won't rapidly replay? 

    Another thing I have discovered with some other piano application other people have made is that if you press a key continually, the audio will obviously replay whenever the key is struck, but it is never cut off. In my program I am in the situation where I will, for instance, strike a key three times. instead of hearing the note end three times, or until it stops ringing, I will hear the note play and then cut off, and begin on the next strike. It is kind of hard to explain I suppose... but if you understand what I am talking about any input would be very much appreciated. Thanks!

    2016年1月1日 2:09
  • Hi, upon implementing your code above IronRazerz (the code in 2 halves with the new class), I am unsure on what to do in regards to the file location. I have my files in the resources section of the program and where you have "C:\..." I have "My.Resouces.file name here. Any help would be greatly appreciated.
    2016年8月24日 9:08
  • Hi, upon implementing your code above IronRazerz (the code in 2 halves with the new class), I am unsure on what to do in regards to the file location. I have my files in the resources section of the program and where you have "C:\..." I have "My.Resouces.file name here. Any help would be greatly appreciated.

     The method i use in the class can not play files directly from the application`s resources.  You would have to either write the files back to the hard drive first OR just keep your audio files in a folder along side of your application and not in the resources.

     If you choose to keep them in the resources,  then it will depend on the type of audio files (.wav) or (.mp3) that you have added to the resources that will depend on the method you need to use to write them back to the hard drive.

     Below i give an example of writing both types to the hard drive from the resources.  I would recommend using the ApplicationData folder as i show here if you do not want the user to find them easily.  Otherwise you can just save them in a folder in the Documents folder.

     However,  if you have a bunch of audio files,  it would be better to just keep them in a folder along side your application.

    Public Class Form1
        Private MyAppDataFolder As String = IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), My.Application.Info.AssemblyName)
        Private WaveAudioFileName As String = IO.Path.Combine(MyAppDataFolder, "My Wave Audio File.wav") 'give the wave file whatever name you want
        Private Mp3AudioFileName As String = IO.Path.Combine(MyAppDataFolder, "My Mp3 File.mp3") 'give the mp3 file whatever name you want
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
            'If MyAppDataFolder does not exist, then creat it
            If Not IO.Directory.Exists(MyAppDataFolder) Then IO.Directory.CreateDirectory(MyAppDataFolder)
    
            'If the audio files are Wave Audio (.wav) types then you need to use this method to write them from the resources to the hard drive.
            'Check if the file exists, if it does not then write it to the hard drive
            If Not IO.File.Exists(WaveAudioFileName) Then
                Dim bts(CInt(My.Resources.MyAudioFile.Length - 1)) As Byte
                My.Resources.MyAudioFile.Read(bts, 0, bts.Length)
                IO.File.WriteAllBytes(WaveAudioFileName, bts)
            End If
    
            'If the audio files are Mp3 types, then you need to use this method to write them from the resources to the hard drive
            'Check if the file exists, if it does not then write it to the hard drive
            If Not IO.File.Exists(Mp3AudioFileName) Then IO.File.WriteAllBytes(Mp3AudioFileName, My.Resources.MyMp3File)
    
        End Sub
    End Class
    


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

    2016年8月24日 22:11
  • Hi! If your still active, when using the Snds.AddSound I can't import anything from My.Resources
    2018年8月25日 8:31
  • Hi! If your still active, when using the Snds.AddSound I can't import anything from My.Resources

     The method I use for playing the files requires an audio file to be on the hard drive.  It can not play a file directly from your application's resources.  You would have to save the files from your resources back to the hard drive first,  then supply the filename to the AddSound method.  You can see the answer/example I posted at This Link to see how you can write an Mp3, Wmv, or Midi file to the hard drive.  It is in the Form Load event of that example,  it uses the File.WriteAllBytes to do it.

     If the files in your resources are wave audio files (.wav),  then you could use DirectX DirectSound to play them directly from the resources.  You can find info and an example I posted about half way down the page in This Link in the GameSound class.  However,  you may want/need to set up your own class?


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

    2018年8月25日 11:25
  • @ IronRazerz I know this is an old thread but I've just added your class to my project and wondered if it's possible to play a sound in a loop ?

    I tried adding a PlayLoop function to the class with the 'repeat' flag but it doesn't play anything (not sure if this is the correct way to do it though).

    Public Function PlayLoop(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) & " repeat", Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Return True
    End Function

    2019年9月4日 10:01
  • @ IronRazerz I know this is an old thread but I've just added your class to my project and wondered if it's possible to play a sound in a loop ?

    I tried adding a PlayLoop function to the class with the 'repeat' flag but it doesn't play anything (not sure if this is the correct way to do it though).

    Public Function PlayLoop(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) & " repeat", Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            Return True
    End Function

    Lee,

    I spent some time trying to get this to work and could not.

    Several "things" I read from others with same problem lead me to believe it does not work in .net and that is a bug?

    There is also "notify" that uses an event handler but I could not get it to do anything either.

    If you like I can post a working example that uses WindowsMediaPlayer to play a song and a timer to make a repeat function. I ended up using both methods to do things in my audio project.


    2019年9月5日 7:52
  • I tried adding a PlayLoop function to the class with the 'repeat' flag but it doesn't play anything (not sure if this is the correct way to do it though).

    You must add "type mpegvideo" for repeat
    2019年9月5日 8:14
  • I tried adding a PlayLoop function to the class with the 'repeat' flag but it doesn't play anything (not sure if this is the correct way to do it though).

    You must add "type mpegvideo" for repeat

    Oh. Ok. This seems to repeat now playing a .wav file. See where I added type mpegvideo to Razerz class named MultiSounds2 here.

    Public Class MultiSounds2
        Private Snds As New Dictionary(Of String, String)
        Private sndcnt As Integer = 0
    
        <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 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
            'If mciSendStringW("open " & Chr(34) & SndFilePath & Chr(34) & " type waveaudio alias " & "Snd_" & sndcnt.ToString, Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            If mciSendStringW("open " & Chr(34) & SndFilePath & Chr(34) & " type mpegvideo 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) & “ repeat”, Nothing, 0, IntPtr.Zero) <> 0 Then Return False
            'If mciSendStringW("play " & Snds.Item(SoundName), Nothing, 0, IntPtr.Zero) <> 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
    End Class


    PS It does not make sense? but there you go.  :)

    2019年9月5日 8:31
  • Lee,

    I spent some time trying to get this to work and could not.

    Several "things" I read from others with same problem lead me to believe it does not work in .net and that is a bug?

    There is also "notify" that uses an event handler but I could not get it to do anything either.

    If you like I can post a working example that uses WindowsMediaPlayer to play a song and a timer to make a repeat function. I ended up using both methods to do things in my audio project.


    Thanks for replying.
    I'd like to see your example.
    2019年9月5日 8:42
  • I tried adding a PlayLoop function to the class with the 'repeat' flag but it doesn't play anything (not sure if this is the correct way to do it though).

    You must add "type mpegvideo" for repeat
    Where would I put this - can you give a working example ?
    Is this for audio (.wav) files ?
    2019年9月5日 8:43
  • Lee,

    I spent some time trying to get this to work and could not.

    Several "things" I read from others with same problem lead me to believe it does not work in .net and that is a bug?

    There is also "notify" that uses an event handler but I could not get it to do anything either.

    If you like I can post a working example that uses WindowsMediaPlayer to play a song and a timer to make a repeat function. I ended up using both methods to do things in my audio project.


    Thanks for replying.
    I'd like to see your example.

    This a mediaplayer example with play, stop and repeat.

    The example makes the controls just cut and paste into an empty form. Change form name and song path as required.

    'play wav mediaplayer with repeat using timer
    Imports System.Runtime.InteropServices
    
    Public Class Form1
        Private WithEvents Timer1 As New Timer With {.Interval = 50, .Enabled = False}
        Private WithEvents PlayBtn As New Button With {.Parent = Me, .Size = New Size(50, 24),
            .FlatStyle = FlatStyle.Flat, .Location = New Point(100, 50), .Text = "Play",
            .ForeColor = Color.AntiqueWhite, .BackColor = Color.Green}
        Private WithEvents RepeatCb As New CheckBox With {.Parent = Me,
            .FlatStyle = FlatStyle.Flat, .Location = New Point(200, 50), .Text = "Repeat",
            .Checked = True}
    
        Private WithEvents Player As New WMPLib.WindowsMediaPlayer
    
        Private PlaySong As String = "c:\test sounds\blondi rapture.wav"
    
        Private Sub Form4_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        End Sub
        Private Sub PlayBtn_Click(sender As Object, e As EventArgs) Handles PlayBtn.Click
    
            If PlayBtn.Text = "Stop" Then
                Timer1.Stop()
                Player.controls.stop()
                Player.controls.currentPosition = 0
                PlayBtn.Text = "Play"
                PlayBtn.BackColor = Color.Green
            Else
    
                Player.URL = PlaySong
                Player.controls.play()
    
                PlayBtn.Text = "Stop"
                PlayBtn.BackColor = Color.Red
                Timer1.Start()
            End If
        End Sub
    
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    
            If Player.controls.currentPosition > 0.2 _
                AndAlso Player.controls.currentPosition + 0.2 > Player.controls.currentItem.duration Then
                If RepeatCb.Checked Then
                    'repeat
                    Player.controls.currentPosition = 0
                Else
                    'stop
                    PlayBtn_Click(0, Nothing)
                End If
            End If
        End Sub
    
    End Class

    2019年9月5日 8:51
  • I tried adding a PlayLoop function to the class with the 'repeat' flag but it doesn't play anything (not sure if this is the correct way to do it though).

    You must add "type mpegvideo" for repeat

    Where would I put this - can you give a working example ?
    Is this for audio (.wav) files ?

    See the updated class from Razerz example MultiSounds2 I posted above?

    Just use Razerz example and replace the class.

    In my example MultiSounds2 see where the original lines are commented out and the new type mpegvideo and repeat are added?

    2019年9月5日 8:53
  • Many thanks to both for replying and thanks for the examples.

    This is now working.

    2019年9月5日 9:57
  • This is a really helpful, straightforward class.

    I have one question - can I specify a volume for each of the registered sounds? I'd like to play items at different levels.

    2020年3月17日 20:33
  • This is a really helpful, straightforward class.

    I have one question - can I specify a volume for each of the registered sounds? I'd like to play items at different levels.

    One must SCALE the wav amplitude. So you read a byte array as above and then multiply the values by a scaling factor ie 1 to 9. I am not sure really at the moment but think that is how. So you change the actual wav file level not the computer volume.

    However you should start your own question thread it is best for searching and etc. Post a new question of your own and then reference it here. I will try to make an example. 

    Plus if you post a new question you get new looks and suggestions form other members.

    2020年3月17日 22:20
  • This is a really helpful, straightforward class.

    I have one question - can I specify a volume for each of the registered sounds? I'd like to play items at different levels.

    If you're talking about mciSendString

    it is done with setaudio  command (volume to ...)

    2020年3月17日 23:50
  • Hi IronRazers,

    How to stop it ?

    2020年9月24日 4:19