Page 1 of 1

Play sound buffer with DirectSound 8

Posted: Thu Dec 18, 2003 3:38 pm
by Danilo
Code updated For 5.20+

Code: Select all

;
; example of playing a sound buffer with DirectX 8
;   by Danilo in co-operation with www.MasterCreating.de
;
#DD_OK = 0
#DS_OK = 0

#DSBCAPS_LOCSOFTWARE   = $8
#DSBCAPS_CTRLFREQUENCY = $20
#DSBCAPS_CTRLVOLUME    = $80
#DSBCAPS_CTRLPAN       = $40

;     Structure WAVEFORMATEX
;      wFormatTag.w        ; Waveform-audio format type. A complete list of format tags can be found in the Mmreg.h header file. For one- Or two-channel PCM data, this value should be WAVE_FORMAT_PCM.
;      nChannels.w         ; Number of channels in the waveform-audio data. Monaural data uses one channel and stereo data uses two channels.
;      nSamplesPerSec.l    ; Sample rate, in samples per second (hertz). If wFormatTag is WAVE_FORMAT_PCM, then common values for nSamplesPerSec are 8.0 kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
;      nAvgBytesPerSec.l   ; Required average data-transfer rate, in bytes per second, for the format tag. If wFormatTag is WAVE_FORMAT_PCM, nAvgBytesPerSec should be equal to the product of nSamplesPerSec and nBlockAlign. For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.
;      nBlockAlign.w       ; Block alignment, in bytes. The block alignment is the minimum atomic unit of data for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM or WAVE_FORMAT_EXTENSIBLE, nBlockAlign must be equal to the product of nChannels and wBitsPerSample divided by 8 (bits per byte). For non-PCM formats, this member must be computed according to the manufacturer's specification of the format tag.  :Software must process a multiple of nBlockAlign bytes of Data at a time. Data written To And Read from a device must always start at the beginning of a block. For example, it is illegal To start playback of PCM Data in the middle of a sample (that is, on a non-block-aligned boundary).
;      wBitsPerSample.w    ; Bits per sample for the wFormatTag format type. If wFormatTag is WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16. For non-PCM formats, this member must be set according to the manufacturer's specification of the format tag. If wFormatTag is WAVE_FORMAT_EXTENSIBLE, this value can be any integer multiple of 8. Some compression schemes cannot define a value for wBitsPerSample, so this member can be zero.
;      cbSize.w            ; Size, in bytes, of extra format information appended to the end of the WAVEFORMATEX structure. This information can be used by non-PCM formats to store extra attributes for the wFormatTag. If no extra information is required by the wFormatTag, this member must be set to zero. For WAVE_FORMAT_PCM formats (and only WAVE_FORMAT_PCM formats), this member is ignored.
;     EndStructure

Structure DSBUFFERDESC
  dwSize.l            ; Size of the Structure
  dwFlags.l           ; Flags specifying the capabilities of the buffer
  dwBufferBytes.l     ; Size of the new buffer, in bytes. This value must be 0 when creating a buffer with the DSBCAPS_PRIMARYBUFFER flag. For secondary buffers, the minimum and maximum sizes allowed are specified by DSBSIZE_MIN and DSBSIZE_MAX, defined in Dsound.h.
  dwReserved.l        ; Must be 0
  *lpwfxFormat        ; Address of a WAVEFORMATEX or WAVEFORMATEXTENSIBLE structure specifying the waveform format for the buffer.
  guid3DAlgorithm.GUID; Unique identifier of the two-speaker virtualization algorithm to be used by DirectSound3D hardware emulation. If DSBCAPS_CTRL3D is not set in dwFlags, this member must be GUID_NULL (DS3DALG_DEFAULT).
EndStructure


Procedure Delete(*obj.IUnknown)
  ProcedureReturn *Obj\Release()
EndProcedure

Procedure Error_Msg(String.s)
  MessageRequester("Error",String.s,0)
  End
EndProcedure

