directsoundaudio.bmx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. SuperStrict
  2. Rem
  3. bbdoc: Audio/DirectSound audio
  4. about:
  5. The DirectSound audio module provides DirectSound drivers for use with the #audio module.
  6. End Rem
  7. Module BRL.DirectSoundAudio
  8. ModuleInfo "Version: 1.05"
  9. ModuleInfo "Author: Mark Sibly"
  10. ModuleInfo "License: zlib/libpng"
  11. ModuleInfo "Copyright: Blitz Research Ltd"
  12. ModuleInfo "Modserver: BRL"
  13. ModuleInfo "History: 1.05 Release"
  14. ModuleInfo "History: Added hardware caps checking"
  15. ModuleInfo "History: 1.04 Release"
  16. ModuleInfo "History: First batch of fixes!"
  17. ModuleInfo "History: 1.02 Release"
  18. ModuleInfo "History: Added volume,pan,rate states to channel"
  19. ModuleInfo "History: 1.01 Initial Release"
  20. ?win32
  21. Import BRL.Math
  22. Import BRL.Audio
  23. Import Pub.DirectX
  24. Private
  25. Const CLOG:Int=False
  26. Global _driver:TDirectSoundAudioDriver
  27. Type TBuf
  28. Field _succ:TBuf
  29. Field _buffer:Byte Ptr,_seq:Int,_paused:Int
  30. Method Playing:Int()
  31. If _paused Return False
  32. Local status:Int
  33. DSASS bmx_directsound_IDirectSoundBuffer_getstatus(_buffer, Varptr status)
  34. Return (status & DSBSTATUS_PLAYING)<>0
  35. End Method
  36. Method Active:Int()
  37. If _paused Return True
  38. Local status:Int
  39. DSASS bmx_directsound_IDirectSoundBuffer_getstatus(_buffer, Varptr status)
  40. Return (status & DSBSTATUS_PLAYING)<>0
  41. End Method
  42. End Type
  43. Function DSASS( n:Int,t$="DirectSound" )
  44. If n>=0 Return
  45. Throw t+" failed ("+(n & 65535)+")"
  46. End Function
  47. Public
  48. Type TDirectSoundSound Extends TSound
  49. Method Delete()
  50. If _seq=_driver._seq
  51. _driver.AddLonely _bufs
  52. EndIf
  53. End Method
  54. Method Play:TDirectSoundChannel( alloced_channel:TChannel=Null ) Override
  55. Local t:TDirectSoundChannel=Cue( alloced_channel )
  56. t.SetPaused False
  57. Return t
  58. End Method
  59. Method Cue:TDirectSoundChannel( alloced_channel:TChannel=Null ) Override
  60. Local t:TDirectSoundChannel=TDirectSoundChannel( alloced_channel )
  61. If t
  62. Assert t._static
  63. Else
  64. t=TDirectSoundChannel.Create( False )
  65. EndIf
  66. t.Cue Self
  67. Return t
  68. End Method
  69. Function Create:TDirectSoundSound( sample:TAudioSample,flags:Int )
  70. _driver.FlushLonely
  71. Select sample.format
  72. Case SF_MONO16BE
  73. sample=sample.Convert( SF_MONO16LE )
  74. Case SF_STEREO16BE
  75. sample=sample.Convert( SF_STEREO16LE )
  76. End Select
  77. GCSuspend
  78. Local length:Int=sample.length
  79. Local hertz:Int=sample.hertz
  80. Local format:Int=sample.format
  81. Local chans:Int=ChannelsPerSample[format]
  82. Local bps:Int=BytesPerSample[format]/chans
  83. Local size:Int=length*chans*bps
  84. Local buf:Byte Ptr
  85. DSASS bmx_directsound_IDirectSound_createsoundbuffer(_driver._dsound, Varptr buf, length, hertz, format, chans, bps, size, flags, _driver._mode), "CreateSoundBuffer"
  86. If CLOG WriteStdout "Created DirectSound buffer~n"
  87. Local ptr1:Byte Ptr,bytes1:Int,ptr2:Byte Ptr,bytes2:Int
  88. DSASS bmx_directsound_IDirectSoundBuffer_lock(buf, 0,size,Varptr ptr1,Varptr bytes1,Varptr ptr2,Varptr bytes2,0 ),"Lock SoundBuffer"
  89. MemCopy ptr1,sample.samples,Size_T(size)
  90. DSASS bmx_directsound_IDirectSoundBuffer_unlock(buf, ptr1,bytes1,ptr2,bytes2),"Unlock SoundBuffer"
  91. Local t:TDirectSoundSound=New TDirectSoundSound
  92. t._seq=_driver._seq
  93. t._buffer=buf
  94. t._hertz=hertz
  95. t._loop=flags & 1
  96. t._bufs=New TBuf
  97. t._bufs._buffer=buf
  98. GCResume
  99. Return t
  100. End Function
  101. Field _seq:Int,_buffer:Byte Ptr,_hertz:Int,_loop:Int,_bufs:TBuf
  102. End Type
  103. Type TDirectSoundChannel Extends TChannel
  104. Method Delete()
  105. If Not _buf Or _seq<>_buf._seq Return
  106. If _buf._paused Stop
  107. End Method
  108. Method Stop() Override
  109. If Not _buf Or _seq<>_buf._seq Return
  110. bmx_directsound_IDirectSoundBuffer_stop(_buf._buffer)
  111. '_buf._buffer.Stop
  112. _buf._paused=False
  113. _buf._seq:+1
  114. _buf=Null
  115. End Method
  116. Method SetPaused( paused:Int ) Override
  117. If Not _buf Or _seq<>_buf._seq Return
  118. If Not _buf.Active()
  119. _buf._seq:+1
  120. _buf=Null
  121. Return
  122. EndIf
  123. If paused
  124. bmx_directsound_IDirectSoundBuffer_stop(_buf._buffer)
  125. Else
  126. bmx_directsound_IDirectSoundBuffer_play(_buf._buffer, 0, 0, _playFlags)
  127. EndIf
  128. _buf._paused=paused
  129. End Method
  130. Method SetVolume( volume# ) Override
  131. volume=Min(Max(volume,0),1)^.1
  132. _volume=volume
  133. If Not _buf Or _seq<>_buf._seq Return
  134. bmx_directsound_IDirectSoundBuffer_setvolume(_buf._buffer, Int((1-volume)*-10000))
  135. End Method
  136. Method SetPan( pan# ) Override
  137. pan=Min(Max(pan,-1),1)
  138. pan=Sgn(pan) * (1-(1-Abs(pan))^.1)
  139. _pan=pan
  140. If Not _buf Or _seq<>_buf._seq Return
  141. bmx_directsound_IDirectSoundBuffer_setpan(_buf._buffer, Int(pan*10000))
  142. End Method
  143. Method SetDepth( depth# ) Override
  144. If Not _buf Or _seq<>_buf._seq Return
  145. End Method
  146. Method SetRate( rate# ) Override
  147. _rate=rate
  148. If Not _buf Or _seq<>_buf._seq Return
  149. bmx_directsound_IDirectSoundBuffer_setfrequency(_buf._buffer, Int(_hertz * rate))
  150. End Method
  151. Method Playing:Int() Override
  152. If Not _buf Or _seq<>_buf._seq Return False
  153. Return _buf.Playing()
  154. End Method
  155. Method Cue:Int( sound:TDirectSoundSound )
  156. Stop
  157. Local t:TBuf=sound._bufs
  158. While t
  159. If Not t.Active()
  160. t._seq:+1
  161. Exit
  162. EndIf
  163. t=t._succ
  164. Wend
  165. If Not t
  166. _driver.FlushLonely
  167. Local buf:Byte Ptr
  168. If bmx_directsound_IDirectSound_duplicatesoundbuffer(_driver._dsound, sound._buffer,Varptr buf)<0 Return False
  169. If CLOG WriteStdout "Duplicated DirectSound buffer~n"
  170. t=New TBuf
  171. t._buffer=buf
  172. t._succ=sound._bufs
  173. sound._bufs=t
  174. EndIf
  175. _sound=sound
  176. _buf=t
  177. _seq=_buf._seq
  178. _hertz=sound._hertz
  179. If sound._loop _playFlags=DSBPLAY_LOOPING Else _playFlags=0
  180. _buf._paused=True
  181. bmx_directsound_IDirectSoundBuffer_setcurrentposition(_buf._buffer, 0)
  182. bmx_directsound_IDirectSoundBuffer_setvolume(_buf._buffer, Int((1-_volume)*-10000))
  183. bmx_directsound_IDirectSoundBuffer_setpan(_buf._buffer, Int(_pan * 10000))
  184. bmx_directsound_IDirectSoundBuffer_setfrequency(_buf._buffer, Int(_hertz * _rate))
  185. Return True
  186. End Method
  187. Function Create:TDirectSoundChannel( static:Int )
  188. Local t:TDirectSoundChannel=New TDirectSoundChannel
  189. t._static=static
  190. Return t
  191. End Function
  192. Field _volume#=1,_pan#=0,_rate#=1,_static:Int
  193. Field _sound:TSound,_buf:TBuf,_seq:Int,_hertz:Int,_playFlags:Int
  194. End Type
  195. Type TDirectSoundAudioDriver Extends TAudioDriver
  196. Method Name$() Override
  197. Return _name
  198. End Method
  199. Method Startup:Int() Override
  200. If bmx_directsound_IDirectSound_create(Varptr _dsound)>=0
  201. If bmx_directsound_IDirectSound_setcooperativeLevel(_dsound, GetDesktopWindow(),DSSCL_PRIORITY )>=0
  202. Rem
  203. 'Never seen this succeed!
  204. 'Apparently a NOP on Win2K/XP/Vista, and
  205. 'probably best not to mess with it on Win98 anyway.
  206. Global primBuf:IDirectSoundBuffer
  207. Local desc:DSBUFFERDESC=New DSBUFFERDESC
  208. desc.dwSize=SizeOf(DSBUFFERDESC)
  209. desc.dwFlags=DSBCAPS_PRIMARYBUFFER
  210. If _dsound.CreateSoundBuffer( desc,primBuf,Null )>=0
  211. Local fmt:WAVEFORMATEX=New WAVEFORMATEX
  212. fmt.wFormatTag=1
  213. fmt.nChannels=2
  214. fmt.wBitsPerSample=16
  215. fmt.nSamplesPerSec=44100
  216. fmt.nBlockAlign=fmt.wBitsPerSample/8*fmt.nChannels
  217. fmt.nAvgBytesPerSec=fmt.nSamplesPerSec*fmt.nBlockAlign
  218. primBuf.SetFormat fmt
  219. primBuf.Release_
  220. EndIf
  221. End Rem
  222. _driver=Self
  223. Return True
  224. EndIf
  225. bmx_directsound_IDirectSound_release(_dsound)
  226. EndIf
  227. End Method
  228. Method Shutdown() Override
  229. _seq:+1
  230. _driver=Null
  231. _lonely=Null
  232. bmx_directsound_IDirectSound_release(_dsound)
  233. End Method
  234. Method CreateSound:TDirectSoundSound( sample:TAudioSample,flags:Int ) Override
  235. Return TDirectSoundSound.Create( sample,flags )
  236. End Method
  237. Method AllocChannel:TDirectSoundChannel() Override
  238. Return TDirectSoundChannel.Create( True )
  239. End Method
  240. Function Create:TDirectSoundAudioDriver( name$,Mode:Int )
  241. Local t:TDirectSoundAudioDriver=New TDirectSoundAudioDriver
  242. t._name=name
  243. t._mode=Mode
  244. Return t
  245. End Function
  246. Method AddLonely( bufs:TBuf )
  247. Local t:TBuf=bufs
  248. While t._succ
  249. t=t._succ
  250. Wend
  251. t._succ=_lonely
  252. _lonely=bufs
  253. End Method
  254. Method FlushLonely()
  255. Local t:TBuf=_lonely,p:TBuf
  256. While t
  257. If t.Active()
  258. p=t
  259. Else
  260. bmx_directsound_IDirectSoundBuffer_release(t._buffer)
  261. If CLOG WriteStdout "Released DirectSound buffer~n"
  262. If p p._succ=t._succ Else _lonely=t._succ
  263. EndIf
  264. t=t._succ
  265. Wend
  266. End Method
  267. Field _name$,_mode:Int,_dsound:Byte Ptr,_lonely:TBuf
  268. Global _seq:Int
  269. End Type
  270. If DirectSoundCreate TDirectSoundAudioDriver.Create "DirectSound",0
  271. ?