DirectSound Capture Question
Posted: Wed Sep 29, 2010 12:59 pm
Below is a simple program which records two seconds of sound from the default sound device using DirectX. On lines 45 - 46, the program works fine if wFormatTag = #WAVE_FORMAT_PCM, but I get an error if I set wFormatTag = $FFFE which is the same as #WAVE_FORMAT_EXTENSIBLE. I am trying to capture more than 2 audio channels with this and as I understand it, it is necessary for wFormatTag to equal $FFFE.
Code: Select all
;DIRECTSOUND RECORD PROGRAM
;chris319
;5/25/2008
;UPDATED ON 9/29/2010
;THIS PROGRAM RECORDS 2 SECONDS OF AUDIO
;FROM THE DEFAULT RECORDING DEVICE, THEN SAVES THE
;AUDIO AS A WAV FILE NAMED "test.wav". YOU CAN FOOL
;AROUND WITH CHANNELS, SAMPLE RATE AND BIT DEPTH HERE:
OpenConsole()
#CHANNELS = 2
#SAMPLE_RATE = 44100
#BIT_DEPTH = 16
#SECONDS = 2
#WAVE_FORMAT_PCM = $0001
#WAVE_FORMAT_EXTENSIBLE = $FFFE
#SPEAKER_FRONT_LEFT = 1
#SPEAKER_FRONT_RIGHT = 2
#SPEAKER_FRONT_CENTER = 4
#SPEAKER_BACK_LEFT = $10
#SPEAKER_BACK_RIGHT = $20
KSDATAFORMAT_SUBTYPE_PCM$ = Chr($1)+Chr($0)+Chr($10)+Chr($80)+Chr($0)+Chr($0)+Chr($aa)+Chr($0)+Chr($38)+Chr($9b)+Chr($71)
#DS_OK = 0
#LOOP_FLAG = 0
#DSCBLOCK_ENTIREBUFFER = 1
Structure WAVEFORMATEXTENSIBLE
format.WAVEFORMATEX ; Capturing WaveFormatEx
wValidBitsPerSample.w
dwChannelMask.l
SubFormat$; .w ;GUID
EndStructure
Global my_wfe.WAVEFORMATEXTENSIBLE ;THE FAMILIAR WAVEFORMATEX STRUCTURE
Global *bufptr ;POINTER TO CAPTURE BUFFER
Global bufsize.l ;SIZE OF CAPTURE BUFFER
my_wfe\format\wFormatTag = #WAVE_FORMAT_PCM
;my_wfe\Format\wFormatTag = $FFFE ;#WAVE_FORMAT_EXTENSIBLE;
my_wfe\Format\nChannels = 2
my_wfe\Format\nSamplesPerSec = 44100
my_wfe\Format\nAvgBytesPerSec = 352800 / 2
;my_wfe\Format\nBlockAlign = 8 ; /* Same as the usual */
;my_wfe\format\nAvgBytesPerSec = (my_wfe\format\nSamplesPerSec * my_wfe\format\nBlockAlign)
my_wfe\Format\wBitsPerSample = 16
my_wfe\Format\cbSize = 22; /* After this to GUID */
my_wfe\wValidBitsPerSample = 16; /* All bits have data */
my_wfe\dwChannelMask = #SPEAKER_FRONT_LEFT | #SPEAKER_FRONT_RIGHT | #SPEAKER_BACK_LEFT | #SPEAKER_BACK_RIGHT
;// Quadraphonic = 0x00000033
my_wfe\SubFormat$ = KSDATAFORMAT_SUBTYPE_PCM$ ;Specify PCM
my_wfe\format\nBlockAlign = (my_wfe\format\wBitsPerSample / 8 * my_wfe\format\nChannels)
my_wfe\format\nAvgBytesPerSec = (my_wfe\format\nSamplesPerSec * my_wfe\format\nBlockAlign)
;DIRECTSOUND BUFFER
Structure DSCBUFFERDESC
dwSize.l ; Size of the structure, in bytes. This member must be initialized before the structure is used.
dwFlags.l ; Flags specifying the capabilities of the buffer
dwBufferBytes.l ; Size of capture buffer to create, in bytes.
dwReserved.l ; Must be 0
*lpwfxFormat ; Address of a WAVEFORMATEX or WAVEFORMATEXTENSIBLE structure specifying the waveform format for the buffer.
EndStructure
Procedure Delete(*obj.IUnknown)
ProcedureReturn *Obj\Release()
EndProcedure
Procedure Error_Msg(String.s)
MessageRequester("Error",String.s,0)
End
EndProcedure
Procedure File_Save()
;SAVE BUFFER AS A WAV FILE
If CreateFile(1, "audio\test.wav") = 0
MessageRequester("Error", "Unable to create file.", #MB_ICONERROR)
End
ProcedureReturn
EndIf
subchunk1size.l = SizeOf(WAVEFORMATEX)
subchunk2size.l = bufsize
chunksize = 4 + (8 + SizeOf(WAVEFORMATEX)) + (8 + subchunk2size)
samprate.l = my_wfe\format\nSamplesPerSec
byterate.l = my_wfe\format\nSamplesPerSec * my_wfe\format\nAvgBytesPerSec ;IS THIS RIGHT?
blockalign.w = my_wfe\format\nChannels * (my_wfe\format\wBitsPerSample / 8)
bitspersample.w = my_wfe\format\wBitsPerSample
my_wfe\format\cbSize = 0
chunksize = chunksize + my_wfe\format\cbSize
my_wfe\format\wFormatTag = #WAVE_FORMAT_PCM
;WRITE WAV HEADER
WriteString(1, "RIFF") ; 4 bytes
WriteLong(1, chunksize) ; 4 bytes
WriteString(1, "WAVE") ; 4 bytes
WriteString(1, "fmt ") ; 4 bytes
WriteLong(1, subchunk1size) ; 4 bytes
WriteData(1, my_WFE, SizeOf(WAVEFORMATEX))
;END OF WAVEFORMATEX STRUCTURE
WriteString(1, "data", #PB_Ascii) ; 4 bytes
WriteLong(1, subchunk2size) ; 4 bytes
;END OF FILE HEADER
;WRITE AUDIO DATA AFTER WAV HEADER
WriteData(1, *bufptr, bufsize)
CloseFile(1)
EndProcedure
Procedure Enumerate()
result.l = DirectSoundCaptureEnumerate_(0, 0)
EndProcedure
;CREATE DIRECTSOUND CAPTURE OBJECT
*DirectSound.IDirectSoundCapture
result.l = DirectSoundCaptureCreate_(0, @*DirectSound, 0)
If Result <> #DS_OK
Error_Msg("Can't do DirectSoundCaptureCreate : " + Str(Result.l))
EndIf
;SET UP CAPTURE BUFFER
dscbd.DSCBUFFERDESC ; Set up structure
dscbd\dwSize = SizeOf(DSCBUFFERDESC) ; Save structure size
dscbd\dwFlags = 0 ; It is the primary Buffer (see DSound.h)
dscbd\dwBufferBytes = my_wfe\format\nAvgBytesPerSec * #SECONDS
dscbd\dwReserved = 0
;dscbd\lpwfxFormat = @my_WFE
dscbd\lpwfxFormat = @my_WFE\format
result = *DirectSound\CreateCaptureBuffer(@dscbd, @*pDSCB.IDirectSoundCaptureBuffer, 0)
If result <> #DS_OK
Error_Msg("Can't set up directsound buffer : " + Str(Result))
EndIf
;START RECORDING
result = *pDSCB.IDirectSoundCaptureBuffer\Start(#LOOP_FLAG)
If result <> #DS_OK
Error_Msg("Can't start : " + Str(Result))
Else
PrintN("Recording started")
EndIf
;RECORD FOR SPECIFIED NUMBER OF SECONDS
Delay(#SECONDS * 1000)
;STOP RECORDING
result = *pDSCB.IDirectSoundCaptureBuffer\Stop()
If result <> #DS_OK
Error_Msg("Can't stop : " + Str(Result))
Else
PrintN("Recording stopped")
EndIf
;LOCK THE BUFFER BEFORE SAVING
result = *pDSCB.IDirectSoundCaptureBuffer\Lock(0, my_wfe\format\nAvgBytesPerSec * #SECONDS, @*bufptr, @bufsize, 0, 0, #DSCBLOCK_ENTIREBUFFER)
If result <> #DS_OK
Error_Msg("Can't lock : " + Str(Result))
EndIf
;SAVE BUFFER CONTENTS AS A WAV FILE
PrintN("Saving")
File_Save()
;UNLOCK THE BUFFER
result = *pDSCB.IDirectSoundCaptureBuffer\Unlock(*bufptr, bufsize, 0, 0)
If result <> #DS_OK
Error_Msg("Can't unlock : " + Str(Result))
EndIf
;PrintN("Normal program termination")
CloseConsole()
End