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

Last change on this file since 5120 was 3925, checked in by bird, 25 years ago

Added the CVS keyword Id.

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