hwnd = OpenWindow(0,0,0,200,200,"Sound",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CreateGadgetList(hwnd)
TextGadget    (1,10,10,180,15,"Frequency: 44100")
TrackBarGadget(2,10,25,180,20,0,441)
SetGadgetState(2,441)
TextGadget    (3,10,50,180,15,"Pan: 0")
TrackBarGadget(4,10,65,180,20,0,200)
SetGadgetState(4,100)
TextGadget    (5,10,90,180,15,"Volume: 10000")
TrackBarGadget(6,10,105,180,20,0,10000)
SetGadgetState(6,10000)


If OpenLibrary(0,"DSOUND.DLL") = 0
  Error_Msg("Can't open direct Sound")
EndIf

*RA_DirectSound.IDirectSound8

; create DS8 Sound Object
Result.l = CallFunction(0,"DirectSoundCreate8",0,@*RA_DirectSound,0)
If Result.l <> #DD_OK
  Error_Msg("Can't do DirectSoundCreate8 : " + Str(Result.l))
EndIf

; Set Coop Level
Result.l = *RA_DirectSound\SetCooperativeLevel(hwnd,1)
If Result.l <> #DD_OK
  Error_Msg("Can't Set Coop Level : " + Str(Result.l))
EndIf


; Setting up Primary Buffer
dsbd.DSBUFFERDESC                          ; Set up structure
dsbd\dwSize        = SizeOf(DSBUFFERDESC)  ; Save structure size
dsbd\dwFlags       = 1                     ; It is the primary Buffer (see DSound.h)
dsbd\dwBufferBytes = 0                     ; NULL ? Because primary Buffer must be Null
dsbd\lpwfxFormat   = 0                     ; NULL ? ? ? <- ist ein Pointer

Result.l = *RA_DirectSound\CreateSoundBuffer(@dsbd,@*pDSBPrimary.IDirectSoundBuffer,0)
If Result.l <> #DD_OK
  Error_Msg("Can't Set up primary sound buffer : " + Str(Result))
EndIf

#channels = 2

wfx.WAVEFORMATEX                ; Wave Format Structure
RtlZeroMemory_(@wfx,SizeOf(WAVEFORMATEX));
wfx\wFormatTag      = #WAVE_FORMAT_PCM;
wfx\nChannels       = #channels ;dwPrimaryChannels;
wfx\nSamplesPerSec  = 44100     ;dwPrimaryFreq;
wfx\wBitsPerSample  = 16        ;dwPrimaryBitRate;
wfx\nBlockAlign     = (wfx\wBitsPerSample / 8 * wfx\nChannels)
wfx\nAvgBytesPerSec = (wfx\nSamplesPerSec * wfx\nBlockAlign)

; secondary Buffer (see DSound.h)
dsbd\dwFlags       = #DSBCAPS_LOCSOFTWARE|#DSBCAPS_CTRLVOLUME|#DSBCAPS_CTRLFREQUENCY|#DSBCAPS_CTRLPAN
dsbd\dwBufferBytes = 10 * wfx\nAvgBytesPerSec ; alloc 10 Seconds
dsbd\lpwfxFormat   = @wfx

; CREATE Secondary Buffer
Result.l = *RA_DirectSound\CreateSoundBuffer(@dsbd,@*pDSB.IDirectSoundBuffer,0)
If Result.l <> #DD_OK
  Error_Msg("Can't Set up secondary sound buffer : " + Str(Result))
EndIf

; ASK for DirectSoundBuffer8 Interface
*DSB8.IDirectSoundBuffer8 = 0
*pDSB\QueryInterface(?IID_DirectSoundBuffer8,@*DSB8)
Delete(*pDSB)

If *DSB8 = 0
  Error_Msg("Can't get DirectSoundBuffer8 Interface")
EndIf

#DSBLOCK_ENTIREBUFFER = $2
If *DSB8\Lock(0,0,@lpvWrite,@dwLength,0,0,#DSBLOCK_ENTIREBUFFER) = #DS_OK
  
  ; OK, now copy data in buffer...
  
  Structure SOUND_BUFFER ; channels, each 16 bit
    channel.w[#channels]
  EndStructure
  
  *Buffer.SOUND_BUFFER = lpvWrite
  
  
  ; GENERATE SOUND DATA ;)
  For a = 0 To dwLength/SizeOf(SOUND_BUFFER)
    If b < $FFFF And flag = 0
      b + 1000
      c + 5000
    Else
      flag = 1
      b - 50
      c - 700
      If b <= 0: b=0: flag = 0: EndIf
    EndIf
    *Buffer\channel[0] = b
    *Buffer\channel[1] = c
    *Buffer + SizeOf(SOUND_BUFFER)
  Next a
  ; GENERATE SOUND END
  
  
  *DSB8\UnLock(lpvWrite,dwLength,0,0)
  #DSBPLAY_LOOPING = $1
  *DSB8\Play(0,0,#DSBPLAY_LOOPING) ; PLAYYYYY!!!
EndIf

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Quit = 1
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 2 ; Frequency Control
          Frequ = GetGadgetState(2)
          SetGadgetText(1,"Frequency: "+Str(Frequ*100))
          *DSB8\SetFrequency(Frequ*100)
        Case 4 ; Pan: Left <> Right
          Pan = GetGadgetState(4)*100-10000
          SetGadgetText(3,"Pan: "+Str(Pan))
          *DSB8\SetPan(Pan)
        Case 6 ; Volume
          Vol = GetGadgetState(6)
          SetGadgetText(5,"Volume: "+Str(Vol))
          *DSB8\SetVolume(Vol-10000)
      EndSelect
  EndSelect
Until Quit

*DSB8\Stop()

; Release/Delete Objects
; (reversed order of creation)
Delete(*DSB8)
Delete(*pDSBPrimary)
Delete(*RA_DirectSound)

End

DataSection
  IID_DirectSoundBuffer8:  ; DSOUND.h
  Data.l $6825A449
  Data.w $7524,$4D82
  Data.b $92,$0F,$50,$E3,$6A,$B3,$AB,$1E
EndDataSection

Posted: Thu Dec 18, 2003 3:47 pm
by freak
The IDirectSoundBuffer8 definition was corrected for 3.81 allready, so it is ok now.

Timo

Posted: Thu Dec 18, 2003 4:21 pm
by Danilo
changed

Posted: Thu Dec 18, 2003 8:07 pm
by Hi-Toro
Fantastic! Thanks, Danilo -- I've been after some code to start off with for ages!