DirectX:DirectSound:Tutorials:VB:DX7:Loading Sound Buffers from Custom Resource Files

From GPWiki

Files:GUITutorial_warn.gif The Game Programming Wiki has moved! Files:GUITutorial_warn.gif

The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server.

However, the GPWiki forums are still active! Come say hello.

I hope there're no vegetarians among us today because I'm going to get straight to the meat!

DirectSoundBuffer.WriteBuffer(start As Long, size As Long, buffer As Any, flags As CONST_DSBLOCKFLAGS)

I wonder if anyone has ever bothered to look at this method of the DirectSoundBuffer object before. I know I certainly hadn't paid it any attention prior to now! But what a thing of beauty she is. All you do is indicate where to write within the buffer (start, usually at the beginning: zero), how much stuff you want to write (size) and what you want to write in that space (buffer). The buffer must be an array of bytes, but you pass only the first element of that array. There's also a flags variable to pass, which can be either DSBLOCK_FROMWRITECURSOR (which writes from the current position of the buffer's playback and ignores the start variable), or DSBLOCK_ENTIREBUFFER (which writes to the entire buffer and ignores the size variable).

As great as WriteBuffer is, we're still not in the clear. We need some method of extracting the byte data from a wave file in order to pass it as our buffer variable, AND we also must find a way to fill a WAVEFORMATEX structure so that we can initialize the buffer correctly when we create it manually. How? Ryan's (not) patented wave file extractor!

'Wave file format info
Private Type WAVETYPE
    strHead As String * 12
    strFormatID As String * 4
    lngChunkSize As Long
    intFormat As Integer
    intChannels As Integer
    lngSamplesPerSec As Long
    lngAvgBytesPerSec As Long
    intBlockAlign As Integer
    intBitsPerSample As Integer
End Type
Global gudtHeader As WAVETYPE
Global glngChunkSize As Long
Global gbytData() As Byte
 
Sub ExtractWaveData(strFileName As String, lngOffset As Long)
 
Dim intWAVFile As Integer
Dim i As Long
Dim strTemp As String * 4
Dim blnFound As Boolean
 
    'Open the wave
    intWAVFile = FreeFile()
    Open strFileName For Binary Access Read Lock Write As intWAVFile
        'Get the header info
        Get intWAVFile, lngOffset, gudtHeader
        'Find the "data" portion of the file
        For i = lngOffset To LOF(intWAVFile)
            Get intWAVFile, i, strTemp
            If strTemp = "data" Then
                blnFound = True
                Exit For
            End If
        Next i
        'Ensure this is a wave file
        If blnFound = False Then
            MsgBox "Invalid wave data.", vbCritical, "Invalid Wave"
            Close intWAVFile
            Exit Sub
        End If
        'Get the data information
        Get intWAVFile, , glngChunkSize
        ReDim gbytData(glngChunkSize)
        Get intWAVFile, , gbytData
    Close intWAVFile
    
End Sub

This gives us everything we need! We now have the wave data buffer (gbytData) and know its size (glngChunkSize). Also, gudtHeader contains the essential info we need for filling a WAVEFORMATEX structure and initializing a buffer from scratch! Observe:

Public Sub LoadSound(objBuffer As DirectSoundBuffer)
 
Dim udtBufferDesc As DSBUFFERDESC
Dim udtFormat As WAVEFORMATEX
   
    'Set the Wave Format
    With udtFormat
        .nFormatTag = gudtHeader.intFormat
        .nChannels = gudtHeader.intChannels
        .lSamplesPerSec = gudtHeader.lngSamplesPerSec
        .nBitsPerSample = gudtHeader.intBitsPerSample
        .nBlockAlign = gudtHeader.intBlockAlign
        .lAvgBytesPerSec = gudtHeader.lngAvgBytesPerSec
    End With
    
    'Create the buffer
    udtBufferDesc.lBufferBytes = glngChunkSize
    Set objBuffer = mobjDS.CreateSoundBuffer(udtBufferDesc, udtFormat)
    
    'Load the buffer with data
    objBuffer.WriteBuffer 0, glngChunkSize, gbytData(0), DSBLOCK_ENTIREBUFFER
    
End Sub

After extracting the wave data from a file we can run this LoadSound routine to create a buffer and load it properly. I realize this tutorial is quite advanced and hope this sample source code may serve to clarify somewhat.