How can you save a wav resource to a file?

Germcloud

Member
Joined
Jun 6, 2010
Messages
9
Programming Experience
1-3
An application I'm building requires that I save a wav resource to a wav file on disk. I can do it just fine for mp3's, but when I try to save the wav resources I get "Error 1 Value of type 'System.IO.UnmanagedMemoryStream' cannot be converted to '1-dimensional array of Byte'."

The program needs to save both kinds of resources, mp3's and wav to a file on disk. This is what I have so far:

VB.NET:
    Public Function Add(ByRef sndResource As Byte(), ByVal blnPlay As Boolean) As Boolean

        'Add one to the count
        intTotal += 1

        'Save the filename location
        strFileName = (Application.StartupPath & "\" & "sound_" & intTotal.ToString & ".wav")

        'Create a file from the resource
        Try
            System.IO.File.WriteAllBytes(Application.StartupPath & "\" & "sound_" & intTotal.ToString & ".wav", sndResource)

        Catch ex As Exception

            'Show error message
            MsgBox(ex.Message)

            'Return false and exit function
            Return False
            Exit Function

        End Try


        'Assign the audio file
        Sound = New Audio(strFileName, blnPlay)

    End Function

And this is the call that's made to the class above:

VB.NET:
Music.Add(My.Resources.flashbulb, True)

flashbulb is the wav resource I'm trying to save. flashbulb.wav
 
My.Resources returns different types depending on the type of resource. A WAV file is not returned as a Byte array but, as the error message suggests, becomes an UnmanagedMemoryStream. You could read the data from that stream into a Byte array and then write that to a file but, really, there's no point. The SoundPlayer class and the My.Compter.Audio.Play method both accept a Stream (ANY Stream) so you can simply play your resource directly.

Apart from that, there are several issues with your code:

1. Why is your first method parameter declared ByRef? You aren't assigning a value to it in the method so there can be no reason for passing the argument by reference.

2. You should never be using Exit Function but, even more so, it's pointless after a Return statement. Any code is pointless after a Return statement because the method completes at that point. The only thing that can be executed after a Return statement is the contents of a Finally block.

3. Your method is declared as returning a Boolean but it only does so if an exception is thrown. If no exception is thrown then you don't explicitly return anything and you don't assign anything to the method's implicit Add variable, so it will implicitly return the default value for the Boolean type, i.e. False. As such, your method return False no matter what, so there's no point it even being a function at all.
 
The SoundPlayer class and the My.Compter.Audio.Play method both accept a Stream (ANY Stream) so you can simply play your resource directly.

I tried this, it will play the wav resource, but for some reason will not play the mp3 resource. I think in the past when I tried this I couldn't play no more than one file/resource at a time.

This was the solution I found that allowed me to play more that one file at the same time, but won't accept My.Resource. So I created the class to temporarily create a file from resource and load it back into the program, behind the scenes, to make it easier to use.

1. Why is your first method parameter declared ByRef? You aren't assigning a value to it in the method so there can be no reason for passing the argument by reference.

Still learning.... I had thought by passing it as a reference I would save memory, doesn't ByRef just gives a pointer to the original and ByVal passes a copy? It was somewhat of a large file I was working with, but perhaps I had misunderstood how it worked.

2. You should never be using Exit Function but, even more so, it's pointless after a Return statement. Any code is pointless after a Return statement because the method completes at that point. The only thing that can be executed after a Return statement is the contents of a Finally block.

Thanks, didn't know this.

3. Your method is declared as returning a Boolean but it only does so if an exception is thrown. If no exception is thrown then you don't explicitly return anything and you don't assign anything to the method's implicit Add variable, so it will implicitly return the default value for the Boolean type, i.e. False. As such, your method return False no matter what, so there's no point it even being a function at all.

I was originally going to return True, if the method had created the file and loaded the file back to the Sound object successfully and False if it didn't. I just hadn't coded it yet. So when it's called from the form it will eventually be something like:

VB.NET:
If Music.Add(My.Resources.Mp3Resource, True) = False Then
    'Some code here
Else
    'Some other code here
End If

But, it may not even be needed. However, thanks for pointing this out for me.

My.Resources returns different types depending on the type of resource. A WAV file is not returned as a Byte array but, as the error message suggests, becomes an UnmanagedMemoryStream. You could read the data from that stream into a Byte array and then write that to a file but, really, there's no point.

I think this is what I'm most interested in. For now, until I find a better solution, how would I do this?

Thanks again for your feedback.
 
Documentation, documentation, documentation. Read it, read it, read it. I cannot stress enough that, whenever you have a question, the relevant documentation should always be your first stop. There won;t always be relevant documentation and it won't always provide the answer, but it should always be the first thing you think of.

The SoundPlayer class and My.Computer.Audio objects both only support WAV files, which the documentation states, which would explain why it wouldn't play an MP3. That would be the first question the documentation could answer for you. I don't know whether it says that they don;t support multiple simultaneous sounds or not but, as you've discovered, they don't. For that you need to use something else like MCI or DirectX. I'm guessing that you're using DirectX now, although I could be wrong.

The next thing that the documentation could do for you is show you how to read the data from an UnmanagedMemoryStream into a Byte array, or at least it will get you on the way. You should go to the documentation for the class and read about it and its members. Thanks to OOP, all .NET streams work the same way, so reading data from an UnamangedMemoryStream is the same as reading a FileStream, NetworkStream, MemoryStream or whatever. So, read what you can and do what you can for yourself first. If you can't work it out, post back and let us know what you've done and we can help, but you should always do what you can first.

Finally, with regards to ByVal and ByRef, you are quite right that ByVal passes a copy and ByRef passes a reference. The thing is, your parameter is an array, which is a reference type. That means that when passing ByVal you are passing a copy of a reference, not a copy of an array. You're thinking like a VB6 developer. In VB.NET, the ONLY reason to pass ByRef is to allow you to change the argument in the method.
 
Back
Top