[Solved] Adapting Structure to PB_X64

Windows specific forum
User avatar
Otrebor
Enthusiast
Enthusiast
Posts: 136
Joined: Mon Mar 17, 2014 1:42 pm
Location: SP, Brasil
Contact:

[Solved] Adapting Structure to PB_X64

Post by Otrebor »

Hi
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

Is there any solution for run with PB x64?
Thanks.
Last edited by Otrebor on Sun Jun 20, 2021 5:21 pm, edited 1 time in total.
fryquez
Enthusiast
Enthusiast
Posts: 192
Joined: Mon Dec 21, 2015 8:12 pm

Re: WaitForSingleObject_ X64

Post by fryquez »

Structures were the problem.

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
  guid3DAlgorithm.guid
EndStructure

Structure DSBPOSITIONNOTIFY Align #PB_Structure_AlignC
  dwOffset.l
  hEventNotify.i
EndStructure

Structure DIRECTSOUND
  RA_DirectSound.i
  Sound.i
  Notify.i
  secBuflen.l
  nChannels.l
EndStructure

Global hWndM, hEvent, ThreadID, SoundFinished
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
User avatar
Otrebor
Enthusiast
Enthusiast
Posts: 136
Joined: Mon Mar 17, 2014 1:42 pm
Location: SP, Brasil
Contact:

Re: [Solved] Adapting Structure to PB_X64

Post by Otrebor »

Thank you very much!! :)
Post Reply