comparison src/audio/macrom/SDL_romaudio.c @ 2049:5f6550e5184f

Merged SDL-ryan-multiple-audio-device branch r2803:2871 into the trunk.
author Ryan C. Gordon <icculus@icculus.org>
date Tue, 17 Oct 2006 09:15:21 +0000
parents c27292a690b7
children d22372343744
comparison
equal deleted inserted replaced
2048:6067c7f9a672 2049:5f6550e5184f
19 Sam Lantinga 19 Sam Lantinga
20 slouken@libsdl.org 20 slouken@libsdl.org
21 */ 21 */
22 #include "SDL_config.h" 22 #include "SDL_config.h"
23 23
24 /* This should work on PowerPC and Intel Mac OS X, and Carbonized Mac OS 9. */
25
24 #if defined(__APPLE__) && defined(__MACH__) 26 #if defined(__APPLE__) && defined(__MACH__)
27 # define SDL_MACOS_NAME "Mac OS X"
25 # include <Carbon/Carbon.h> 28 # include <Carbon/Carbon.h>
26 #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335) 29 #elif TARGET_API_MAC_CARBON && (UNIVERSAL_INTERFACES_VERSION > 0x0335)
30 # define SDL_MACOS_NAME "Mac OS 9"
27 # include <Carbon.h> 31 # include <Carbon.h>
28 #else 32 #else
33 # define SDL_MACOS_NAME "Mac OS 9"
29 # include <Sound.h> /* SoundManager interface */ 34 # include <Sound.h> /* SoundManager interface */
30 # include <Gestalt.h> 35 # include <Gestalt.h>
31 # include <DriverServices.h> 36 # include <DriverServices.h>
32 #endif 37 #endif
33 38
43 #include "SDL_audio.h" 48 #include "SDL_audio.h"
44 #include "../SDL_audio_c.h" 49 #include "../SDL_audio_c.h"
45 #include "../SDL_sysaudio.h" 50 #include "../SDL_sysaudio.h"
46 #include "SDL_romaudio.h" 51 #include "SDL_romaudio.h"
47 52
48 /* Audio driver functions */
49
50 static void Mac_CloseAudio(_THIS);
51 static int Mac_OpenAudio(_THIS, SDL_AudioSpec * spec);
52 static void Mac_LockAudio(_THIS);
53 static void Mac_UnlockAudio(_THIS);
54
55 /* Audio driver bootstrap functions */
56
57
58 static int
59 Audio_Available(void)
60 {
61 return (1);
62 }
63
64 static void
65 Audio_DeleteDevice(SDL_AudioDevice * device)
66 {
67 SDL_free(device->hidden);
68 SDL_free(device);
69 }
70
71 static SDL_AudioDevice *
72 Audio_CreateDevice(int devindex)
73 {
74 SDL_AudioDevice *this;
75
76 /* Initialize all variables that we clean on shutdown */
77 this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
78 if (this) {
79 SDL_memset(this, 0, (sizeof *this));
80 this->hidden = (struct SDL_PrivateAudioData *)
81 SDL_malloc((sizeof *this->hidden));
82 }
83 if ((this == NULL) || (this->hidden == NULL)) {
84 SDL_OutOfMemory();
85 if (this) {
86 SDL_free(this);
87 }
88 return (0);
89 }
90 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
91
92 /* Set the function pointers */
93 this->OpenAudio = Mac_OpenAudio;
94 this->CloseAudio = Mac_CloseAudio;
95 this->LockAudio = Mac_LockAudio;
96 this->UnlockAudio = Mac_UnlockAudio;
97 this->free = Audio_DeleteDevice;
98
99 #ifdef __MACOSX__ /* Mac OS X uses threaded audio, so normal thread code is okay */
100 this->LockAudio = NULL;
101 this->UnlockAudio = NULL;
102 #endif
103 return this;
104 }
105
106 AudioBootStrap SNDMGR_bootstrap = {
107 "sndmgr", "MacOS SoundManager 3.0",
108 Audio_Available, Audio_CreateDevice
109 };
110
111 #if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
112 /* This works correctly on Mac OS X */
113
114 #pragma options align=power 53 #pragma options align=power
115 54
116 static volatile SInt32 audio_is_locked = 0; 55 static volatile SInt32 audio_is_locked = 0;
117 static volatile SInt32 need_to_mix = 0; 56 static volatile SInt32 need_to_mix = 0;
118 57
119 static UInt8 *buffer[2]; 58 static UInt8 *buffer[2];
120 static volatile UInt32 running = 0; 59 static volatile UInt32 running = 0;
121 static CmpSoundHeader header; 60 static CmpSoundHeader header;
122 static volatile Uint32 fill_me = 0; 61 static volatile Uint32 fill_me = 0;
62
123 63
124 static void 64 static void
125 mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer) 65 mix_buffer(SDL_AudioDevice * audio, UInt8 * buffer)
126 { 66 {
127 if (!audio->paused) { 67 if (!audio->paused) {
148 88
149 DecrementAtomic((SInt32 *) & need_to_mix); 89 DecrementAtomic((SInt32 *) & need_to_mix);
150 } 90 }
151 91
152 static void 92 static void
153 Mac_LockAudio(_THIS) 93 SNDMGR_LockDevice(_THIS)
154 { 94 {
155 IncrementAtomic((SInt32 *) & audio_is_locked); 95 IncrementAtomic((SInt32 *) & audio_is_locked);
156 } 96 }
157 97
158 static void 98 static void
159 Mac_UnlockAudio(_THIS) 99 SNDMGR_UnlockDevice(_THIS)
160 { 100 {
161 SInt32 oldval; 101 SInt32 oldval;
162 102
163 oldval = DecrementAtomic((SInt32 *) & audio_is_locked); 103 oldval = DecrementAtomic((SInt32 *) & audio_is_locked);
164 if (oldval != 1) /* != 1 means audio is still locked. */ 104 if (oldval != 1) /* != 1 means audio is still locked. */
196 cmd.cmd = bufferCmd; 136 cmd.cmd = bufferCmd;
197 cmd.param1 = 0; 137 cmd.param1 = 0;
198 cmd.param2 = (long) &header; 138 cmd.param2 = (long) &header;
199 SndDoCommand(chan, &cmd, 0); 139 SndDoCommand(chan, &cmd, 0);
200 140
201 memset(buffer[fill_me], 0, audio->spec.size); 141 SDL_memset(buffer[fill_me], 0, audio->spec.size);
202 142
203 /* 143 /*
204 * if audio device isn't locked, mix the next buffer to be queued in 144 * if audio device isn't locked, mix the next buffer to be queued in
205 * the memory block that just finished playing. 145 * the memory block that just finished playing.
206 */ 146 */
217 SndDoCommand(chan, &cmd, 0); 157 SndDoCommand(chan, &cmd, 0);
218 } 158 }
219 } 159 }
220 160
221 static int 161 static int
222 Mac_OpenAudio(_THIS, SDL_AudioSpec * spec) 162 SNDMGR_OpenDevice(_THIS, const char *devname, int iscapture)
223 { 163 {
224 164 SDL_AudioSpec *spec = &this->spec;
165 SndChannelPtr channel = NULL;
225 SndCallBackUPP callback; 166 SndCallBackUPP callback;
226 int sample_bits; 167 int sample_bits;
227 int i; 168 int i;
228 long initOptions; 169 long initOptions;
229 170
171 /* Initialize all variables that we clean on shutdown */
172 this->hidden = (struct SDL_PrivateAudioData *)
173 SDL_malloc((sizeof *this->hidden));
174 if (this->hidden == NULL) {
175 SDL_OutOfMemory();
176 return 0;
177 }
178 SDL_memset(this->hidden, 0, (sizeof *this->hidden));
179
180 /* !!! FIXME: iterate through format matrix... */
230 /* Very few conversions are required, but... */ 181 /* Very few conversions are required, but... */
231 switch (spec->format) { 182 switch (spec->format) {
232 case AUDIO_S8: 183 case AUDIO_S8:
233 spec->format = AUDIO_U8; 184 spec->format = AUDIO_U8;
234 break; 185 break;
240 break; 191 break;
241 case AUDIO_F32LSB: 192 case AUDIO_F32LSB:
242 spec->format = AUDIO_F32MSB; 193 spec->format = AUDIO_F32MSB;
243 break; 194 break;
244 } 195 }
245 SDL_CalculateAudioSpec(spec); 196 SDL_CalculateAudioSpec(&this->spec);
246 197
247 /* initialize bufferCmd header */ 198 /* initialize bufferCmd header */
248 memset(&header, 0, sizeof(header)); 199 SDL_memset(&header, 0, sizeof(header));
249 callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc); 200 callback = (SndCallBackUPP) NewSndCallBackUPP(callBackProc);
250 sample_bits = spec->size / spec->samples / spec->channels * 8; 201 sample_bits = spec->size / spec->samples / spec->channels * 8;
251 202
252 #ifdef DEBUG_AUDIO 203 #ifdef DEBUG_AUDIO
253 fprintf(stderr, 204 fprintf(stderr,
276 header.format = kFloat32Format; 227 header.format = kFloat32Format;
277 } 228 }
278 229
279 /* allocate 2 buffers */ 230 /* allocate 2 buffers */
280 for (i = 0; i < 2; i++) { 231 for (i = 0; i < 2; i++) {
281 buffer[i] = (UInt8 *) malloc(sizeof(UInt8) * spec->size); 232 buffer[i] = (UInt8 *) SDL_malloc(sizeof(UInt8) * spec->size);
282 if (buffer[i] == NULL) { 233 if (buffer[i] == NULL) {
234 SNDMGR_CloseDevice(this);
283 SDL_OutOfMemory(); 235 SDL_OutOfMemory();
284 return (-1); 236 return 0;
285 } 237 }
286 memset(buffer[i], 0, spec->size); 238 SDL_memset(buffer[i], 0, spec->size);
287 } 239 }
288 240
289 /* Create the sound manager channel */ 241 /* Create the sound manager channel */
290 channel = (SndChannelPtr) SDL_malloc(sizeof(*channel)); 242 channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
291 if (channel == NULL) { 243 if (channel == NULL) {
244 SNDMGR_CloseDevice(this);
292 SDL_OutOfMemory(); 245 SDL_OutOfMemory();
293 return (-1); 246 return 0;
294 } 247 }
248 this->hidden->channel = channel;
295 if (spec->channels >= 2) { 249 if (spec->channels >= 2) {
296 initOptions = initStereo; 250 initOptions = initStereo;
297 } else { 251 } else {
298 initOptions = initMono; 252 initOptions = initMono;
299 } 253 }
300 channel->userInfo = (long) this; 254 channel->userInfo = (long) this;
301 channel->qLength = 128; 255 channel->qLength = 128;
302 if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) { 256 if (SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr) {
257 SNDMGR_CloseDevice(this);
303 SDL_SetError("Unable to create audio channel"); 258 SDL_SetError("Unable to create audio channel");
304 SDL_free(channel); 259 return 0;
305 channel = NULL;
306 return (-1);
307 } 260 }
308 261
309 /* start playback */ 262 /* start playback */
310 { 263 {
311 SndCommand cmd; 264 SndCommand cmd;
317 270
318 return 1; 271 return 1;
319 } 272 }
320 273
321 static void 274 static void
322 Mac_CloseAudio(_THIS) 275 SNDMGR_CloseDevice(_THIS)
323 { 276 {
324
325 int i; 277 int i;
326 278
327 running = 0; 279 running = 0;
328 280
329 if (channel) { 281 if (this->hidden->channel) {
330 SndDisposeChannel(channel, true); 282 SndDisposeChannel(this->hidden->channel, true);
331 channel = NULL; 283 this->hidden->channel = NULL;
332 } 284 }
333 285
334 for (i = 0; i < 2; ++i) { 286 for (i = 0; i < 2; ++i) {
335 if (buffer[i]) { 287 if (buffer[i]) {
336 SDL_free(buffer[i]); 288 SDL_free(buffer[i]);
337 buffer[i] = NULL; 289 buffer[i] = NULL;
338 } 290 }
339 } 291 }
340 } 292 SDL_free(this->hidden);
341 293 this->hidden = NULL;
342 #else /* !TARGET_API_MAC_CARBON && !USE_RYANS_SOUNDCODE */
343
344 static void
345 Mac_LockAudio(_THIS)
346 {
347 /* no-op. */
348 }
349
350 static void
351 Mac_UnlockAudio(_THIS)
352 {
353 /* no-op. */
354 }
355
356
357 /* This function is called by Sound Manager when it has exhausted one of
358 the buffers, so we'll zero it to silence and fill it with audio if
359 we're not paused.
360 */
361 static pascal void
362 sndDoubleBackProc(SndChannelPtr chan, SndDoubleBufferPtr newbuf)
363 {
364 SDL_AudioDevice *audio = (SDL_AudioDevice *) newbuf->dbUserInfo[0];
365
366 /* If audio is quitting, don't do anything */
367 if (!audio->enabled) {
368 return;
369 }
370 memset(newbuf->dbSoundData, 0, audio->spec.size);
371 newbuf->dbNumFrames = audio->spec.samples;
372 if (!audio->paused) {
373 if (audio->convert.needed) {
374 audio->spec.callback(audio->spec.userdata,
375 (Uint8 *) audio->convert.buf,
376 audio->convert.len);
377 SDL_ConvertAudio(&audio->convert);
378 #if 0
379 if (audio->convert.len_cvt != audio->spec.size) {
380 /* Uh oh... probably crashes here */ ;
381 }
382 #endif
383 SDL_memcpy(newbuf->dbSoundData, audio->convert.buf,
384 audio->convert.len_cvt);
385 } else {
386 audio->spec.callback(audio->spec.userdata,
387 (Uint8 *) newbuf->dbSoundData,
388 audio->spec.size);
389 }
390 }
391 newbuf->dbFlags |= dbBufferReady;
392 } 294 }
393 295
394 static int 296 static int
395 DoubleBufferAudio_Available(void) 297 SNDMGR_Init(SDL_AudioDriverImpl *impl)
396 { 298 {
397 int available; 299 /* Set the function pointers */
398 NumVersion sndversion; 300 impl->OpenDevice = SNDMGR_OpenDevice;
399 long response; 301 impl->CloseDevice = SNDMGR_CloseDevice;
400 302 impl->ProvidesOwnCallbackThread = 1;
401 available = 0; 303 impl->OnlyHasDefaultOutputDevice = 1;
402 sndversion = SndSoundManagerVersion(); 304
403 if (sndversion.majorRev >= 3) { 305 /* Mac OS X uses threaded audio, so normal thread code is okay */
404 if (Gestalt(gestaltSoundAttr, &response) == noErr) { 306 #ifndef __MACOSX__
405 if ((response & (1 << gestaltSndPlayDoubleBuffer))) { 307 impl->LockDevice = SNDMGR_LockDevice;
406 available = 1; 308 impl->UnlockDevice = SNDMGR_UnlockDevice;
407 } 309 impl->SkipMixerLock = 1;
408 } 310 #endif
409 } else {
410 if (Gestalt(gestaltSoundAttr, &response) == noErr) {
411 if ((response & (1 << gestaltHasASC))) {
412 available = 1;
413 }
414 }
415 }
416 return (available);
417 }
418
419 static void
420 Mac_CloseAudio(_THIS)
421 {
422 int i;
423
424 if (channel != NULL) {
425 /* Clean up the audio channel */
426 SndDisposeChannel(channel, true);
427 channel = NULL;
428 }
429 for (i = 0; i < 2; ++i) {
430 if (audio_buf[i]) {
431 SDL_free(audio_buf[i]);
432 audio_buf[i] = NULL;
433 }
434 }
435 }
436
437 static int
438 Mac_OpenAudio(_THIS, SDL_AudioSpec * spec)
439 {
440 SndDoubleBufferHeader2 audio_dbh;
441 int i;
442 long initOptions;
443 int sample_bits;
444 SndDoubleBackUPP doubleBackProc;
445
446 /* Check to make sure double-buffered audio is available */
447 if (!DoubleBufferAudio_Available()) {
448 SDL_SetError("Sound manager doesn't support double-buffering");
449 return (-1);
450 }
451
452 /* Very few conversions are required, but... */
453 switch (spec->format) {
454 case AUDIO_S8:
455 spec->format = AUDIO_U8;
456 break;
457 case AUDIO_U16LSB:
458 spec->format = AUDIO_S16LSB;
459 break;
460 case AUDIO_U16MSB:
461 spec->format = AUDIO_S16MSB;
462 break;
463 }
464 SDL_CalculateAudioSpec(spec);
465
466 /* initialize the double-back header */
467 SDL_memset(&audio_dbh, 0, sizeof(audio_dbh));
468 doubleBackProc = NewSndDoubleBackProc(sndDoubleBackProc);
469 sample_bits = spec->size / spec->samples / spec->channels * 8;
470
471 audio_dbh.dbhNumChannels = spec->channels;
472 audio_dbh.dbhSampleSize = sample_bits;
473 audio_dbh.dbhCompressionID = 0;
474 audio_dbh.dbhPacketSize = 0;
475 audio_dbh.dbhSampleRate = spec->freq << 16;
476 audio_dbh.dbhDoubleBack = doubleBackProc;
477 audio_dbh.dbhFormat = 0;
478
479 /* Note that we install the 16bitLittleEndian Converter if needed. */
480 if (spec->format == 0x8010) {
481 audio_dbh.dbhCompressionID = fixedCompression;
482 audio_dbh.dbhFormat = k16BitLittleEndianFormat;
483 }
484
485 /* allocate the 2 double-back buffers */
486 for (i = 0; i < 2; ++i) {
487 audio_buf[i] = SDL_calloc(1, sizeof(SndDoubleBuffer) + spec->size);
488 if (audio_buf[i] == NULL) {
489 SDL_OutOfMemory();
490 return (-1);
491 }
492 audio_buf[i]->dbNumFrames = spec->samples;
493 audio_buf[i]->dbFlags = dbBufferReady;
494 audio_buf[i]->dbUserInfo[0] = (long) this;
495 audio_dbh.dbhBufferPtr[i] = audio_buf[i];
496 }
497
498 /* Create the sound manager channel */
499 channel = (SndChannelPtr) SDL_malloc(sizeof(*channel));
500 if (channel == NULL) {
501 SDL_OutOfMemory();
502 return (-1);
503 }
504 if (spec->channels >= 2) {
505 initOptions = initStereo;
506 } else {
507 initOptions = initMono;
508 }
509 channel->userInfo = 0;
510 channel->qLength = 128;
511 if (SndNewChannel(&channel, sampledSynth, initOptions, 0L) != noErr) {
512 SDL_SetError("Unable to create audio channel");
513 SDL_free(channel);
514 channel = NULL;
515 return (-1);
516 }
517
518 /* Start playback */
519 if (SndPlayDoubleBuffer(channel, (SndDoubleBufferHeaderPtr) & audio_dbh)
520 != noErr) {
521 SDL_SetError("Unable to play double buffered audio");
522 return (-1);
523 }
524 311
525 return 1; 312 return 1;
526 } 313 }
527 314
528 #endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */ 315 AudioBootStrap SNDMGR_bootstrap = {
316 "sndmgr", SDL_MACOS_NAME " SoundManager", SNDMGR_Init, 0
317 };
318
529 /* vi: set ts=4 sw=4 expandtab: */ 319 /* vi: set ts=4 sw=4 expandtab: */