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

Last change on this file since 3555 was 3555, checked in by mike, 25 years ago

Updated and slightly fixed DSOUND

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