source: trunk/src/dsound/new/dart.cpp@ 3073

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

Changed buffer size calculation

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