SDL_os2audio.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #if SDL_AUDIO_DRIVER_OS2
  20. /* Allow access to a raw mixing buffer */
  21. #include "../../core/os2/SDL_os2.h"
  22. #include "SDL_audio.h"
  23. #include "../SDL_audio_c.h"
  24. #include "SDL_os2audio.h"
  25. static PMCI_MIX_BUFFER _getNextBuffer(SDL_PrivateAudioData *pAData, PMCI_MIX_BUFFER pBuffer)
  26. {
  27. PMCI_MIX_BUFFER pFirstBuffer = &pAData->aMixBuffers[0];
  28. PMCI_MIX_BUFFER pLastBuffer = &pAData->aMixBuffers[pAData->cMixBuffers -1];
  29. return (pBuffer == pLastBuffer ? pFirstBuffer : pBuffer+1);
  30. }
  31. static ULONG _getEnvULong(const char *name, ULONG ulMax, ULONG ulDefault)
  32. {
  33. ULONG ulValue;
  34. char* end;
  35. char* envval = SDL_getenv(name);
  36. if (envval == NULL)
  37. return ulDefault;
  38. ulValue = SDL_strtoul(envval, &end, 10);
  39. return (end == envval) || (ulValue > ulMax)? ulDefault : ulMax;
  40. }
  41. static int _MCIError(const char *func, ULONG ulResult)
  42. {
  43. CHAR acBuf[128];
  44. mciGetErrorString(ulResult, acBuf, sizeof(acBuf));
  45. return SDL_SetError("[%s] %s", func, acBuf);
  46. }
  47. static void _mixIOError(const char *function, ULONG ulRC)
  48. {
  49. debug_os2("%s() - failed, rc = 0x%lX (%s)",
  50. function, ulRC,
  51. (ulRC == MCIERR_INVALID_MODE) ? "Mixer mode does not match request" :
  52. (ulRC == MCIERR_INVALID_BUFFER) ? "Caller sent an invalid buffer" : "unknown");
  53. }
  54. static LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
  55. ULONG ulFlags)
  56. {
  57. SDL_AudioDevice *_this = (SDL_AudioDevice *)pBuffer->ulUserParm;
  58. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  59. ULONG ulRC;
  60. debug_os2("cbAudioWriteEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags);
  61. if (pAData->ulState == 2)
  62. {
  63. return 0;
  64. }
  65. if (ulFlags != MIX_WRITE_COMPLETE) {
  66. debug_os2("flags = 0x%lX", ulFlags);
  67. return 0;
  68. }
  69. pAData->pDrainBuffer = pBuffer;
  70. ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
  71. pAData->pDrainBuffer, 1);
  72. if (ulRC != MCIERR_SUCCESS) {
  73. _mixIOError("pmixWrite", ulRC);
  74. return 0;
  75. }
  76. ulRC = DosPostEventSem(pAData->hevBuf);
  77. if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
  78. debug_os2("DosPostEventSem(), rc = %lu", ulRC);
  79. }
  80. return 1; /* return value doesn't seem to matter. */
  81. }
  82. static LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer,
  83. ULONG ulFlags)
  84. {
  85. SDL_AudioDevice *_this = (SDL_AudioDevice *)pBuffer->ulUserParm;
  86. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  87. ULONG ulRC;
  88. debug_os2("cbAudioReadEvent: ulStatus = %lu, pBuffer = %p, ulFlags = %#lX",ulStatus,pBuffer,ulFlags);
  89. if (pAData->ulState == 2)
  90. {
  91. return 0;
  92. }
  93. if (ulFlags != MIX_READ_COMPLETE) {
  94. debug_os2("flags = 0x%lX", ulFlags);
  95. return 0;
  96. }
  97. pAData->pFillBuffer = pBuffer;
  98. if (pAData->pFillBuffer == pAData->aMixBuffers)
  99. {
  100. ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle,
  101. pAData->pFillBuffer, pAData->cMixBuffers);
  102. if (ulRC != MCIERR_SUCCESS) {
  103. _mixIOError("pmixRead", ulRC);
  104. return 0;
  105. }
  106. }
  107. ulRC = DosPostEventSem(pAData->hevBuf);
  108. if (ulRC != NO_ERROR && ulRC != ERROR_ALREADY_POSTED) {
  109. debug_os2("DosPostEventSem(), rc = %lu", ulRC);
  110. }
  111. return 1;
  112. }
  113. static void OS2_DetectDevices(void)
  114. {
  115. MCI_SYSINFO_PARMS stMCISysInfo;
  116. CHAR acBuf[256];
  117. ULONG ulDevicesNum;
  118. MCI_SYSINFO_LOGDEVICE stLogDevice;
  119. MCI_SYSINFO_PARMS stSysInfoParams;
  120. ULONG ulRC;
  121. ULONG ulNumber;
  122. MCI_GETDEVCAPS_PARMS stDevCapsParams;
  123. MCI_OPEN_PARMS stMCIOpen;
  124. MCI_GENERIC_PARMS stMCIGenericParams;
  125. SDL_memset(&stMCISysInfo, 0, sizeof(stMCISysInfo));
  126. acBuf[0] = '\0';
  127. stMCISysInfo.pszReturn = acBuf;
  128. stMCISysInfo.ulRetSize = sizeof(acBuf);
  129. stMCISysInfo.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
  130. ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_QUANTITY,
  131. &stMCISysInfo, 0);
  132. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  133. debug_os2("MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%hX", LOUSHORT(ulRC));
  134. return;
  135. }
  136. ulDevicesNum = SDL_strtoul(stMCISysInfo.pszReturn, NULL, 10);
  137. for (ulNumber = 1; ulNumber <= ulDevicesNum;
  138. ulNumber++) {
  139. /* Get device install name. */
  140. stSysInfoParams.ulNumber = ulNumber;
  141. stSysInfoParams.pszReturn = acBuf;
  142. stSysInfoParams.ulRetSize = sizeof(acBuf);
  143. stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX;
  144. ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME,
  145. &stSysInfoParams, 0);
  146. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  147. debug_os2("MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%hX", LOUSHORT(ulRC));
  148. continue;
  149. }
  150. /* Get textual product description. */
  151. stSysInfoParams.ulItem = MCI_SYSINFO_QUERY_DRIVER;
  152. stSysInfoParams.pSysInfoParm = &stLogDevice;
  153. SDL_strlcpy(stLogDevice.szInstallName, stSysInfoParams.pszReturn, MAX_DEVICE_NAME);
  154. ulRC = mciSendCommand(0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM,
  155. &stSysInfoParams, 0);
  156. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  157. debug_os2("MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC));
  158. continue;
  159. }
  160. SDL_AddAudioDevice(0, stLogDevice.szProductInfo, NULL, (void *)ulNumber);
  161. /* Open audio device for querying its capabilities */
  162. /* at this point we HAVE TO OPEN the waveaudio device and not the ampmix device */
  163. /* because only the waveaudio device (tied to the ampmix device) supports querying for playback/record capability */
  164. SDL_memset(&stMCIOpen, 0, sizeof(stMCIOpen));
  165. stMCIOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO,LOUSHORT(ulNumber));
  166. ulRC = mciSendCommand(0, MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,&stMCIOpen, 0);
  167. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  168. debug_os2("MCI_OPEN (getDevCaps) - failed");
  169. continue;
  170. }
  171. /* check for recording capability */
  172. SDL_memset(&stDevCapsParams, 0, sizeof(stDevCapsParams));
  173. stDevCapsParams.ulItem = MCI_GETDEVCAPS_CAN_RECORD;
  174. ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_GETDEVCAPS, MCI_WAIT | MCI_GETDEVCAPS_ITEM,
  175. &stDevCapsParams, 0);
  176. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  177. debug_os2("MCI_GETDEVCAPS, MCI_GETDEVCAPS_ITEM - failed, rc = 0x%hX", LOUSHORT(ulRC));
  178. }
  179. else {
  180. if (stDevCapsParams.ulReturn) {
  181. SDL_AddAudioDevice(1, stLogDevice.szProductInfo, NULL, (void *)(ulNumber | 0x80000000));
  182. }
  183. }
  184. /* close the audio device, we are done querying its capabilities */
  185. SDL_memset(&stMCIGenericParams, 0, sizeof(stMCIGenericParams));
  186. ulRC = mciSendCommand(stMCIOpen.usDeviceID, MCI_CLOSE, MCI_WAIT,
  187. &stMCIGenericParams, 0);
  188. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  189. debug_os2("MCI_CLOSE (getDevCaps) - failed");
  190. }
  191. }
  192. }
  193. static void OS2_WaitDevice(_THIS)
  194. {
  195. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  196. ULONG ulRC;
  197. debug_os2("Enter");
  198. /* Wait for an audio chunk to finish */
  199. ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
  200. if (ulRC != NO_ERROR) {
  201. debug_os2("DosWaitEventSem(), rc = %lu", ulRC);
  202. }
  203. }
  204. static Uint8 *OS2_GetDeviceBuf(_THIS)
  205. {
  206. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  207. debug_os2("Enter");
  208. return (Uint8 *) pAData->pFillBuffer->pBuffer;
  209. }
  210. static void OS2_PlayDevice(_THIS)
  211. {
  212. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  213. ULONG ulRC;
  214. PMCI_MIX_BUFFER pMixBuffer = NULL;
  215. debug_os2("Enter");
  216. pMixBuffer = pAData->pDrainBuffer;
  217. pAData->pFillBuffer = _getNextBuffer(pAData, pAData->pFillBuffer);
  218. if (!pAData->ulState && pAData->pFillBuffer != pMixBuffer)
  219. {
  220. /*
  221. * this buffer was filled but we have not yet filled all buffers
  222. * so just signal event sem so that OS2_WaitDevice does not need
  223. * to block
  224. */
  225. ulRC = DosPostEventSem(pAData->hevBuf);
  226. }
  227. if (!pAData->ulState && (pAData->pFillBuffer == pMixBuffer) )
  228. {
  229. debug_os2("!hasStarted");
  230. pAData->ulState = 1;
  231. /* Write buffers to kick off the amp mixer */
  232. ulRC = pAData->stMCIMixSetup.pmixWrite(pAData->stMCIMixSetup.ulMixHandle,
  233. pMixBuffer, pAData->cMixBuffers);
  234. if (ulRC != MCIERR_SUCCESS) {
  235. _mixIOError("pmixWrite", ulRC);
  236. }
  237. }
  238. }
  239. static int OS2_CaptureFromDevice(_THIS,void *buffer,int buflen)
  240. {
  241. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  242. ULONG ulRC;
  243. PMCI_MIX_BUFFER pMixBuffer = NULL;
  244. int len = 0;
  245. if (!pAData->ulState)
  246. {
  247. pAData->ulState = 1;
  248. ulRC = pAData->stMCIMixSetup.pmixRead(pAData->stMCIMixSetup.ulMixHandle,
  249. pAData->aMixBuffers, pAData->cMixBuffers);
  250. if (ulRC != MCIERR_SUCCESS) {
  251. _mixIOError("pmixRead", ulRC);
  252. return -1;
  253. }
  254. }
  255. /* Wait for an audio chunk to finish */
  256. ulRC = DosWaitEventSem(pAData->hevBuf, 5000);
  257. if (ulRC != NO_ERROR)
  258. {
  259. debug_os2("DosWaitEventSem(), rc = %lu", ulRC);
  260. return -1;
  261. }
  262. pMixBuffer = pAData->pDrainBuffer;
  263. len = SDL_min((int)pMixBuffer->ulBufferLength, buflen);
  264. SDL_memcpy(buffer,pMixBuffer->pBuffer, len);
  265. pAData->pDrainBuffer = _getNextBuffer(pAData, pMixBuffer);
  266. debug_os2("buflen = %u, ulBufferLength = %lu",buflen,pMixBuffer->ulBufferLength);
  267. return len;
  268. }
  269. static void OS2_FlushCapture(_THIS)
  270. {
  271. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  272. ULONG ulIdx;
  273. debug_os2("Enter");
  274. /* Fill all device buffers with data */
  275. for (ulIdx = 0; ulIdx < pAData->cMixBuffers; ulIdx++) {
  276. pAData->aMixBuffers[ulIdx].ulFlags = 0;
  277. pAData->aMixBuffers[ulIdx].ulBufferLength = _this->spec.size;
  278. pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)_this;
  279. SDL_memset(((PMCI_MIX_BUFFER)pAData->aMixBuffers)[ulIdx].pBuffer,
  280. _this->spec.silence, _this->spec.size);
  281. }
  282. pAData->pFillBuffer = pAData->aMixBuffers;
  283. pAData->pDrainBuffer = pAData->aMixBuffers;
  284. }
  285. static void OS2_CloseDevice(_THIS)
  286. {
  287. SDL_PrivateAudioData *pAData = (SDL_PrivateAudioData *)_this->hidden;
  288. MCI_GENERIC_PARMS sMCIGenericParms;
  289. ULONG ulRC;
  290. debug_os2("Enter");
  291. if (pAData == NULL)
  292. return;
  293. pAData->ulState = 2;
  294. /* Close up audio */
  295. if (pAData->usDeviceId != (USHORT)~0) { /* Device is open. */
  296. SDL_zero(sMCIGenericParms);
  297. ulRC = mciSendCommand(pAData->usDeviceId, MCI_STOP,
  298. MCI_WAIT,
  299. &sMCIGenericParms, 0);
  300. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  301. debug_os2("MCI_STOP - failed" );
  302. }
  303. if (pAData->stMCIMixSetup.ulBitsPerSample != 0) { /* Mixer was initialized. */
  304. ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
  305. MCI_WAIT | MCI_MIXSETUP_DEINIT,
  306. &pAData->stMCIMixSetup, 0);
  307. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  308. debug_os2("MCI_MIXSETUP, MCI_MIXSETUP_DEINIT - failed");
  309. }
  310. }
  311. if (pAData->cMixBuffers != 0) { /* Buffers was allocated. */
  312. MCI_BUFFER_PARMS stMCIBuffer;
  313. stMCIBuffer.ulBufferSize = pAData->aMixBuffers[0].ulBufferLength;
  314. stMCIBuffer.ulNumBuffers = pAData->cMixBuffers;
  315. stMCIBuffer.pBufList = pAData->aMixBuffers;
  316. ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
  317. MCI_WAIT | MCI_DEALLOCATE_MEMORY, &stMCIBuffer, 0);
  318. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  319. debug_os2("MCI_BUFFER, MCI_DEALLOCATE_MEMORY - failed");
  320. }
  321. }
  322. ulRC = mciSendCommand(pAData->usDeviceId, MCI_CLOSE, MCI_WAIT,
  323. &sMCIGenericParms, 0);
  324. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  325. debug_os2("MCI_CLOSE - failed");
  326. }
  327. }
  328. if (pAData->hevBuf != NULLHANDLE)
  329. DosCloseEventSem(pAData->hevBuf);
  330. SDL_free(pAData);
  331. }
  332. static int OS2_OpenDevice(_THIS, const char *devname)
  333. {
  334. SDL_PrivateAudioData *pAData;
  335. SDL_AudioFormat test_format;
  336. MCI_AMP_OPEN_PARMS stMCIAmpOpen;
  337. MCI_BUFFER_PARMS stMCIBuffer;
  338. ULONG ulRC;
  339. ULONG ulIdx;
  340. BOOL new_freq;
  341. SDL_bool iscapture = _this->iscapture;
  342. ULONG ulHandle = (ULONG)_this->handle;
  343. new_freq = FALSE;
  344. SDL_zero(stMCIAmpOpen);
  345. SDL_zero(stMCIBuffer);
  346. for (test_format = SDL_FirstAudioFormat(_this->spec.format); test_format; test_format = SDL_NextAudioFormat()) {
  347. if (test_format == AUDIO_U8 || test_format == AUDIO_S16)
  348. break;
  349. }
  350. if (!test_format) {
  351. debug_os2("Unsupported audio format, AUDIO_S16 used");
  352. test_format = AUDIO_S16;
  353. }
  354. pAData = (SDL_PrivateAudioData *) SDL_calloc(1, sizeof(struct SDL_PrivateAudioData));
  355. if (pAData == NULL)
  356. return SDL_OutOfMemory();
  357. _this->hidden = pAData;
  358. ulRC = DosCreateEventSem(NULL, &pAData->hevBuf, DCE_AUTORESET, TRUE);
  359. if (ulRC != NO_ERROR) {
  360. debug_os2("DosCreateEventSem() failed, rc = %lu", ulRC);
  361. return -1;
  362. }
  363. /* Open audio device */
  364. stMCIAmpOpen.usDeviceID = 0;
  365. stMCIAmpOpen.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX,LOUSHORT(ulHandle));
  366. ulRC = mciSendCommand(0, MCI_OPEN,
  367. (_getEnvULong("SDL_AUDIO_SHARE", 1, 0) != 0)?
  368. MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE :
  369. MCI_WAIT | MCI_OPEN_TYPE_ID,
  370. &stMCIAmpOpen, 0);
  371. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  372. DosCloseEventSem(pAData->hevBuf);
  373. pAData->usDeviceId = (USHORT)~0;
  374. return _MCIError("MCI_OPEN", ulRC);
  375. }
  376. pAData->usDeviceId = stMCIAmpOpen.usDeviceID;
  377. if (iscapture) {
  378. MCI_CONNECTOR_PARMS stMCIConnector;
  379. MCI_AMP_SET_PARMS stMCIAmpSet;
  380. BOOL fLineIn = _getEnvULong("SDL_AUDIO_LINEIN", 1, 0);
  381. /* Set particular connector. */
  382. SDL_zero(stMCIConnector);
  383. stMCIConnector.ulConnectorType = (fLineIn)? MCI_LINE_IN_CONNECTOR :
  384. MCI_MICROPHONE_CONNECTOR;
  385. mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_CONNECTOR,
  386. MCI_WAIT | MCI_ENABLE_CONNECTOR |
  387. MCI_CONNECTOR_TYPE, &stMCIConnector, 0);
  388. /* Disable monitor. */
  389. SDL_zero(stMCIAmpSet);
  390. stMCIAmpSet.ulItem = MCI_AMP_SET_MONITOR;
  391. mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_SET,
  392. MCI_WAIT | MCI_SET_OFF | MCI_SET_ITEM,
  393. &stMCIAmpSet, 0);
  394. /* Set record volume. */
  395. stMCIAmpSet.ulLevel = _getEnvULong("SDL_AUDIO_RECVOL", 100, 90);
  396. stMCIAmpSet.ulItem = MCI_AMP_SET_AUDIO;
  397. stMCIAmpSet.ulAudio = MCI_SET_AUDIO_ALL; /* Both cnannels. */
  398. stMCIAmpSet.ulValue = (fLineIn) ? MCI_LINE_IN_CONNECTOR :
  399. MCI_MICROPHONE_CONNECTOR ;
  400. mciSendCommand(stMCIAmpOpen.usDeviceID, MCI_SET,
  401. MCI_WAIT | MCI_SET_AUDIO | MCI_AMP_SET_GAIN,
  402. &stMCIAmpSet, 0);
  403. }
  404. _this->spec.format = test_format;
  405. _this->spec.channels = _this->spec.channels > 1 ? 2 : 1;
  406. if (_this->spec.freq < 8000) {
  407. _this->spec.freq = 8000;
  408. new_freq = TRUE;
  409. } else if (_this->spec.freq > 48000) {
  410. _this->spec.freq = 48000;
  411. new_freq = TRUE;
  412. }
  413. /* Setup mixer. */
  414. pAData->stMCIMixSetup.ulFormatTag = MCI_WAVE_FORMAT_PCM;
  415. pAData->stMCIMixSetup.ulBitsPerSample = SDL_AUDIO_BITSIZE(test_format);
  416. pAData->stMCIMixSetup.ulSamplesPerSec = _this->spec.freq;
  417. pAData->stMCIMixSetup.ulChannels = _this->spec.channels;
  418. pAData->stMCIMixSetup.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
  419. if (!iscapture) {
  420. pAData->stMCIMixSetup.ulFormatMode= MCI_PLAY;
  421. pAData->stMCIMixSetup.pmixEvent = cbAudioWriteEvent;
  422. } else {
  423. pAData->stMCIMixSetup.ulFormatMode= MCI_RECORD;
  424. pAData->stMCIMixSetup.pmixEvent = cbAudioReadEvent;
  425. }
  426. ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
  427. MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
  428. if (LOUSHORT(ulRC) != MCIERR_SUCCESS && _this->spec.freq > 44100) {
  429. new_freq = TRUE;
  430. pAData->stMCIMixSetup.ulSamplesPerSec = 44100;
  431. _this->spec.freq = 44100;
  432. ulRC = mciSendCommand(pAData->usDeviceId, MCI_MIXSETUP,
  433. MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0);
  434. }
  435. debug_os2("Setup mixer [BPS: %lu, Freq.: %lu, Channels: %lu]: %s",
  436. pAData->stMCIMixSetup.ulBitsPerSample,
  437. pAData->stMCIMixSetup.ulSamplesPerSec,
  438. pAData->stMCIMixSetup.ulChannels,
  439. (ulRC == MCIERR_SUCCESS)? "SUCCESS" : "FAIL");
  440. if (ulRC != MCIERR_SUCCESS) {
  441. pAData->stMCIMixSetup.ulBitsPerSample = 0;
  442. return _MCIError("MCI_MIXSETUP", ulRC);
  443. }
  444. if (_this->spec.samples == 0 || new_freq == TRUE) {
  445. /* also see SDL_audio.c:prepare_audiospec() */
  446. /* Pick a default of ~46 ms at desired frequency */
  447. Uint32 samples = (_this->spec.freq / 1000) * 46;
  448. Uint32 power2 = 1;
  449. while (power2 < samples) {
  450. power2 <<= 1;
  451. }
  452. _this->spec.samples = power2;
  453. }
  454. /* Update the fragment size as size in bytes */
  455. SDL_CalculateAudioSpec(&_this->spec);
  456. /* Allocate memory buffers */
  457. stMCIBuffer.ulBufferSize = _this->spec.size;/* (_this->spec.freq / 1000) * 100 */
  458. stMCIBuffer.ulNumBuffers = NUM_BUFFERS;
  459. stMCIBuffer.pBufList = pAData->aMixBuffers;
  460. ulRC = mciSendCommand(pAData->usDeviceId, MCI_BUFFER,
  461. MCI_WAIT | MCI_ALLOCATE_MEMORY, &stMCIBuffer, 0);
  462. if (LOUSHORT(ulRC) != MCIERR_SUCCESS) {
  463. return _MCIError("MCI_BUFFER", ulRC);
  464. }
  465. pAData->cMixBuffers = stMCIBuffer.ulNumBuffers;
  466. _this->spec.size = stMCIBuffer.ulBufferSize;
  467. debug_os2("%s, number of mix buffers: %lu",iscapture ? "capture": "play",pAData->cMixBuffers);
  468. /* Fill all device buffers with data */
  469. for (ulIdx = 0; ulIdx < stMCIBuffer.ulNumBuffers; ulIdx++) {
  470. pAData->aMixBuffers[ulIdx].ulFlags = 0;
  471. pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize;
  472. pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)_this;
  473. SDL_memset(((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer,
  474. _this->spec.silence, stMCIBuffer.ulBufferSize);
  475. }
  476. pAData->pFillBuffer = pAData->aMixBuffers;
  477. pAData->pDrainBuffer = pAData->aMixBuffers;
  478. return 0;
  479. }
  480. static SDL_bool OS2_Init(SDL_AudioDriverImpl * impl)
  481. {
  482. /* Set the function pointers */
  483. impl->DetectDevices = OS2_DetectDevices;
  484. impl->OpenDevice = OS2_OpenDevice;
  485. impl->PlayDevice = OS2_PlayDevice;
  486. impl->WaitDevice = OS2_WaitDevice;
  487. impl->GetDeviceBuf = OS2_GetDeviceBuf;
  488. impl->CloseDevice = OS2_CloseDevice;
  489. impl->CaptureFromDevice = OS2_CaptureFromDevice ;
  490. impl->FlushCapture = OS2_FlushCapture;
  491. impl->HasCaptureSupport = SDL_TRUE;
  492. return SDL_TRUE; /* this audio target is available. */
  493. }
  494. AudioBootStrap OS2AUDIO_bootstrap = {
  495. "DART", "OS/2 DART", OS2_Init, SDL_FALSE
  496. };
  497. #endif /* SDL_AUDIO_DRIVER_OS2 */
  498. /* vi: set ts=4 sw=4 expandtab: */