0
votes

Okay so i created a SOUND class using mciSendString. I am using it to play music and other sound files for an RPG style game that I am making. It works, and it works well...however. My issue is that it needs the full entire path of the sound file in order for it to work (not sure if this is true).

Here are some of the querks of mcisendstring:

  • mcisendstring Hates spaces, spaces will cause crash (failure to load file) - ADD QUOTES
  • Dots in path can cause failure to load (only dot should be for the extention)
  • Very Long Paths will cause failure to load (Max Characters allowed is 255)
  • Relative paths will cause failure to load...(cannot use something like chicken.mp3 ... must use C:\chicken.mp3)
  • .wav files will fail to load if repeat = true

I tried adding the files to my resources and tried setting the path to the resource, however it said: Value of type '1-dimensional array of Byte' cannot be converted to 'String'.

Any help is greatly appreciated :)

Here is my code:

Public Class SOUND

Public Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA" _
(ByVal lpstrCommand As String, ByVal lpstrReturnString As String, ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer
'Command String VERY IMPORTANT

Private oName As String = Nothing

Public Property Name As String
    Set(value As String)
        oName = value
    End Set
    Get
        Return oName
    End Get
End Property

Public Sub Play(ByVal id As Integer, ByVal repeat As Boolean, Optional volume As Integer = 1000)

    If repeat = True Then

        mciSendString("Open " & GetFile(id) & " alias " & oName, CStr(0), 0, 0) 'Open the file
        mciSendString("play " & oName & " repeat ", CStr(0), 0, 0) 'then play with repeating value

    Else

        mciSendString("Open " & GetFile(id) & " alias " & oName, CStr(0), 0, 0)
        mciSendString("play " & oName, CStr(0), 0, 0)

    End If

    'Optionally Set Volume
    mciSendString("setaudio " & oName & " volume to " & volume, CStr(0), 0, 0)

End Sub

Public Sub Kill(ByVal song As String)

    mciSendString("close " & song, CStr(0), 0, 0)
    oName = Nothing

End Sub

' Media Library
Private Function GetFile(ByVal id As Integer) As String

    Dim path As String = ""

    'mcisendstring Hates spaces, spaces will cause crash (failure to load file) - ADD QUOTES
    'Dots in path can cause failure to load (only dot should be for the extention)
    'Very Long Paths will cause failure to load (Max Characters allowed is 255)
    'Relative paths will cause failure to load...(cannot use something like chicken.mp3 ... must use ex:[C:\chicken.mp3])
    '.wav files will fail to load if repeat = true

    Select Case id

        Case 0 'Game Over

            path = "C:\FinalFantasy7-SendaDreamIntoTheUniverse.mp3"

        Case 1 'Battle Sequence

            path = "C:\FinalFantasyTactics-Garland_Magic.mp3"

        Case 2 'Battle Victory

            path = "C:\FinalFantasyLegend2-Victory.mp3"

        Case 3 'Mission Time

            path = "C:\FinalFantasyAdventure-Mission.mp3"

    End Select

    path = Chr(34) & path & Chr(34)
    'Chr(34) is quotes...cannot just use "" because it will think that it is part of the string/path itself.


    Return path
End Function

End Class

What i need:

  • I need to somehow get the .mp3 files as a resource usable for the path's or I need some other means instead of having these files be in the root drive or some other full computer path.

EXAMPLE OF SOMETHING I NEED

Change

Select Case id

            Case 0 'Game Over

                path = "C:\FinalFantasy7-SendaDreamIntoTheUniverse.mp3"
End Select

to

Select Case id

            Case 0 'Game Over

                path = My.Resources.FinalFantasyAdventure_Mission
End Select

How I play the sound:

(on another test form)

Dim intSound As Integer = 0
Dim snd As New SOUND 'SOUND is the sound class with mcisendstring

Private Sub PlaySoundBtn_Click(sender As System.Object, e As System.EventArgs) Handles PlaySoundBtn.Click

    intSound += 1

    With snd
        .Name = "SOUND" & intSound 'SOUND is the alias along with the number (this one is SOUND1)
        .Play(3, True, 500)
        '3 is the song ID, True is for the repeat, 500 is for the optional volume (Max = 1000)
    End With

End Sub

P.S. I am using XNA Graphics in my project and I also have NuGet's BizArk Core. So if I can use either of these then please tell me how I can use either of these to do what i need to do. Thanks in advance for any help.

2
this is not possible with mciSendString. But certainly possible with XNA: msdn.microsoft.com/en-us/library/bb195053.aspx - Hans Passant
Okay, I looked at the page, however, it did not assist me whatsoever lol. How would I go about doing this in .net (Not C# or C++) - Richard Paulicelli

2 Answers

1
votes

As mentioned above, this is an old thread, but I suppose with Google there will still be people finding it (as I did today).

Just an additional suggestion, sometimes you won't have your audio file in the output directory or may wish to distribute a stand-alone executable. There's also the risk that the file can be deleted from the output directory and it's handy to be able to recreate it. Also, having a resource as part of the executable and in the output directory takes up more room than just having it as part of the executable, so sometimes it's worth only having the file on the disk temporarily (and deleting it later) rather than having to have a permanent copy there so you can access it.

In these cases, it's useful to be able to take a file from resources at runtime and save it to disk somewhere you can access (possibly a temporary file location if you want to delete it later).

The below very simple code can do that:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load

    SaveResourceObject("FinalFantasyAdventure_Mission", "C:\FinalFantasyAdventure_Mission.mp3")

End Sub

Sub SaveResourceObject(Resource as String, FileName as String)
    Dim myMemStream As New System.IO.MemoryStream
    My.Resources.ResourceManager.GetObject(Resource).CopyTo(myMemStream)
    Dim myBytes() As Byte = myMemStream.ToArray
    My.Computer.FileSystem.WriteAllBytes(FileName, myBytes, False)
End Sub

Be careful, the Resource variable in the above code is actually the name of the resource, not the resource itself. So you'll get an error if you try to do the following:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    SaveResourceObject(My.Resources.FinalFantasyAdventure_Mission, "C:\FinalFantasyAdventure_Mission.mp3")
End Sub

You could modify the code easily enough to accept the actual resource as a parameter if you prefer.

Note, I've used "C:\" in the above example but I'd recommend creating your own folder in the application data folder, which you can find using:

Dim AppDataPath as String = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData)

Or, more simply if you've imported System.Environment:

Dim AppDataPath as String = GetFolderPath(SpecialFolder.ApplicationData)
0
votes

I know this is a super old thread, but if it helps anyone, here's a solution.

You will have to use a full path, but assuming your resources are stored in /projectfolder/resources/ you can use

Dim filePath As String = Chr(34) & Application.StartupPath & "/../../Resources/myMusic.mp3" & Chr(34)
mciSendString("open " & filePath & " alias myMusic", CStr(0), 0, 0)

In VB.NET projects, Application.StartupPath is the full path to the folder the .exe is stored in. Usually that's at path/projectfolder/bin/debug/ or path/projectfolder/bin/release/. Appending /../../resources/ to that will bring you to /projectfolder/resources/, allowing you to not know the full path to your folder, as VB.NET finds it itself.