drv_ds.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:9k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998-2001 Miodrag Vallat and others - see file AUTHORS for
  3. complete list.
  4. This library is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17. 02111-1307, USA.
  18. */
  19. /*==============================================================================
  20.   $Id: drv_ds.c,v 1.3 2004/01/31 22:39:40 raph Exp $
  21.   Driver for output on win32 platforms using DirectSound
  22. ==============================================================================*/
  23. /*
  24. Written by Brian McKinney <Brian.McKinney@colorado.edu>
  25. */
  26. #ifdef HAVE_CONFIG_H
  27. #include "config.h"
  28. #endif
  29. #include "mikmod_internals.h"
  30. #ifdef DRV_DS
  31. #include <memory.h>
  32. #include <string.h>
  33. #define INITGUID
  34. #include <dsound.h>
  35. /* DSBCAPS_CTRLALL is not defined anymore with DirectX 7. Of course DirectSound
  36.    is a coherent, backwards compatible API... */
  37. #ifndef DSBCAPS_CTRLALL
  38. #define DSBCAPS_CTRLALL ( DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLVOLUME | 
  39.   DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | 
  40.   DSBCAPS_CTRL3D )
  41. #endif
  42. /* size of each buffer */
  43. #define FRAGSIZE 16
  44. /* buffer count */
  45. #define UPDATES  2
  46. static LPDIRECTSOUND pSoundCard = NULL;
  47. static LPDIRECTSOUNDBUFFER pPrimarySoundBuffer = NULL, pSoundBuffer = NULL;
  48. static LPDIRECTSOUNDNOTIFY pSoundBufferNotify = NULL;
  49. static HANDLE notifyUpdateHandle = 0, updateBufferHandle = 0;
  50. static BOOL threadInUse = FALSE;
  51. static int fragsize=1<<FRAGSIZE;
  52. static DWORD controlflags = DSBCAPS_CTRLALL & ~DSBCAPS_GLOBALFOCUS;
  53. #define SAFE_RELEASE(p) 
  54. do { 
  55. if (p) { 
  56. if ((p)->lpVtbl) { 
  57. (p)->lpVtbl->Release(p); 
  58. (p) = NULL;
  59. } while (0)
  60. static DWORD WINAPI updateBufferProc(LPVOID lpParameter)
  61. {
  62. LPVOID pBlock1 = NULL, pBlock2 = NULL;
  63. DWORD soundBufferCurrentPosition, blockBytes1, blockBytes2;
  64. DWORD start;
  65. while (threadInUse) {
  66. if (WaitForSingleObject(notifyUpdateHandle,INFINITE)==WAIT_OBJECT_0) {
  67. if (!threadInUse) break;
  68. pSoundBuffer->lpVtbl->GetCurrentPosition
  69. (pSoundBuffer,&soundBufferCurrentPosition,NULL);
  70. if (soundBufferCurrentPosition < fragsize)
  71. start = fragsize;
  72. else
  73. start = 0;
  74. if (pSoundBuffer->lpVtbl->Lock
  75. (pSoundBuffer,start,fragsize,&pBlock1,&blockBytes1,
  76.  &pBlock2,&blockBytes2,0)==DSERR_BUFFERLOST) {
  77. pSoundBuffer->lpVtbl->Restore(pSoundBuffer);
  78. pSoundBuffer->lpVtbl->Lock
  79. (pSoundBuffer,start,fragsize,&pBlock1,&blockBytes1,
  80.  &pBlock2,&blockBytes2,0);
  81. }
  82. MUTEX_LOCK(vars);
  83. if (Player_Paused_internal()) {
  84. VC_SilenceBytes((SBYTE*)pBlock1,(ULONG)blockBytes1);
  85. if (pBlock2)
  86. VC_SilenceBytes((SBYTE*)pBlock2,(ULONG)blockBytes2);
  87. } else {
  88. VC_WriteBytes((SBYTE*)pBlock1,(ULONG)blockBytes1);
  89. if (pBlock2)
  90. VC_WriteBytes((SBYTE*)pBlock2,(ULONG)blockBytes2);
  91. }
  92. MUTEX_UNLOCK(vars);
  93. pSoundBuffer->lpVtbl->Unlock
  94. (pSoundBuffer,pBlock1,blockBytes1,pBlock2,blockBytes2);
  95. }
  96. }
  97. return 0;
  98. }
  99. static void DS_CommandLine(CHAR *cmdline)
  100. {
  101. CHAR *ptr=MD_GetAtom("buffer",cmdline,0);
  102. if (ptr) {
  103. int buf=atoi(ptr);
  104. if ((buf<12)||(buf>19)) buf=FRAGSIZE;
  105. fragsize=1<<buf;
  106. free(ptr);
  107. }
  108. if ((ptr=MD_GetAtom("globalfocus",cmdline,1))) {
  109. controlflags |= DSBCAPS_GLOBALFOCUS;
  110. free(ptr);
  111. } else
  112. controlflags &= ~DSBCAPS_GLOBALFOCUS;
  113. }
  114. static BOOL DS_IsPresent(void)
  115. {
  116. if(DirectSoundCreate(NULL,&pSoundCard,NULL)!=DS_OK)
  117. return 0;
  118. SAFE_RELEASE(pSoundCard);
  119. return 1;
  120. }
  121. static BOOL DS_Init(void)
  122. {
  123. DSBUFFERDESC soundBufferFormat;
  124. WAVEFORMATEX pcmwf;
  125. DSBPOSITIONNOTIFY positionNotifications[2];
  126. DWORD updateBufferThreadID;
  127. if (DirectSoundCreate(NULL,&pSoundCard,NULL)!=DS_OK) {
  128. _mm_errno=MMERR_OPENING_AUDIO;
  129. return 1;
  130. }
  131. if (pSoundCard->lpVtbl->SetCooperativeLevel
  132. (pSoundCard,GetForegroundWindow(),DSSCL_PRIORITY)!=DS_OK) {
  133. _mm_errno=MMERR_DS_PRIORITY;
  134. return 1;
  135. }
  136. memset(&soundBufferFormat,0,sizeof(DSBUFFERDESC));
  137.     soundBufferFormat.dwSize       =sizeof(DSBUFFERDESC);
  138.     soundBufferFormat.dwFlags      =DSBCAPS_PRIMARYBUFFER;
  139.     soundBufferFormat.dwBufferBytes=0;
  140.     soundBufferFormat.lpwfxFormat  =NULL;
  141. if (pSoundCard->lpVtbl->CreateSoundBuffer
  142. (pSoundCard,&soundBufferFormat,&pPrimarySoundBuffer,NULL)!=DS_OK) {
  143. _mm_errno=MMERR_DS_BUFFER;
  144. return 1;
  145. }
  146. memset(&pcmwf,0,sizeof(WAVEFORMATEX));
  147. pcmwf.wFormatTag     =WAVE_FORMAT_PCM;
  148. pcmwf.nChannels      =(md_mode&DMODE_STEREO)?2:1;
  149. pcmwf.nSamplesPerSec =md_mixfreq;
  150. pcmwf.wBitsPerSample =(md_mode&DMODE_16BITS)?16:8;
  151. pcmwf.nBlockAlign    =(pcmwf.wBitsPerSample * pcmwf.nChannels) / 8;
  152. pcmwf.nAvgBytesPerSec=pcmwf.nSamplesPerSec*pcmwf.nBlockAlign;
  153.     if (pPrimarySoundBuffer->lpVtbl->SetFormat
  154. (pPrimarySoundBuffer,&pcmwf)!=DS_OK) {
  155. _mm_errno=MMERR_DS_FORMAT;
  156. return 1;
  157. }
  158.     pPrimarySoundBuffer->lpVtbl->Play(pPrimarySoundBuffer,0,0,DSBPLAY_LOOPING);
  159. memset(&soundBufferFormat,0,sizeof(DSBUFFERDESC));
  160.     soundBufferFormat.dwSize       =sizeof(DSBUFFERDESC);
  161.     soundBufferFormat.dwFlags      =controlflags|DSBCAPS_GETCURRENTPOSITION2 ;
  162.     soundBufferFormat.dwBufferBytes=fragsize*UPDATES;
  163.     soundBufferFormat.lpwfxFormat  =&pcmwf;
  164. if (pSoundCard->lpVtbl->CreateSoundBuffer
  165. (pSoundCard,&soundBufferFormat,&pSoundBuffer,NULL)!=DS_OK) {
  166. _mm_errno=MMERR_DS_BUFFER;
  167. return 1;
  168. }
  169. pSoundBuffer->lpVtbl->QueryInterface
  170. (pSoundBuffer,&IID_IDirectSoundNotify,(LPVOID*)&pSoundBufferNotify);
  171. if (!pSoundBufferNotify) {
  172. _mm_errno=MMERR_DS_NOTIFY;
  173. return 1;
  174. }
  175. notifyUpdateHandle=CreateEvent
  176. (NULL,FALSE,FALSE,"libmikmod DirectSound Driver positionNotify Event");
  177. if (!notifyUpdateHandle) {
  178. _mm_errno=MMERR_DS_EVENT;
  179. return 1;
  180. }
  181. updateBufferHandle=CreateThread
  182. (NULL,0,updateBufferProc,NULL,CREATE_SUSPENDED,&updateBufferThreadID);
  183. if (!updateBufferHandle) {
  184. _mm_errno=MMERR_DS_THREAD;
  185. return 1;
  186. }
  187. memset(positionNotifications,0,2*sizeof(DSBPOSITIONNOTIFY));
  188. positionNotifications[0].dwOffset    =0;
  189. positionNotifications[0].hEventNotify=notifyUpdateHandle;
  190. positionNotifications[1].dwOffset    =fragsize;
  191. positionNotifications[1].hEventNotify=notifyUpdateHandle;
  192. if (pSoundBufferNotify->lpVtbl->SetNotificationPositions
  193. (pSoundBufferNotify,2,positionNotifications) != DS_OK) {
  194. _mm_errno=MMERR_DS_UPDATE;
  195. return 1;
  196. }
  197. return VC_Init();
  198. }
  199. static void DS_Exit(void)
  200. {
  201. DWORD statusInfo;
  202. if(updateBufferHandle) {
  203. /* Signal thread to exit and wait for the exit */
  204. if (threadInUse) {
  205. threadInUse = 0;
  206. MUTEX_UNLOCK(vars);
  207. SetEvent (notifyUpdateHandle);
  208. WaitForSingleObject (updateBufferHandle, INFINITE);
  209. MUTEX_LOCK(vars);
  210. }
  211. CloseHandle(updateBufferHandle),
  212. updateBufferHandle = 0;
  213. }
  214. if (notifyUpdateHandle) {
  215. CloseHandle(notifyUpdateHandle),
  216. notifyUpdateHandle = 0;
  217. }
  218. SAFE_RELEASE(pSoundBufferNotify);
  219. if(pSoundBuffer) {
  220. if(pSoundBuffer->lpVtbl->GetStatus(pSoundBuffer,&statusInfo)==DS_OK)
  221. if(statusInfo&DSBSTATUS_PLAYING)
  222. pSoundBuffer->lpVtbl->Stop(pSoundBuffer);
  223. SAFE_RELEASE(pSoundBuffer);
  224. }
  225. if(pPrimarySoundBuffer) {
  226. if(pPrimarySoundBuffer->lpVtbl->GetStatus
  227. (pPrimarySoundBuffer,&statusInfo)==DS_OK)
  228. if(statusInfo&DSBSTATUS_PLAYING)
  229. pPrimarySoundBuffer->lpVtbl->Stop(pPrimarySoundBuffer);
  230. SAFE_RELEASE(pPrimarySoundBuffer);
  231. }
  232. SAFE_RELEASE(pSoundCard);
  233. VC_Exit();
  234. }
  235. static BOOL do_update = 0;
  236. static void DS_Update(void)
  237. {
  238. LPVOID block;
  239. DWORD bBytes;
  240. /* Do first update in DS_Update() to be consistent with other
  241.    non threaded drivers. */
  242. if (do_update && pSoundBuffer) {
  243. do_update = 0;
  244. if (pSoundBuffer->lpVtbl->Lock (pSoundBuffer, 0, fragsize,
  245. &block, &bBytes, NULL, NULL, 0)
  246. == DSERR_BUFFERLOST) {
  247. pSoundBuffer->lpVtbl->Restore (pSoundBuffer);
  248. pSoundBuffer->lpVtbl->Lock (pSoundBuffer, 0, fragsize,
  249. &block, &bBytes, NULL, NULL, 0);
  250. }
  251. if (Player_Paused_internal()) {
  252. VC_SilenceBytes ((SBYTE *)block, (ULONG)bBytes);
  253. } else {
  254. VC_WriteBytes ((SBYTE *)block, (ULONG)bBytes);
  255. }
  256. pSoundBuffer->lpVtbl->Unlock (pSoundBuffer, block, bBytes, NULL, 0);
  257. pSoundBuffer->lpVtbl->SetCurrentPosition(pSoundBuffer, 0);
  258. pSoundBuffer->lpVtbl->Play(pSoundBuffer, 0, 0, DSBPLAY_LOOPING);
  259. threadInUse=1;
  260. ResumeThread (updateBufferHandle);
  261. }
  262. }
  263. static void DS_PlayStop(void)
  264. {
  265. do_update = 0;
  266. if (pSoundBuffer)
  267. pSoundBuffer->lpVtbl->Stop(pSoundBuffer);
  268. VC_PlayStop();
  269. }
  270. static BOOL DS_PlayStart(void)
  271. {
  272. do_update = 1;
  273. return VC_PlayStart();
  274. }
  275. MIKMODAPI MDRIVER drv_ds=
  276. {
  277. NULL,
  278. "DirectSound",
  279. "DirectSound Driver (DX6+) v0.4",
  280. 0,255,
  281. "ds",
  282. "buffer:r:12,19,16:Audio buffer log2 sizen"
  283.         "globalfocus:b:0:Play if window does not have the focusn",
  284. DS_CommandLine,
  285. DS_IsPresent,
  286. VC_SampleLoad,
  287. VC_SampleUnload,
  288. VC_SampleSpace,
  289. VC_SampleLength,
  290. DS_Init,
  291. DS_Exit,
  292. NULL,
  293. VC_SetNumVoices,
  294. DS_PlayStart,
  295. DS_PlayStop,
  296. DS_Update,
  297. NULL,
  298. VC_VoiceSetVolume,
  299. VC_VoiceGetVolume,
  300. VC_VoiceSetFrequency,
  301. VC_VoiceGetFrequency,
  302. VC_VoiceSetPanning,
  303. VC_VoiceGetPanning,
  304. VC_VoicePlay,
  305. VC_VoiceStop,
  306. VC_VoiceStopped,
  307. VC_VoiceGetPosition,
  308. VC_VoiceRealVolume
  309. };
  310. #else
  311. MISSING(drv_ds);
  312. #endif
  313. /* ex:set ts=4: */