The code below run normally with PB 5.73 x86, but not with x64.
Seems that the problem is related with the API WaitForSingleObject (just my guess).
Code: Select all
;/ /// Threadbased DirectSound Streaming Play by Inc.
;/ /// Main parts do base on a Directsound playback example by Tomijan
;/ /// For PB4
;/ /// Normally you should not use DirectX within threads, but here no problems do occur
;/ /// Please do report any bugs.
;/ /// In this state the code is just an example. Its quick'n dirty and so still using globals and no further commands
;/ /// like stop/pause/seek etc. are implemented - these will be supported in future releases.
#NUM_PLAY_NOTIFICATIONS = 2
#Duration = 1 ;in sec. - Keep in mind: Increasing the buffer size increases the audio data latency
;
#DSBCAPS_LOCSOFTWARE = $8
#DSBCAPS_CTRLFREQUENCY = $20
#DSBCAPS_CTRLVOLUME = $80
#DSBCAPS_CTRLPAN = $40
#DSBCAPS_CTRLPOSITIONNOTIFY = $00000100
#DSBCAPS_GETCURRENTPOSITION2 =$00010000
#DSBCAPS_GLOBALFOCUS = $00008000
;
#DSSCL_EXCLUSIVE = 3
#DSSCL_NORMAL = 1
#DSSCL_PRIORITY = 2
#DSSCL_WRITEPRIMARY = 4
#DD_OK = 0
#DS_OK = 0
;
#DSBPLAY_LOOPING = $1
#DSBLOCK_FROMWRITECURSOR = $1
#DSBLOCK_ENTIREBUFFER = $2
#TIME_CALLBACK_FUNCTION = 0
;Structure WAVEFORMATEX Extends WAVEFORMAT
; wBitsPerSample.w
; cbSize.w
;EndStructure
Structure DSBUFFERDESC
dwSize.l
dwFlags.l
dwBufferBytes.l
dwReserved.l
*lpwfxFormat
EndStructure
Structure DSBPOSITIONNOTIFY
dwOffset.l;
hEventNotify.l;
EndStructure
Structure DIRECTSOUND
RA_DirectSound.l
Sound.l
Notify.l
secBuflen.l
nChannels.l
EndStructure
Global hWndM, hEvent, ThreadID, SoundFinished.b
Global Dim Notifications.DSBPOSITIONNOTIFY(#NUM_PLAY_NOTIFICATIONS-1)
Global DX8Sound.DIRECTSOUND
Procedure Delete(*obj.IUnknown)
ProcedureReturn *obj\Release()
EndProcedure
Procedure PrepareDX8Sound (*pWfx.WAVEFORMATEX)
If OpenLibrary(0,"DSOUND.DLL")
Result.l = CallFunction(0,"DirectSoundCreate8",0,@*RA_DirectSound.IDIRECTSOUND8,0)
EndIf
If Result = #Null
Result = *RA_DirectSound\SetCooperativeLevel(hWndM,#DSSCL_NORMAL) ; hwnd is the WindowID
If Result.l <> #DD_OK
Delete(*RA_DirectSound)
Else
dsbd.DSBUFFERDESC
dsbd\dwSize = SizeOf(DSBUFFERDESC)
dsbd\dwFlags = #DSBCAPS_LOCSOFTWARE|#DSBCAPS_CTRLVOLUME|#DSBCAPS_CTRLPOSITIONNOTIFY|#DSBCAPS_GLOBALFOCUS | #DSBCAPS_GETCURRENTPOSITION2
dsbd\dwBufferBytes = *pWfx\nAvgBytesPerSec * #Duration
dsbd\lpwfxFormat = *pWfx
nBlockAlign = *pWfx\nBlockAlign;
nSamplesPerSec = *pWfx\nSamplesPerSec;
dwNotifySize = nSamplesPerSec * #Duration * nBlockAlign / #NUM_PLAY_NOTIFICATIONS;
dwNotifySize = dwNotifySize - (dwNotifySize % nBlockAlign)
hEvent = CreateEvent_(0,#True,0,0)
For i = 0 To #NUM_PLAY_NOTIFICATIONS-1
Notifications(i)\dwOffset = dwNotifySize*(i)
Notifications(i)\hEventNotify = hEvent
Next
Result.l = *RA_DirectSound\CreateSoundBuffer(@dsbd,@*pDSB.IDirectSoundBuffer,0)
If Result.l <> #DD_OK
Delete(*RA_DirectSound)
Fresult = #Null
Else
*DSB8.IDIRECTSOUNDBUFFER8 = 0
*pDSB\QueryInterface(?IID_DirectSoundBuffer8,@*DSB8)
*DSN8.IDirectSoundNotify = 0
*pDSB\QueryInterface(?IID_DirectSoundNotify8,@*DSN8)
Delete(*pDSB)
If *DSB8 = 0
Delete(*RA_DirectSound)
Else
NotifyRes = *DSN8\SetNotificationPositions(#NUM_PLAY_NOTIFICATIONS,@Notifications(0))
DX8Sound\secBuflen = #Duration * *pWfx\nAvgBytesPerSec
DX8Sound\Sound = *DSB8
DX8Sound\Notify = *DSN8
DX8Sound\RA_DirectSound = *RA_DirectSound
DX8Sound\nChannels = *pWfx\nChannels
Fresult = *DSB8
EndIf
EndIf
EndIf
Else
MessageRequester("Error","Please install DirectX v.8 or above",0)
End
EndIf
If IsLibrary(0)
CloseLibrary(0)
EndIf
ProcedureReturn Fresult
EndProcedure
Procedure TimerThread(dummy)
dwLength.l = DX8Sound\secBuflen/#NUM_PLAY_NOTIFICATIONS
dwLengthAll.l = DX8Sound\secBuflen
*Sound.IDIRECTSOUNDBUFFER8 = DX8Sound\Sound
L1 = 1
Repeat
wfso = WaitForSingleObject_(hEvent,#INFINITE)
wres = *Sound\Lock(0, dwLength, @Write1, @L1, @Write2, @L2, #DSBLOCK_FROMWRITECURSOR )
If wres = #DS_OK
L1 = ReadData(0, Write1, L1) ;/ /// If the result > 0 then there's still data to buffer and therefore to play
Debug "Buffer 1 refilled using "+Str(L1)+ "bytes"
If L2
L2 = ReadData(0, Write2, L2)
Debug "Buffer 2 refilled using "+Str(L2)+ "bytes"
Debug " "
EndIf
lres = *Sound\Unlock(Write1, L1, Write2, L2) ; L1/L2 here do inform how much data has been buffered
EndIf
ResetEvent_(hEvent)
Debug "Soundfile readpointer now at byte "+Str(Loc(0))
Until L1 = 0 ;/ /// No more bytes in Soundfile available and by this no more bytes to buffer and so playback stops.
Debug "... which should equal to "+Str(Lof(0))+" which is the actual soundfile size"
Debug " "
Debug "finished"
SoundFinished = #True
*Sound\stop() ;/ /// Do stop the Loop
KillThread(ThreadID)
EndProcedure
Procedure DXSound(File.s)
Protected pWfx.WAVEFORMATEX
cb = ReadFile(0, File)
If cb
FileSeek(0, 20) ;/ /// go to the WAVEFORMATEX headerpart of the Soundfile ...
ReadData(0, @pWfx, SizeOf(WAVEFORMATEX))
FileSeek(0, 44) ;/ /// ... and to the start of the soundata. --> http://de.wikipedia.org/wiki/WAV_(Format)
Result = PrepareDX8Sound(@pWfx)
If Result
*Sound.IDIRECTSOUNDBUFFER8 = DX8Sound\Sound
*Sound\SetCurrentPosition(0)
*Sound\Play(0,0,#DSBPLAY_LOOPING) ;/ /// Start the Loop
ThreadID = CreateThread(@TimerThread(),0) ;/ /// Creating our buffer refilling thread
EndIf
EndIf
EndProcedure
;- /// An example of usage
CompilerIf #PB_Compiler_Debugger = #False
MessageRequester("Info","Please run this example using the debugger and see its output while choosing a wave file")
End
CompilerEndIf
hWndM = OpenWindow(0,0,0,20,20,"Sound",#PB_Window_ScreenCentered)
File.s = OpenFileRequester("Choose a soundfile","","Wave files (*.wav)|*.wav",0)
DXSound(File) ;/ /// Load and Play
Repeat
event = WaitWindowEvent()
Delay(10)
Until SoundFinished = #True Or event = #PB_Event_CloseWindow
If IsThread(ThreadID) : KillThread(ThreadID) : EndIf
CloseWindow(0)
FreeMemory(-1)
End
DataSection
IID_DirectSoundBuffer8: ; DSOUND.h
Data.l $6825A449
Data.w $7524,$4D82
Data.b $92,$0F,$50,$E3,$6A,$B3,$AB,$1E
IID_DirectSoundNotify8:
Data.l $B0210783
Data.w $89CD, $11D0
Data.b $AF,$08,$00,$A0,$C9,$25,$CD,$16
EndDataSection
Thanks.