comparison src/audio/macrom/SDL_romaudio.c @ 323:b7e8038e40ae

The audio lock and unlock functions are now a part of the driver. The MacOS audio locking has been implemented, courtesy of Ryan Gordon
author Sam Lantinga <slouken@libsdl.org>
date Sat, 30 Mar 2002 20:03:27 +0000
parents f6ffac90895c
children f25f666d609a
comparison
equal deleted inserted replaced
322:fd93a09655e3 323:b7e8038e40ae
28 #if TARGET_API_MAC_CARBON 28 #if TARGET_API_MAC_CARBON
29 # include <Carbon.h> 29 # include <Carbon.h>
30 #else 30 #else
31 # include <Sound.h> /* SoundManager interface */ 31 # include <Sound.h> /* SoundManager interface */
32 # include <Gestalt.h> 32 # include <Gestalt.h>
33 # include <DriverServices.h>
33 #endif 34 #endif
34 35
35 #include <stdlib.h> 36 #include <stdlib.h>
36 #include <stdio.h> 37 #include <stdio.h>
37 38
44 45
45 /* Audio driver functions */ 46 /* Audio driver functions */
46 47
47 static void Mac_CloseAudio(_THIS); 48 static void Mac_CloseAudio(_THIS);
48 static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec); 49 static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec);
50 static void Mac_LockAudio(_THIS);
51 static void Mac_UnlockAudio(_THIS);
49 52
50 /* Audio driver bootstrap functions */ 53 /* Audio driver bootstrap functions */
51 54
52 55
53 static int Audio_Available(void) 56 static int Audio_Available(void)
82 memset(this->hidden, 0, (sizeof *this->hidden)); 85 memset(this->hidden, 0, (sizeof *this->hidden));
83 86
84 /* Set the function pointers */ 87 /* Set the function pointers */
85 this->OpenAudio = Mac_OpenAudio; 88 this->OpenAudio = Mac_OpenAudio;
86 this->CloseAudio = Mac_CloseAudio; 89 this->CloseAudio = Mac_CloseAudio;
90 this->LockAudio = Mac_LockAudio;
91 this->UnlockAudio = Mac_UnlockAudio;
87 this->free = Audio_DeleteDevice; 92 this->free = Audio_DeleteDevice;
88 93
89 return this; 94 return this;
90 } 95 }
91 96
92 AudioBootStrap SNDMGR_bootstrap = { 97 AudioBootStrap SNDMGR_bootstrap = {
93 "sndmgr", "MacOS SoundManager 3.0", 98 "sndmgr", "MacOS SoundManager 3.0",
94 Audio_Available, Audio_CreateDevice 99 Audio_Available, Audio_CreateDevice
95 }; 100 };
96 101
97 #if TARGET_API_MAC_CARBON 102 #if defined(TARGET_API_MAC_CARBON) || defined(USE_RYANS_SOUNDCODE)
103 /* FIXME: Does this work correctly on MacOS X as well? */
104
105 #pragma options align=power
106
107 static volatile SInt32 audio_is_locked = 0;
108 static volatile SInt32 need_to_mix = 0;
98 109
99 static UInt8 *buffer[2]; 110 static UInt8 *buffer[2];
100 static volatile UInt32 running = 0; 111 static volatile UInt32 running = 0;
101 static CmpSoundHeader header; 112 static CmpSoundHeader header;
102 113 static volatile Uint32 fill_me = 0;
103 static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) { 114
104 115 static void mix_buffer(SDL_AudioDevice *audio, UInt8 *buffer)
105 UInt32 fill_me, play_me; 116 {
106 SndCommand cmd;
107 SDL_AudioDevice *audio = (SDL_AudioDevice *)chan->userInfo;
108
109 fill_me = cmd_passed->param2; /* buffer that has just finished playing, so fill it */
110 play_me = ! fill_me; /* filled buffer to play _now_ */
111
112 if ( ! audio->enabled ) {
113 return;
114 }
115
116 header.samplePtr = (Ptr)buffer[play_me];
117
118 cmd.cmd = bufferCmd;
119 cmd.param1 = 0;
120 cmd.param2 = (long)&header;
121
122 SndDoCommand (chan, &cmd, 0);
123
124 memset (buffer[fill_me], 0, audio->spec.size);
125
126 if ( ! audio->paused ) { 117 if ( ! audio->paused ) {
127 if ( audio->convert.needed ) { 118 if ( audio->convert.needed ) {
128 #if MACOSX
129 SDL_mutexP(audio->mixer_lock);
130 #endif
131 audio->spec.callback(audio->spec.userdata, 119 audio->spec.callback(audio->spec.userdata,
132 (Uint8 *)audio->convert.buf,audio->convert.len); 120 (Uint8 *)audio->convert.buf,audio->convert.len);
133 #if MACOSX
134 SDL_mutexV(audio->mixer_lock);
135 #endif
136 SDL_ConvertAudio(&audio->convert); 121 SDL_ConvertAudio(&audio->convert);
137 #if 0 122 #if 0
138 if ( audio->convert.len_cvt != audio->spec.size ) { 123 if ( audio->convert.len_cvt != audio->spec.size ) {
139 /* Uh oh... probably crashes here; */ 124 /* Uh oh... probably crashes here; */
140 } 125 }
141 #endif 126 #endif
142 memcpy(buffer[fill_me], audio->convert.buf, 127 memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
143 audio->convert.len_cvt);
144 } else { 128 } else {
145 #if MACOSX 129 audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
146 SDL_mutexP(audio->mixer_lock); 130 }
147 #endif 131 }
148 audio->spec.callback(audio->spec.userdata, 132
149 (Uint8 *)buffer[fill_me], audio->spec.size); 133 DecrementAtomic((SInt32 *) &need_to_mix);
150 #if MACOSX 134 }
151 SDL_mutexV(audio->mixer_lock); 135
152 #endif 136 static void Mac_LockAudio(_THIS)
153 } 137 {
154 } 138 IncrementAtomic((SInt32 *) &audio_is_locked);
155 139 }
156 if ( running ) { 140
141 static void Mac_UnlockAudio(_THIS)
142 {
143 SInt32 oldval;
157 144
145 oldval = DecrementAtomic((SInt32 *) &audio_is_locked);
146 if ( oldval != 1 ) /* != 1 means audio is still locked. */
147 return;
148
149 /* Did we miss the chance to mix in an interrupt? Do it now. */
150 if ( BitAndAtomic (0xFFFFFFFF, &need_to_mix) ) {
151 /*
152 * Note that this could be a problem if you missed an interrupt
153 * while the audio was locked, and get preempted by a second
154 * interrupt here, but that means you locked for way too long anyhow.
155 */
156 mix_buffer (this, buffer[fill_me]);
157 }
158 }
159
160 static void callBackProc (SndChannel *chan, SndCommand *cmd_passed ) {
161 UInt32 play_me;
162 SndCommand cmd;
163 SDL_AudioDevice *audio = (SDL_AudioDevice *)chan->userInfo;
164
165 IncrementAtomic((SInt32 *) &need_to_mix);
166
167 fill_me = cmd_passed->param2; /* buffer that has just finished playing, so fill it */
168 play_me = ! fill_me; /* filled buffer to play _now_ */
169
170 if ( ! audio->enabled ) {
171 return;
172 }
173
174 /* queue previously mixed buffer for playback. */
175 header.samplePtr = (Ptr)buffer[play_me];
176 cmd.cmd = bufferCmd;
177 cmd.param1 = 0;
178 cmd.param2 = (long)&header;
179 SndDoCommand (chan, &cmd, 0);
180
181 memset (buffer[fill_me], 0, audio->spec.size);
182
183 /*
184 * if audio device isn't locked, mix the next buffer to be queued in
185 * the memory block that just finished playing.
186 */
187 if ( ! BitAndAtomic(0xFFFFFFFF, &audio_is_locked) ) {
188 mix_buffer (audio, buffer[fill_me]);
189 }
190
191 /* set this callback to run again when current buffer drains. */
192 if ( running ) {
158 cmd.cmd = callBackCmd; 193 cmd.cmd = callBackCmd;
159 cmd.param1 = 0; 194 cmd.param1 = 0;
160 cmd.param2 = play_me; 195 cmd.param2 = play_me;
161 196
162 SndDoCommand (chan, &cmd, 0); 197 SndDoCommand (chan, &cmd, 0);
163 } 198 }
164
165 } 199 }
166 200
167 static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) { 201 static int Mac_OpenAudio(_THIS, SDL_AudioSpec *spec) {
168 202
169 SndCallBackUPP callback; 203 SndCallBackUPP callback;
170 int sample_bits; 204 int sample_bits;
171 int i; 205 int i;
172 long initOptions; 206 long initOptions;
173 207
174 /* Very few conversions are required, but... */ 208 /* Very few conversions are required, but... */
175 switch (spec->format) { 209 switch (spec->format) {
176 case AUDIO_S8: 210 case AUDIO_S8:
177 spec->format = AUDIO_U8; 211 spec->format = AUDIO_U8;
178 break; 212 break;
229 } else { 263 } else {
230 initOptions = initMono; 264 initOptions = initMono;
231 } 265 }
232 channel->userInfo = (long)this; 266 channel->userInfo = (long)this;
233 channel->qLength = 128; 267 channel->qLength = 128;
234 if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) != 268 if ( SndNewChannel(&channel, sampledSynth, initOptions, callback) != noErr ) {
235 noErr ) {
236 SDL_SetError("Unable to create audio channel"); 269 SDL_SetError("Unable to create audio channel");
237 free(channel); 270 free(channel);
238 channel = NULL; 271 channel = NULL;
239 return(-1); 272 return(-1);
240 } 273 }
268 buffer[i] = NULL; 301 buffer[i] = NULL;
269 } 302 }
270 } 303 }
271 } 304 }
272 305
273 #else /* !TARGET_API_MAC_CARBON */ 306 #else /* !TARGET_API_MAC_CARBON && !USE_RYANS_SOUNDCODE */
307
308 static void Mac_LockAudio(_THIS)
309 {
310 /* no-op. */
311 }
312
313 static void Mac_UnlockAudio(_THIS)
314 {
315 /* no-op. */
316 }
317
274 318
275 /* This function is called by Sound Manager when it has exhausted one of 319 /* This function is called by Sound Manager when it has exhausted one of
276 the buffers, so we'll zero it to silence and fill it with audio if 320 the buffers, so we'll zero it to silence and fill it with audio if
277 we're not paused. 321 we're not paused.
278 */ 322 */
334 static void Mac_CloseAudio(_THIS) 378 static void Mac_CloseAudio(_THIS)
335 { 379 {
336 int i; 380 int i;
337 381
338 if ( channel != NULL ) { 382 if ( channel != NULL ) {
339 #if 0
340 SCStatus status;
341
342 /* Wait for audio to complete */
343 do {
344 SndChannelStatus(channel, sizeof(status), &status);
345 } while ( status.scChannelBusy );
346 #endif
347 /* Clean up the audio channel */ 383 /* Clean up the audio channel */
348 SndDisposeChannel(channel, true); 384 SndDisposeChannel(channel, true);
349 channel = NULL; 385 channel = NULL;
350 } 386 }
351 for ( i=0; i<2; ++i ) { 387 for ( i=0; i<2; ++i ) {
444 } 480 }
445 481
446 return 1; 482 return 1;
447 } 483 }
448 484
449 #endif /* TARGET_API_MAC_CARBON */ 485 #endif /* TARGET_API_MAC_CARBON || USE_RYANS_SOUNDCODE */
450 486
451