Microsoft DirectX 8.1 (Visual Basic)

Writing to a Wave File

Short sounds can be saved from a secondary buffer to a wave file by using DirectSoundSecondaryBuffer8.SaveToFile. This method copies the entire contents of the buffer to a file.

In most cases, the sound that you want to save starts out in a capture buffer. The following code shows how to move data from a capture buffer, dscb, to a secondary buffer and then to a file.

Dim ds As DirectSound8
Dim dscb As DirectSoundCaptureBuffer8 
Dim dscd As DSCBUFFERDESC
Dim dsd As DSBUFFERDESC
Dim capCurs As DSCURSORS
Dim numBytes As Long
Dim ByteBuffer() As Integer 
.
.
.
' Assume that ds has been created, dscb has been created and
' contains data, and dscd holds the format of the capture buffer.
 
' Create a secondary buffer with the same format, and large enough
' to contain all data so far written to the capture buffer.
 
dscb.GetCurrentPosition capCurs
numBytes = capCurs.lWrite + 1
dsd.lBufferBytes = numBytes
dsd.fxFormat = dscd.fxFormat
Set dsb = ds.CreateSoundBuffer(dsd)
 
' Make a private buffer large enough to hold the same data.
 
ReDim ByteBuffer(numBytes)
 
' Read the contents of the capture buffer into the private buffer.
 
dscb.ReadBuffer 0, numBytes, ByteBuffer(0), DSCBLOCK_DEFAULT
 
' Write the private buffer to the secondary buffer.
 
dsb.WriteBuffer 0, numBytes, ByteBuffer(0), DSBLOCK_DEFAULT
 
' Save the wave.
 
dsb.SaveToFile "captured.wav"

For sounds that might exceed the length of the capture buffer, you need to create the wave file yourself and stream data into it. Streaming captured data to a wave file is done in the following steps:

  1. Create the file and write the file header, the format chunk, and the header of the data chunk. The format chunk must describe the format of the capture buffer. Note, however, that the elements of the format are not in the same order as in the WAVEFORMATEX type. For information on the organization of headers and chunks, see Reading Wave Files.
  2. Stream data from a capture buffer to a private buffer and from there to the file, keeping track of how many bytes have been written. For more information, see Using the Capture Buffer.
  3. When capture stops and all data has been written, calculate the length of the data chunk and the total size of the file, and write these values to the appropriate locations in the data chunk header and file header respectively.

The following code creates a file and writes the RIFF header information:

Private Type FileHeader
  lRiff As Long
  lFileSize As Long
  lWave As Long
  lFormat As Long
  lFormatLength As Long
End Type
 
Private Type WaveFormat
  wFormatTag As Integer
  nChannels As Integer
  nSamplesPerSec As Long
  nAvgBytesPerSec As Long
  nBlockAlign As Integer
  wBitsPerSample As Integer
'  cbSize As Integer
End Type
 
Private Type ChunkHeader
  lType As Long
  lLen As Long
End Type
 
Dim fh As FileHeader
Dim wf As WaveFormat
Dim ch As ChunkHeader

Private Sub OpenFile(WaveFileName As String)

  Open WaveFileName For Binary Access Write As #1
  
  With fh
  .lRiff = &H46464952  ' <RIFF> chunk tag
  .lFileSize = 0   ' Will get later
  .lWave = &H45564157  ' <WAVE> chunk tag
  .lFormat = &H20746D66  ' <fmt > chunk tag
  .lFormatLength = Len(wf)
  End With
  
  Put #1, , fh
  
  With wf
  .wFormatTag = dscbDesc.fxFormat.nFormatTag
  .nChannels = dscbDesc.fxFormat.nChannels
  .nSamplesPerSec = dscbDesc.fxFormat.lSamplesPerSec
  .wBitsPerSample = dscbDesc.fxFormat.nBitsPerSample
  .nBlockAlign = dscbDesc.fxFormat.nBlockAlign
  .nAvgBytesPerSec = dscbDesc.fxFormat.lAvgBytesPerSec
  End With
  
  Put #1, , wf
  
  ch.lType = &H61746164  ' <data> chunk tag
  
  Put #1, , ch
  
End Sub

Captured data can now be appended to the file. Assuming that the number of data bytes written to the file is kept in a Long called BytesWritten, the file is closed by using the following procedure:

Private Sub CloseFile()
 
  Dim fsize As Long
  
  ' Write file size.
 
  fsize = Len(fh) + Len(wf) + Len(ch) + BytesWritten
  Put #1, 5, fsize
  
  ' Rewrite data chunk header with size.
  
  ch.lLen = BytesWritten
  Put #1, Len(fh) + Len(wf) + 1, ch
  
  Close #1
 
End Sub