source: trunk/src/dsound/dart.cpp@ 9232

Last change on this file since 9232 was 9232, checked in by sandervl, 23 years ago

YD: Load MMPM2 (MDM.DLL) on demand

File size: 14.5 KB
Line 
1/* $Id: dart.cpp,v 1.6 2002-09-14 08:31:24 sandervl Exp $ */
2/*
3 * Dart Interface..
4 *
5 * Kevin Langman
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11#define INCL_DOS
12#define INCL_OS2MM
13#include <os2wrap.h>
14#include <os2mewrap.h>
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19
20#define DART_DSOUND
21#include "dart.h"
22#include "dsmixer.h"
23
24#include "initdsound.h"
25
26#include <misc.h>
27
28static MCI_MIXSETUP_PARMS *MixSetup_Global;
29static long lLastBuff;
30static char *pDSoundBuff;
31static BOOL fIsPlaying = FALSE;
32
33USHORT usDeviceID; /* Amp Mixer device id */
34
35/* TODO: scrap this variable! */
36MCI_MIX_BUFFER *pMixBuffers; /* Device buffers */
37
38MCI_MIXSETUP_PARMS MixSetupParms; /* Mixer parameters */
39MCI_BUFFER_PARMS BufferParms; /* Device buffer parms */
40ULONG ulNumDartBuffs; /* # of DART buffers */
41
42#define ULONG_LOWD(ul) (*(USHORT *)((ULONG *)(&ul))) /* Low Word */
43
44//******************************************************************************
45//******************************************************************************
46LONG APIENTRY OS2_Dart_Update(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
47{
48 ULONG rc;
49
50 if( ( (ulFlags == MIX_WRITE_COMPLETE) ||
51 ((ulFlags == (MIX_WRITE_COMPLETE | MIX_STREAM_ERROR))&&
52 (ulStatus == ERROR_DEVICE_UNDERRUN)) )
53 )
54 {
55 // wrap last buffer index
56 lLastBuff++;
57 if (lLastBuff >= ulNumDartBuffs)
58 {
59 lLastBuff = 0;
60 }
61
62 if( fIsPlaying == FALSE /*&& lLastBuff == 0*/ )
63 {
64 dsmciSendCommand(usDeviceID, MCI_STOP, MCI_WAIT, NULL, 0);
65 return TRUE;
66 }
67
68 /* Now mix sound from all playing secondary SoundBuffers into the primary buffer */
69 MixCallback(BUFFER_SIZE/ulNumDartBuffs);
70
71 /* Fill The next buff from the DSound Buffer */
72 memcpy( pMixBuffers[lLastBuff].pBuffer, &pDSoundBuff[lLastBuff*(BUFFER_SIZE/ulNumDartBuffs)], BUFFER_SIZE/ulNumDartBuffs );
73
74 /* Send the NEXT Buffer to Dart for playing! */
75 rc = MixSetup_Global->pmixWrite(MixSetup_Global->ulMixHandle, &pMixBuffers[lLastBuff], 1 );
76 }
77
78 return TRUE;
79}
80
81
82long Dart_Open_Device(USHORT *pusDeviceID, void **vpMixBuffer, void **vpMixSetup,
83 void **vpBuffParms, void **ppvBuffer)
84{
85
86 MCI_AMP_OPEN_PARMS AmpOpenParms;
87 ULONG rc, ulNew;
88 LONG lAdd = 5;
89 short device = 0;
90
91 dprintf(("DSOUND-DART: Dart_Open_Device"));
92
93 /* TODO: remove eventually... */
94 DosSetRelMaxFH(&lAdd, &ulNew);
95
96 ulNumDartBuffs = BUFFER_SIZE * 44100 / (2 * 2 * 2048 * 22050);
97
98 pMixBuffers = (MCI_MIX_BUFFER*)malloc(sizeof(MCI_MIX_BUFFER) * ulNumDartBuffs);
99
100 *vpMixBuffer = pMixBuffers;
101 *vpMixSetup = &MixSetupParms;
102 *vpBuffParms = &BufferParms;
103
104 lLastBuff = 0;
105
106 /* Is there a way to avoid the use of the MixSetup_Global ????? */
107 MixSetup_Global = &MixSetupParms;
108 /****************************************************************/
109
110 // If the DSOUND_DEVICE is set then use that number as the device for DART.
111 // this will allow people with many sound cards to use the card of their choice
112 // for an instance of a DSOUND enabled app!
113 if (getenv("DSOUND_DEVICE") != NULL) {
114 device = atoi(getenv("DSOUND_DEVICE"));
115 }
116
117 /* Open the AmpMix Device and start processing the buffer! */
118 memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
119 AmpOpenParms.usDeviceID = 0;
120 //AmpOpenParms.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX;
121 AmpOpenParms.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, (USHORT)device);
122
123 rc = dsmciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE_ID, (PVOID)&AmpOpenParms, 0);
124 if (rc != MCIERR_SUCCESS) {
125 dprintf(("DSOUND-DART: MCI_OPEN %d", rc));
126 return DSERR_GENERIC;
127 }
128 *pusDeviceID = AmpOpenParms.usDeviceID;
129 usDeviceID = AmpOpenParms.usDeviceID;
130
131 /* setup playback parameters */
132 memset(&MixSetupParms, 0, sizeof(MCI_MIXSETUP_PARMS));
133 MixSetupParms.ulBitsPerSample = 16;
134 MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
135 MixSetupParms.ulSamplesPerSec = 22500;
136 MixSetupParms.ulChannels = 2;
137 MixSetupParms.ulFormatMode = MCI_PLAY;
138 MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
139 MixSetupParms.pmixEvent = OS2_Dart_Update;
140
141 rc = dsmciSendCommand(usDeviceID, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_INIT,
142 (PVOID)&MixSetupParms, 0);
143 if (rc != MCIERR_SUCCESS) {
144 dprintf(("DSOUND-DART: MCI_MIXSETUP (Constructor) %d", rc));
145 return DSERR_GENERIC;
146 }
147
148 /* Create the Audio Buffer */
149 // OK... Since DSound only uses 1 buffer and uses the GetPosition API to
150 // figure out where it can and can't write. I have emulating this by
151 // using many smaller buffers and do locking by tracking what buffer that is
152 // currently playing. This maybe less CPU friendly then other methods but
153 // it's the best my little brain could come up with!!
154
155 MixSetupParms.ulBufferSize = BUFFER_SIZE / ulNumDartBuffs;
156
157 BufferParms.ulNumBuffers = ulNumDartBuffs;
158 BufferParms.ulBufferSize = MixSetupParms.ulBufferSize;
159 BufferParms.pBufList = pMixBuffers;
160
161 rc = dsmciSendCommand(usDeviceID, MCI_BUFFER, MCI_WAIT | MCI_ALLOCATE_MEMORY,
162 (PVOID)&BufferParms, 0);
163 if ( ULONG_LOWD(rc) != MCIERR_SUCCESS ) {
164 dprintf(("DSOUND-DART: MCI_BUFFER (Alloc) %d", rc));
165 dsmciSendCommand(*pusDeviceID, MCI_CLOSE, MCI_WAIT, NULL, 0);
166 return DSERR_OUTOFMEMORY;
167 }
168
169 /* Clear the Buffer */
170 // Set initial values to 32767 to avoid clicks on start of playback.
171 for (device = 0; device < ulNumDartBuffs; device++) {
172 memset(pMixBuffers[device].pBuffer, 32767, BUFFER_SIZE/ulNumDartBuffs);
173 }
174
175 // Allocate memory for the DSound "Holder" buffer.
176 // TODO: Move this to the Constructor for OS2PrimBuff
177 // so that the Deconstructor can be used to free the memory!
178 *(char**)ppvBuffer = (char*)malloc(BUFFER_SIZE);
179 if (*ppvBuffer == NULL) {
180 return DSERR_OUTOFMEMORY;
181 }
182 pDSoundBuff = (char*)(*ppvBuffer);
183
184 dprintf(("DSOUND-DART: Dart_Open_Device Exiting"));
185
186 return DS_OK;
187}
188
189long Dart_Close_Device(USHORT usDeviceID, void *vpMixBuffer, void *vpMixSetup,
190 void *vpBuffParms )
191{
192 MCI_MIX_BUFFER *MixBuffer;
193 MCI_MIXSETUP_PARMS *MixSetup;
194 MCI_BUFFER_PARMS *BufferParms;
195 ULONG rc;
196
197 dprintf(("DSOUND-DART: Dart_Close_Device"));
198
199 MixBuffer = (MCI_MIX_BUFFER*)vpMixBuffer;
200 MixSetup = (MCI_MIXSETUP_PARMS*)vpMixSetup;
201 BufferParms = (MCI_BUFFER_PARMS*)vpBuffParms;
202
203 rc = dsmciSendCommand(usDeviceID, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, BufferParms, 0);
204 if (rc != MCIERR_SUCCESS) {
205 dprintf(("DSOUND-DART: MCI_BUFFER (Close) %d", rc));
206 }
207 rc = dsmciSendCommand(usDeviceID, MCI_CLOSE, MCI_WAIT, NULL, 0);
208 if (rc != MCIERR_SUCCESS) {
209 dprintf(("DSOUND-DART: MCI_CLOSE (Close) %d", rc));
210 }
211
212 dprintf(("DSOUND-DART: Dart_Close_Device returning DS_OK"));
213 return DS_OK;
214}
215
216
217long Dart_GetPosition(USHORT usDeviceID, LONG *pulPosition)
218{
219 dprintf(("DSOUND-DART: Dart_GetPosition"));
220
221 *pulPosition = (lLastBuff * (BUFFER_SIZE/ulNumDartBuffs)) + (BUFFER_SIZE/ulNumDartBuffs);
222 if (*pulPosition > BUFFER_SIZE)
223 *pulPosition = 0;
224
225 dprintf(("DSOUND-DART: Returning %d", *pulPosition));
226
227 return DS_OK;
228}
229
230long Dart_SetFormat(USHORT *pusDeviceID, void *vpMixSetup, void *vpBufferParms, void **vpMixBuffer, LONG lBPS, LONG lSPS, LONG lChannels )
231{
232 ULONG rc;
233 MCI_MIXSETUP_PARMS *MixSetup;
234 MCI_BUFFER_PARMS *BufferParms;
235 MCI_AMP_OPEN_PARMS AmpOpenParms;
236 short device = 0;
237
238 /* Recalculate the number of DART buffers based on the new data rate */
239 /* Note: the factor 2048 means a 2K buffer, 1024 = 4K, 512 = 8K and so on */
240 ulNumDartBuffs = BUFFER_SIZE * 44100 / ((lBPS / 8) * lChannels * 2048 * lSPS);
241
242 /* Reallocate the MCI_MIX_BUFFER array */
243 free(pMixBuffers);
244 pMixBuffers = (MCI_MIX_BUFFER*)malloc(sizeof(MCI_MIX_BUFFER) * ulNumDartBuffs);
245
246 MixSetup = (MCI_MIXSETUP_PARMS*)vpMixSetup;
247 BufferParms = (MCI_BUFFER_PARMS*)vpBufferParms;
248 *vpMixBuffer = pMixBuffers;
249
250
251 dprintf(("DSOUND-DART: Dart_SetFormat"));
252
253 // If the DSOUND_DEVICE is set then use that number as the device for DART.
254 // this will allow people with many sound cards to use the card of there choice
255 // for an instance of a DSOUND enabled app!
256 if (getenv("DSOUND_DEVICE") != NULL) {
257 device = atoi(getenv( "DSOUND_DEVICE" ));
258 }
259
260 /* Dealloc to avoid the 5511 error */
261 rc = dsmciSendCommand(*pusDeviceID, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY,
262 BufferParms, 0);
263 if (rc != MCIERR_SUCCESS) {
264 dprintf(("DSOUND-DART: MCI_DEALLOCATE_MEMORY (SetFormat) %d", rc));
265 return DSERR_GENERIC;
266 }
267
268 rc = dsmciSendCommand(*pusDeviceID, MCI_CLOSE, MCI_WAIT, NULL, 0);
269 if (rc != MCIERR_SUCCESS) {
270 dprintf(("DSOUND-DART: MCI_CLOSE (SetFormat) %d", rc));
271 return(DSERR_GENERIC);
272 }
273
274 /* Reopen the MixAmp Device and start processing the buffer! */
275 memset(&AmpOpenParms,0,sizeof(MCI_AMP_OPEN_PARMS));
276 AmpOpenParms.usDeviceID = 0;
277 AmpOpenParms.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, (USHORT)device);
278
279 rc = dsmciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE_ID, (PVOID)&AmpOpenParms, 0);
280 if (rc != MCIERR_SUCCESS) {
281 dprintf(("DSOUND-DART: MCI_OPEN %d", rc));
282 return DSERR_GENERIC;
283 }
284 *pusDeviceID = AmpOpenParms.usDeviceID;
285
286 /* setup playback parameters */
287 memset(MixSetup, 0, sizeof(MCI_MIXSETUP_PARMS));
288 MixSetup->ulBitsPerSample = lBPS;
289 MixSetup->ulFormatTag = MCI_WAVE_FORMAT_PCM;
290 MixSetup->ulSamplesPerSec = lSPS;
291 MixSetup->ulChannels = lChannels;
292 MixSetup->ulFormatMode = MCI_PLAY;
293 MixSetup->ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
294 MixSetup->pmixEvent = OS2_Dart_Update;
295
296 rc = dsmciSendCommand(*pusDeviceID, MCI_MIXSETUP, MCI_WAIT | MCI_MIXSETUP_INIT,
297 (PVOID)MixSetup, 0);
298 if (rc != MCIERR_SUCCESS) {
299 dprintf(("DSOUND-DART: MCI_MIXSETUP (SetFormat) %d", rc));
300 return DSERR_GENERIC;
301 }
302
303 memset(BufferParms, 0, sizeof(MCI_BUFFER_PARMS));
304 memset(pMixBuffers, 0, sizeof(MCI_MIX_BUFFER) * ulNumDartBuffs);
305 BufferParms->ulStructLength = sizeof(MCI_BUFFER_PARMS);
306 BufferParms->ulNumBuffers = ulNumDartBuffs;
307 BufferParms->ulBufferSize = BUFFER_SIZE/ulNumDartBuffs;
308 BufferParms->pBufList = pMixBuffers;
309 pMixBuffers->pBuffer = NULL;
310
311 rc = dsmciSendCommand(*pusDeviceID, MCI_BUFFER, MCI_WAIT | MCI_ALLOCATE_MEMORY,
312 (PVOID)BufferParms, 0);
313 if (rc != MCIERR_SUCCESS) {
314 dprintf(("DSOUND-DART: MCI_BUFFER_ALLOCATE_MEMORY (SetFormat) %d", rc));
315 dsmciSendCommand(*pusDeviceID, MCI_CLOSE, MCI_WAIT, NULL, 0);
316 memset(pMixBuffers, 0, sizeof(MCI_MIX_BUFFER) * ulNumDartBuffs);
317 return DSERR_OUTOFMEMORY;
318 }
319
320 /* Clear the Buffer */
321 // If the data is 8bit then set values to 127
322 // If the data is 16bit then set values to 32767
323 // Doing this will avoid the clicks at the beging of playback! :)
324 for (int i=0; i<ulNumDartBuffs; i++) {
325 memset(pMixBuffers[i].pBuffer, lBPS == 8 ? 127 : 32767, BUFFER_SIZE / ulNumDartBuffs);
326 }
327
328 lLastBuff = 0; /* we have to reset this, the number of buffers probably changed! */
329
330 /* If the primary buffer was playing, we have to restart it!! */
331 if (fIsPlaying) {
332 dprintf(("DSOUND-DART: Restarting playback!!!!"));
333
334 /* Mix the first buffer before playing */
335 MixCallback(BUFFER_SIZE/ulNumDartBuffs);
336 memcpy(pMixBuffers[lLastBuff].pBuffer, &pDSoundBuff[lLastBuff*(BUFFER_SIZE/ulNumDartBuffs)], BUFFER_SIZE/ulNumDartBuffs);
337
338 USHORT sel = RestoreOS2FS();
339 /* Note: the call to pmixWrite trashes the FS selector, we have to save */
340 /* and then restore FS!!! Otherwise exception handling will be broken. */
341 MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, pMixBuffers, 2);
342 SetFS(sel);
343 fIsPlaying = TRUE;
344 }
345
346 return DS_OK;
347}
348
349
350long Dart_Stop(USHORT usDeviceID)
351{
352 dprintf(("DSOUND-DART: Dart_Stop"));
353
354 if (!fIsPlaying)
355 return DS_OK;
356
357 fIsPlaying = FALSE;
358
359 // The OS2_Dart_Update function is now used to send the MCI_STOP!!
360 // Doing this fixes a bug where after a Dart_Stop call the sound would
361 // continue to loop because the OS2_Dart_Update would send the next
362 // buffer causing Dart to start again..
363
364 //rc = dsmciSendCommand(usDeviceID, MCI_STOP, MCI_WAIT, NULL, 0);
365 //if (rc != MCIERR_SUCCESS) {
366 // { FILE *dbf; dbf=fopen("log.log", "a"); fprintf( dbf, "Error in MCI_STOP...\n"); fclose(dbf); }
367 // dprintf(("DSOUND-DART: MCI_PAUSE %d", rc));
368 // return DSERR_GENERIC;
369 //}
370
371
372 return DS_OK;
373}
374
375long Dart_Play(USHORT usDeviceID, void *vpMixSetup, void *vpMixBuffer, long playing)
376{
377 ULONG rc;
378 MCI_MIXSETUP_PARMS *MixSetup;
379 MCI_MIX_BUFFER *MixBuffer;
380
381 MixSetup = (MCI_MIXSETUP_PARMS*)vpMixSetup;
382 MixBuffer = (MCI_MIX_BUFFER*)vpMixBuffer;
383
384 dprintf(("DSOUND-DART: Dart_Play"));
385
386 if (playing == TRUE)
387 {
388 rc = dsmciSendCommand(usDeviceID, MCI_RESUME, MCI_WAIT, NULL, 0);
389 if (rc != MCIERR_SUCCESS)
390 {
391 dprintf(("DSOUND-DART: MCI_RESUME %d", rc));
392 return DSERR_GENERIC;
393 }
394 }
395 else
396 { //if (playing==FALSE)
397 dprintf(("DSOUND-DART: Playback started!!!!"));
398
399 // verify if buffers have actually been allocated
400 // PH 2001-04-20 Power DVD 3 seens to come in here
401 // with ulNumDartBuffs == 0 and also pmixWrite==NULL.
402 // However pmixEvent is != NULL. So I assume (!)
403 // this might fix the cause.
404 //
405 // Does fix the crash actually. I suspect DART cannot
406 // deliver mixing functions for the requested sound format:
407 // 16-Bit, 4-channel?, 48kHz.
408 if( (MixSetup->pmixWrite != NULL) &&
409 (MixSetup->ulNumBuffers > 0) )
410 {
411
412 /* Mix the first buffer before playing */
413 MixCallback(BUFFER_SIZE/ulNumDartBuffs);
414 memcpy(MixBuffer[lLastBuff].pBuffer, &pDSoundBuff[lLastBuff*(BUFFER_SIZE/ulNumDartBuffs)], BUFFER_SIZE/ulNumDartBuffs);
415
416 USHORT sel = RestoreOS2FS();
417 /* Note: the call to pmixWrite trashes the FS selector, we have to save */
418 /* and then restore FS!!! Otherwise exception handling will be broken. */
419 MixSetupParms.pmixWrite(MixSetupParms.ulMixHandle, MixBuffer, 2);
420 SetFS(sel);
421 fIsPlaying = TRUE;
422 }
423 }
424
425 return DS_OK;
426}
Note: See TracBrowser for help on using the repository browser.