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

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998, 1999, 2000 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_dart.c,v 1.2 2004/01/31 22:39:40 raph Exp $
  21.   Driver for output on OS/2 MMPM/2 using direct audio (DART)
  22. ==============================================================================*/
  23. /*
  24. Written by Miodrag Vallat <miod@mikmod.org>
  25. Lots of improvements (basically made usable...) by Andrew Zabolotny
  26.                                                    <bit@eltech.ru>
  27. */
  28. #ifdef HAVE_CONFIG_H
  29. #include "config.h"
  30. #endif
  31. #include "mikmod_internals.h"
  32. #ifdef DRV_DART
  33. #define INCL_DOS
  34. #define INCL_OS2MM
  35. #include <os2.h>
  36. /* Prevent a warning: PPFN redefined */
  37. #define PPFN _PPFN
  38. #include <os2me.h>
  39. #undef PPFN
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #define MAX_BUFFERCOUNT 8
  43. static MCI_MIX_BUFFER MixBuffers[MAX_BUFFERCOUNT];
  44. static MCI_MIXSETUP_PARMS MixSetupParms;
  45. static MCI_BUFFER_PARMS BufferParms;
  46. static ULONG DeviceIndex = 0; /* use default waveaudio device */
  47. static ULONG BufferSize = (ULONG)-1; /* autodetect buffer size */
  48. static ULONG BufferCount = 2; /* use two buffers */
  49. static ULONG DeviceID = 0;
  50. static void Dart_CommandLine(CHAR *cmdline)
  51. {
  52. char *ptr;
  53. int buf;
  54. if ((ptr = MD_GetAtom("buffer", cmdline, 0))) {
  55. buf = atoi(ptr);
  56. if (buf >= 12 && buf <= 16)
  57. BufferSize = 1 << buf;
  58. free(ptr);
  59. }
  60. if ((ptr = MD_GetAtom("count", cmdline, 0))) {
  61. buf = atoi(ptr);
  62. if (buf >= 2 && buf <= MAX_BUFFERCOUNT)
  63. BufferCount = buf;
  64. free(ptr);
  65. }
  66. if ((ptr = MD_GetAtom("device", cmdline, 0))) {
  67. buf = atoi(ptr);
  68. if (buf >= 0 && buf <= 8)
  69. DeviceIndex = buf;
  70. free(ptr);
  71. }
  72. }
  73. /* Buffer update thread (created and called by DART)
  74.    This is a high-priority thread used to compute and update the audio stream,
  75.    automatically created by the DART subsystem. We compute the next audio
  76.    buffer and feed it to the waveaudio device. */
  77. static LONG APIENTRY Dart_UpdateBuffers(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
  78. {
  79. /* sanity check */
  80. if (!pBuffer)
  81. return TRUE;
  82. /* if we have finished a buffer, we're ready to play a new one */
  83. if ((ulFlags == MIX_WRITE_COMPLETE) ||
  84. ((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR)) &&
  85.  (ulStatus == ERROR_DEVICE_UNDERRUN))) {
  86. /* refill this audio buffer and feed it again */
  87. MUTEX_LOCK(vars);
  88. if (Player_Paused_internal())
  89. pBuffer->ulBufferLength =
  90. VC_SilenceBytes(pBuffer->pBuffer, BufferSize);
  91. else
  92. pBuffer->ulBufferLength =
  93. VC_WriteBytes(pBuffer->pBuffer, BufferSize);
  94. MUTEX_UNLOCK(vars);
  95. MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, pBuffer, 1);
  96. }
  97. return TRUE;
  98. }
  99. static BOOL Dart_IsPresent(void)
  100. {
  101. MCI_AMP_OPEN_PARMS AmpOpenParms;
  102. MCI_GENERIC_PARMS GenericParms;
  103. memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
  104. AmpOpenParms.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX,
  105. (USHORT) DeviceIndex);
  106. if (mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID,
  107.    (PVOID) &AmpOpenParms, 0) != MCIERR_SUCCESS)
  108. return 0;
  109. mciSendCommand(AmpOpenParms.usDeviceID, MCI_CLOSE, MCI_WAIT,
  110.    (PVOID) &GenericParms, 0);
  111. return 1;
  112. }
  113. static BOOL Dart_Init(void)
  114. {
  115. MCI_AMP_OPEN_PARMS AmpOpenParms;
  116. MCI_GENERIC_PARMS GenericParms;
  117. MixBuffers[0].pBuffer = NULL; /* marker */
  118. DeviceID = 0;
  119. memset(&GenericParms, 0, sizeof(MCI_GENERIC_PARMS));
  120. /* open AMP device */
  121. memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
  122. AmpOpenParms.usDeviceID = 0;
  123. AmpOpenParms.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX,
  124. (USHORT) DeviceIndex);
  125. if (mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_SHAREABLE | MCI_OPEN_TYPE_ID,
  126.    (PVOID) & AmpOpenParms, 0) != MCIERR_SUCCESS) {
  127. _mm_errno = MMERR_OPENING_AUDIO;
  128. return 1;
  129. }
  130. DeviceID = AmpOpenParms.usDeviceID;
  131. /* setup playback parameters */
  132. memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS));
  133. MixSetupParms.ulBitsPerSample = (md_mode & DMODE_16BITS) ? 16 : 8;
  134. MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
  135. MixSetupParms.ulSamplesPerSec = md_mixfreq;
  136. MixSetupParms.ulChannels = (md_mode & DMODE_STEREO) ? 2 : 1;
  137. MixSetupParms.ulFormatMode = MCI_PLAY;
  138. MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
  139. MixSetupParms.pmixEvent = Dart_UpdateBuffers;
  140. if (mciSendCommand(DeviceID, MCI_MIXSETUP,
  141.    MCI_WAIT | MCI_MIXSETUP_INIT,
  142.    (PVOID) & MixSetupParms, 0) != MCIERR_SUCCESS) {
  143. _mm_errno = MMERR_OS2_MIXSETUP;
  144. return 1;
  145. }
  146. /* Compute audio buffer size now if necessary */
  147. if (BufferSize == (ULONG)-1) {
  148. /* DART suggested buffer size is somewhat too big. We compute a size
  149.    for circa 1/4" of playback. */
  150. int bit;
  151. BufferSize = md_mixfreq >> 2;
  152. if (md_mode & DMODE_STEREO)
  153. BufferSize <<= 1;
  154. if (md_mode & DMODE_16BITS)
  155. BufferSize <<= 1;
  156. for (bit = 15; bit >= 12; bit--)
  157. if (BufferSize & (1 << bit))
  158. break;
  159. BufferSize = (1 << bit);
  160. }
  161. /* make sure buffer is not greater than 64 Kb, as DART can't handle this
  162.    situation. */
  163. if (BufferSize > 65536)
  164. BufferSize = 65536;
  165. BufferParms.ulStructLength = sizeof(BufferParms);
  166. BufferParms.ulNumBuffers = BufferCount;
  167. BufferParms.ulBufferSize = BufferSize;
  168. BufferParms.pBufList = MixBuffers;
  169. if (mciSendCommand(DeviceID, MCI_BUFFER,
  170.    MCI_WAIT | MCI_ALLOCATE_MEMORY,
  171.    (PVOID) &BufferParms, 0) != MCIERR_SUCCESS) {
  172. _mm_errno = MMERR_OUT_OF_MEMORY;
  173. return 1;
  174. }
  175. return VC_Init();
  176. }
  177. static void Dart_Exit(void)
  178. {
  179. MCI_GENERIC_PARMS GenericParms;
  180. VC_Exit();
  181. if (MixBuffers[0].pBuffer) {
  182. mciSendCommand(DeviceID, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY,
  183.    &BufferParms, 0);
  184. MixBuffers[0].pBuffer = NULL;
  185. }
  186. if (DeviceID) {
  187. mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID) &GenericParms, 0);
  188. DeviceID = 0;
  189. }
  190. }
  191. static BOOL Dart_PlayStart(void)
  192. {
  193. MCI_GENERIC_PARMS GenericParms;
  194. int i;
  195. if (VC_PlayStart())
  196. return 1;
  197. /* silence buffers */
  198. for (i = 0; i < BufferCount; i++) {
  199. VC_SilenceBytes(MixBuffers[i].pBuffer, BufferSize);
  200. MixBuffers[i].ulBufferLength = BufferSize;
  201. }
  202. /* grab exclusive rights to device instance (not entire device) */
  203. GenericParms.hwndCallback = 0;  /* Not needed, so set to 0 */
  204. if (mciSendCommand(DeviceID, MCI_ACQUIREDEVICE, MCI_EXCLUSIVE_INSTANCE,
  205.                    (PVOID) &GenericParms, 0) != MCIERR_SUCCESS) {
  206. mciSendCommand(DeviceID, MCI_CLOSE, MCI_WAIT, (PVOID) &GenericParms, 0);
  207. _mm_errno = MMERR_OPENING_AUDIO;
  208. return 1;
  209. }
  210. /* wake DART up */
  211. MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, MixBuffers, BufferCount);
  212. return 0;
  213. }
  214. static void Dart_Update(void)
  215. {
  216. /* Nothing to do: everything is done in DART_UpdateBuffers() */
  217. }
  218. static void Dart_PlayStop(void)
  219. {
  220. MCI_GENERIC_PARMS GenericParms;
  221. GenericParms.hwndCallback = 0;
  222. mciSendCommand(DeviceID, MCI_STOP, MCI_WAIT, (PVOID) &GenericParms, 0);
  223. VC_PlayStop();
  224. }
  225. MIKMODAPI MDRIVER drv_dart = {
  226. NULL,
  227. "Direct audio (DART)",
  228. "OS/2 DART driver v1.2",
  229. 0, 255,
  230. "dart",
  231. "device:r:0,8,0:Waveaudio device index to use (0 - default)n"
  232.         "buffer:r:12,16:Audio buffer log2 sizen"
  233.         "count:r:2,8,2:Number of audio buffersn",
  234. Dart_CommandLine,
  235. Dart_IsPresent,
  236. VC_SampleLoad,
  237. VC_SampleUnload,
  238. VC_SampleSpace,
  239. VC_SampleLength,
  240. Dart_Init,
  241. Dart_Exit,
  242. NULL,
  243. VC_SetNumVoices,
  244. Dart_PlayStart,
  245. Dart_PlayStop,
  246. Dart_Update,
  247. NULL,
  248. VC_VoiceSetVolume,
  249. VC_VoiceGetVolume,
  250. VC_VoiceSetFrequency,
  251. VC_VoiceGetFrequency,
  252. VC_VoiceSetPanning,
  253. VC_VoiceGetPanning,
  254. VC_VoicePlay,
  255. VC_VoiceStop,
  256. VC_VoiceStopped,
  257. VC_VoiceGetPosition,
  258. VC_VoiceRealVolume
  259. };
  260. #else
  261. MISSING(drv_dart);
  262. #endif
  263. /* ex:set ts=4: */