This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_dart.c
454 lines (403 loc) · 15.6 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
20
21
Sam Lantinga
slouken@libsdl.org
*/
22
#include "SDL_config.h"
23
24
25
26
27
/* Allow access to a raw mixing buffer */
#include "SDL_timer.h"
#include "SDL_audio.h"
28
#include "../SDL_audio_c.h"
29
30
31
32
33
34
#include "SDL_dart.h"
// Buffer states:
#define BUFFER_EMPTY 0
#define BUFFER_USED 1
35
36
37
38
typedef struct _tMixBufferDesc
{
int iBufferUsage; // BUFFER_EMPTY or BUFFER_USED
SDL_AudioDevice *pSDLAudioDevice;
39
40
41
42
43
44
45
46
47
} tMixBufferDesc, *pMixBufferDesc;
//---------------------------------------------------------------------
// DARTEventFunc
//
// This function is called by DART, when an event occures, like end of
// playback of a buffer, etc...
//---------------------------------------------------------------------
48
LONG APIENTRY
49
DARTEventFunc(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, ULONG ulFlags)
50
{
51
52
53
54
55
56
57
58
59
60
61
62
63
64
if (ulFlags && MIX_WRITE_COMPLETE) { // Playback of buffer completed!
// Get pointer to buffer description
pMixBufferDesc pBufDesc;
if (pBuffer) {
pBufDesc = (pMixBufferDesc) (*pBuffer).ulUserParm;
if (pBufDesc) {
SDL_AudioDevice *pSDLAudioDevice = pBufDesc->pSDLAudioDevice;
// Set the buffer to be empty
pBufDesc->iBufferUsage = BUFFER_EMPTY;
// And notify DART feeder thread that it will have to work a bit.
if (pSDLAudioDevice)
65
66
DosPostEventSem(pSDLAudioDevice->hidden->
hevAudioBufferPlayed);
67
68
}
}
69
}
70
return TRUE;
71
72
73
}
74
int
75
DART_OpenAudio(_THIS, SDL_AudioSpec * spec)
76
{
77
78
79
80
81
82
83
84
85
86
87
88
89
90
MCI_AMP_OPEN_PARMS AmpOpenParms;
MCI_GENERIC_PARMS GenericParms;
int iDeviceOrd = 0; // Default device to be used
int bOpenShared = 1; // Try opening it shared
int iBits = 16; // Default is 16 bits signed
int iFreq = 44100; // Default is 44KHz
int iChannels = 2; // Default is 2 channels (Stereo)
int iNumBufs = 2; // Number of audio buffers: 2
int iBufSize;
int iOpenMode;
int iSilence;
int rc;
// First thing is to try to open a given DART device!
91
SDL_memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
92
93
94
95
96
97
98
99
// pszDeviceType should contain the device type in low word, and device ordinal in high word!
AmpOpenParms.pszDeviceType =
(PSZ) (MCI_DEVTYPE_AUDIO_AMPMIX | (iDeviceOrd << 16));
iOpenMode = MCI_WAIT | MCI_OPEN_TYPE_ID;
if (bOpenShared)
iOpenMode |= MCI_OPEN_SHAREABLE;
100
rc = mciSendCommand(0, MCI_OPEN, iOpenMode, (PVOID) & AmpOpenParms, 0);
101
102
103
104
105
106
107
108
if (rc != MCIERR_SUCCESS) // No audio available??
return (-1);
// Save the device ID we got from DART!
// We will use this in the next calls!
iDeviceOrd = AmpOpenParms.usDeviceID;
// Determine the audio parameters from the AudioSpec
switch (spec->format & 0xFF) {
109
110
111
112
113
114
115
116
117
118
119
120
121
122
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
iSilence = 0x80;
iBits = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
iSilence = 0x00;
iBits = 16;
break;
default:
// Close DART, and exit with error code!
123
124
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Unsupported audio format");
125
126
127
128
129
return (-1);
}
iFreq = spec->freq;
iChannels = spec->channels;
/* Update the fragment size as size in bytes */
130
SDL_CalculateAudioSpec(spec);
131
132
133
iBufSize = spec->size;
// Now query this device if it supports the given freq/bits/channels!
134
135
SDL_memset(&(_this->hidden->MixSetupParms), 0,
sizeof(MCI_MIXSETUP_PARMS));
136
137
138
139
140
141
142
_this->hidden->MixSetupParms.ulBitsPerSample = iBits;
_this->hidden->MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
_this->hidden->MixSetupParms.ulSamplesPerSec = iFreq;
_this->hidden->MixSetupParms.ulChannels = iChannels;
_this->hidden->MixSetupParms.ulFormatMode = MCI_PLAY;
_this->hidden->MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
_this->hidden->MixSetupParms.pmixEvent = DARTEventFunc;
143
144
145
rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
&(_this->hidden->MixSetupParms), 0);
146
147
if (rc != MCIERR_SUCCESS) { // The device cannot handle this format!
// Close DART, and exit with error code!
148
149
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Audio device doesn't support requested audio format");
150
151
152
return (-1);
}
// The device can handle this format, so initialize!
153
154
155
rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT,
&(_this->hidden->MixSetupParms), 0);
156
if (rc != MCIERR_SUCCESS) { // The device could not be opened!
157
// Close DART, and exit with error code!
158
159
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Audio device could not be set up");
160
161
162
163
164
165
return (-1);
}
// Ok, the device is initialized.
// Now we should allocate buffers. For this, we need a place where
// the buffer descriptors will be:
_this->hidden->pMixBuffers =
166
(MCI_MIX_BUFFER *) SDL_malloc(sizeof(MCI_MIX_BUFFER) * iNumBufs);
167
168
if (!(_this->hidden->pMixBuffers)) { // Not enough memory!
// Close DART, and exit with error code!
169
170
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Not enough memory for audio buffer descriptors");
171
172
173
174
175
176
177
178
return (-1);
}
// Now that we have the place for buffer list, we can ask DART for the
// buffers!
_this->hidden->BufferParms.ulNumBuffers = iNumBufs; // Number of buffers
_this->hidden->BufferParms.ulBufferSize = iBufSize; // each with this size
_this->hidden->BufferParms.pBufList = _this->hidden->pMixBuffers; // getting descriptorts into this list
// Allocate buffers!
179
180
181
rc = mciSendCommand(iDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
182
183
184
185
if ((rc != MCIERR_SUCCESS)
|| (iNumBufs != _this->hidden->BufferParms.ulNumBuffers)
|| (_this->hidden->BufferParms.ulBufferSize == 0)) { // Could not allocate memory!
// Close DART, and exit with error code!
186
SDL_free(_this->hidden->pMixBuffers);
187
_this->hidden->pMixBuffers = NULL;
188
189
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("DART could not allocate buffers");
190
191
192
193
194
195
196
return (-1);
}
// Ok, we have all the buffers allocated, let's mark them!
{
int i;
for (i = 0; i < iNumBufs; i++) {
pMixBufferDesc pBufferDesc =
197
(pMixBufferDesc) SDL_malloc(sizeof(tMixBufferDesc));;
198
199
200
201
202
203
204
205
// Check if this buffer was really allocated by DART
if ((!(_this->hidden->pMixBuffers[i].pBuffer))
|| (!pBufferDesc)) { // Wrong buffer!
// Close DART, and exit with error code!
// Free buffer descriptions
{
int j;
for (j = 0; j < i; j++)
206
207
SDL_free((void *) (_this->hidden->pMixBuffers[j].
ulUserParm));
208
209
}
// and cleanup
210
211
212
213
mciSendCommand(iDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
SDL_free(_this->hidden->pMixBuffers);
214
_this->hidden->pMixBuffers = NULL;
215
216
217
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT,
&GenericParms, 0);
SDL_SetError("Error at internal buffer check");
218
219
220
221
222
223
224
225
226
227
228
return (-1);
}
pBufferDesc->iBufferUsage = BUFFER_EMPTY;
pBufferDesc->pSDLAudioDevice = _this;
_this->hidden->pMixBuffers[i].ulBufferLength =
_this->hidden->BufferParms.ulBufferSize;
_this->hidden->pMixBuffers[i].ulUserParm = (ULONG) pBufferDesc; // User parameter: Description of buffer
_this->hidden->pMixBuffers[i].ulFlags = 0; // Some stuff should be flagged here for DART, like end of
// audio data, but as we will continously send
// audio data, there will be no end.:)
229
230
SDL_memset(_this->hidden->pMixBuffers[i].pBuffer, iSilence,
iBufSize);
231
232
}
}
233
234
235
236
237
_this->hidden->iNextFreeBuffer = 0;
_this->hidden->iLastPlayedBuf = -1;
// Create event semaphore
if (DosCreateEventSem
(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE) != NO_ERROR)
238
{
239
240
241
242
// Could not create event semaphore!
{
int i;
for (i = 0; i < iNumBufs; i++)
243
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
244
}
245
246
247
248
mciSendCommand(iDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
SDL_free(_this->hidden->pMixBuffers);
249
_this->hidden->pMixBuffers = NULL;
250
251
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Could not create event semaphore");
252
return (-1);
253
}
254
255
256
257
258
259
260
261
262
// Store the new settings in global variables
_this->hidden->iCurrDeviceOrd = iDeviceOrd;
_this->hidden->iCurrFreq = iFreq;
_this->hidden->iCurrBits = iBits;
_this->hidden->iCurrChannels = iChannels;
_this->hidden->iCurrNumBufs = iNumBufs;
_this->hidden->iCurrBufSize = iBufSize;
return (0);
263
264
265
266
}
267
void
268
DART_ThreadInit(_THIS)
269
{
270
return;
271
272
273
}
/* This function waits until it is possible to write a full sound buffer */
274
void
275
DART_WaitAudio(_THIS)
276
{
277
278
279
280
int i;
pMixBufferDesc pBufDesc;
ULONG ulPostCount;
281
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
282
283
284
285
286
287
288
// If there is already an empty buffer, then return now!
for (i = 0; i < _this->hidden->iCurrNumBufs; i++) {
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[i].ulUserParm;
if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
return;
}
// If there is no empty buffer, wait for one to be empty!
289
DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // Wait max 1 sec!!! Important!
290
return;
291
292
}
293
void
294
DART_PlayAudio(_THIS)
295
{
296
297
298
299
300
301
302
int iFreeBuf = _this->hidden->iNextFreeBuffer;
pMixBufferDesc pBufDesc;
pBufDesc =
(pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
pBufDesc->iBufferUsage = BUFFER_USED;
// Send it to DART to be queued
303
304
305
306
_this->hidden->MixSetupParms.pmixWrite(_this->hidden->MixSetupParms.
ulMixHandle,
&(_this->hidden->
pMixBuffers[iFreeBuf]), 1);
307
308
309
310
_this->hidden->iLastPlayedBuf = iFreeBuf;
iFreeBuf = (iFreeBuf + 1) % _this->hidden->iCurrNumBufs;
_this->hidden->iNextFreeBuffer = iFreeBuf;
311
312
}
313
Uint8 *
314
DART_GetAudioBuf(_THIS)
315
{
316
317
318
int iFreeBuf;
Uint8 *pResult;
pMixBufferDesc pBufDesc;
319
320
321
322
323
324
325
326
327
328
329
330
331
332
if (_this) {
if (_this->hidden) {
iFreeBuf = _this->hidden->iNextFreeBuffer;
pBufDesc =
(pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].
ulUserParm;
if (pBufDesc) {
if (pBufDesc->iBufferUsage == BUFFER_EMPTY) {
pResult = _this->hidden->pMixBuffers[iFreeBuf].pBuffer;
return pResult;
}
} else
333
334
printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n",
pBufDesc);
335
} else
336
337
printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n",
_this->hidden);
338
} else
339
printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this);
340
return NULL;
341
342
}
343
void
344
DART_WaitDone(_THIS)
345
{
346
347
348
349
350
351
352
353
354
355
pMixBufferDesc pBufDesc;
ULONG ulPostCount;
APIRET rc;
pBufDesc =
(pMixBufferDesc) _this->hidden->pMixBuffers[_this->hidden->
iLastPlayedBuf].
ulUserParm;
rc = NO_ERROR;
while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc == NO_ERROR)) {
356
357
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
358
}
359
360
}
361
void
362
DART_CloseAudio(_THIS)
363
{
364
365
MCI_GENERIC_PARMS GenericParms;
int rc;
366
367
// Stop DART playback
368
369
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT,
&GenericParms, 0);
370
if (rc != MCIERR_SUCCESS) {
371
#ifdef SFX_DEBUG_BUILD
372
373
printf("Could not stop DART playback!\n");
fflush(stdout);
374
#endif
375
376
}
// Close event semaphore
377
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
378
379
380
381
382
// Free memory of buffer descriptions
{
int i;
for (i = 0; i < _this->hidden->iCurrNumBufs; i++)
383
SDL_free((void *) (_this->hidden->pMixBuffers[i].ulUserParm));
384
}
385
386
// Deallocate buffers
387
388
389
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_DEALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
390
391
// Free bufferlist
392
SDL_free(_this->hidden->pMixBuffers);
393
_this->hidden->pMixBuffers = NULL;
394
395
// Close dart
396
397
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT,
&(GenericParms), 0);
398
399
400
401
}
/* Audio driver bootstrap functions */
402
int
403
Audio_Available(void)
404
{
405
return (1);
406
407
}
408
void
409
Audio_DeleteDevice(SDL_AudioDevice * device)
410
{
411
412
SDL_free(device->hidden);
SDL_free(device);
413
414
}
415
SDL_AudioDevice *
416
Audio_CreateDevice(int devindex)
417
{
418
419
420
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
421
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
422
if (this) {
423
SDL_memset(this, 0, (sizeof *this));
424
this->hidden = (struct SDL_PrivateAudioData *)
425
SDL_malloc((sizeof *this->hidden));
426
427
}
if ((this == NULL) || (this->hidden == NULL)) {
428
SDL_OutOfMemory();
429
if (this)
430
SDL_free(this);
431
432
return (0);
}
433
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
434
435
436
437
438
439
440
441
442
443
444
445
446
/* Set the function pointers */
this->OpenAudio = DART_OpenAudio;
this->ThreadInit = DART_ThreadInit;
this->WaitAudio = DART_WaitAudio;
this->PlayAudio = DART_PlayAudio;
this->GetAudioBuf = DART_GetAudioBuf;
this->WaitDone = DART_WaitDone;
this->CloseAudio = DART_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
447
448
449
}
AudioBootStrap DART_bootstrap = {
450
451
"dart", "OS/2 Direct Audio RouTines (DART)",
Audio_Available, Audio_CreateDevice
452
453
};
454
/* vi: set ts=4 sw=4 expandtab: */