comparison src/audio/amigaos/SDL_audio.c @ 0:74212992fb08

Initial revision
author Sam Lantinga <slouken@lokigames.com>
date Thu, 26 Apr 2001 16:45:43 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:74212992fb08
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Sam Lantinga
20 slouken@devolution.com
21 */
22
23 #ifdef SAVE_RCSID
24 static char rcsid =
25 "@(#) $Id$";
26 #endif
27
28 /* Allow access to a raw mixing buffer */
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <signal.h>
32 #include <string.h>
33
34 #include "SDL.h"
35 #include "SDL_audio.h"
36 #include "SDL_timer.h"
37 #include "SDL_error.h"
38 #include "SDL_audio_c.h"
39 #include "SDL_audiomem.h"
40 #include "SDL_sysaudio.h"
41
42
43 /* Available audio drivers */
44 static AudioBootStrap *bootstrap[] = {
45 #ifdef unix
46 &AUDIO_bootstrap,
47 #endif
48 #ifdef linux
49 &DMA_bootstrap,
50 #endif
51 #ifdef ESD_SUPPORT
52 &ESD_bootstrap,
53 #endif
54 #ifdef ENABLE_DIRECTX
55 &DSOUND_bootstrap,
56 #endif
57 #ifdef ENABLE_WINDIB
58 &WAVEOUT_bootstrap,
59 #endif
60 #ifdef __BEOS__
61 &BAUDIO_bootstrap,
62 #endif
63 #ifdef macintosh
64 &AUDIO_bootstrap,
65 #endif
66 #ifdef _AIX
67 &Paud_bootstrap,
68 #endif
69 #ifdef ENABLE_CYBERGRAPHICS
70 &AHI_bootstrap,
71 #endif
72 NULL
73 };
74 SDL_AudioDevice *current_audio = NULL;
75
76 /* Various local functions */
77 int SDL_AudioInit(const char *driver_name);
78 void SDL_AudioQuit(void);
79
80 struct SignalSemaphore AudioSem;
81
82 /* The general mixing thread function */
83 int RunAudio(void *audiop)
84 {
85 SDL_AudioDevice *audio = (SDL_AudioDevice *)audiop;
86 Uint8 *stream;
87 int stream_len;
88 void *udata;
89 void (*fill)(void *userdata,Uint8 *stream, int len);
90 int silence,started=0;
91
92 D(bug("Task audio started audio struct:<%lx>...\n",audiop));
93
94 D(bug("Before Openaudio..."));
95 if(audio->OpenAudio(audio, &audio->spec)==-1)
96 {
97 return(-1);
98 }
99
100 D(bug("OpenAudio...OK\n"));
101
102 /* Perform any thread setup */
103 if ( audio->ThreadInit ) {
104 audio->ThreadInit(audio);
105 }
106 audio->threadid = SDL_ThreadID();
107
108 /* Set up the mixing function */
109 fill = audio->spec.callback;
110 udata = audio->spec.userdata;
111 if ( audio->convert.needed ) {
112 if ( audio->convert.src_format == AUDIO_U8 ) {
113 silence = 0x80;
114 D(bug("*** Silence 0x80 ***\n"));
115 } else {
116 silence = 0;
117 }
118 stream_len = audio->convert.len;
119 } else {
120 silence = audio->spec.silence;
121 stream_len = audio->spec.size;
122 }
123 stream = audio->fake_stream;
124
125 ObtainSemaphore(&AudioSem);
126 ReleaseSemaphore(&AudioSem);
127
128 D(bug("Enering audio loop...\n"));
129
130 D(if(audio->convert.needed)bug("*** Conversion needed.\n"));
131
132 /* Loop, filling the audio buffers */
133 while ( audio->enabled )
134 {
135 /* Wait for new current buffer to finish playing */
136
137 if ( stream == audio->fake_stream )
138 SDL_Delay((audio->spec.samples*1000)/audio->spec.freq);
139 else
140 {
141 if(started>1)
142 {
143 // D(bug("Waiting audio...\n"));
144 audio->WaitAudio(audio);
145 }
146 }
147
148 ObtainSemaphore(&AudioSem);
149
150 /* Fill the current buffer with sound */
151 if ( audio->convert.needed ) {
152 stream = audio->convert.buf;
153 } else {
154 stream = audio->GetAudioBuf(audio);
155 }
156
157 if(stream!=audio->fake_stream)
158 memset(stream, silence, stream_len);
159
160 if ( ! audio->paused ) {
161 ObtainSemaphore(&audio->mixer_lock);
162 (*fill)(udata, stream, stream_len);
163 ReleaseSemaphore(&audio->mixer_lock);
164 }
165
166 /* Convert the audio if necessary */
167 if ( audio->convert.needed ) {
168 SDL_ConvertAudio(&audio->convert);
169 stream = audio->GetAudioBuf(audio);
170 memcpy(stream, audio->convert.buf,audio->convert.len_cvt);
171 }
172
173 if(stream!=audio->fake_stream)
174 {
175 // D(bug("Playing stream at %lx\n",stream));
176
177 audio->PlayAudio(audio);
178 started++;
179 }
180 ReleaseSemaphore(&AudioSem);
181
182 }
183 D(bug("Out of subtask loop...\n"));
184
185 /* Wait for the audio to drain.. */
186 if ( audio->WaitDone ) {
187 audio->WaitDone(audio);
188 }
189
190 D(bug("WaitAudio...Done\n"));
191
192 audio->CloseAudio(audio);
193
194 D(bug("CloseAudio..Done, subtask exiting...\n"));
195
196 return(0);
197 }
198
199 int SDL_AudioInit(const char *driver_name)
200 {
201 SDL_AudioDevice *audio;
202 int i = 0, idx;
203
204 /* Check to make sure we don't overwrite 'current_audio' */
205 if ( current_audio != NULL ) {
206 SDL_AudioQuit();
207 }
208
209 /* Select the proper audio driver */
210 audio = NULL;
211 idx = 0;
212
213 InitSemaphore(&AudioSem);
214
215 if ( audio == NULL ) {
216 if ( driver_name != NULL ) {
217 if ( strrchr(driver_name, ':') != NULL ) {
218 idx = atoi(strrchr(driver_name, ':')+1);
219 }
220 for ( i=0; bootstrap[i]; ++i ) {
221 if (strncmp(bootstrap[i]->name, driver_name,
222 strlen(bootstrap[i]->name)) == 0) {
223 if ( bootstrap[i]->available() ) {
224 audio=bootstrap[i]->create(idx);
225 break;
226 }
227 }
228 }
229 } else {
230 for ( i=0; bootstrap[i]; ++i ) {
231 if ( bootstrap[i]->available() ) {
232 audio = bootstrap[i]->create(idx);
233 if ( audio != NULL ) {
234 break;
235 }
236 }
237 }
238 }
239 if ( audio == NULL ) {
240 SDL_SetError("No available audio device");
241 #if 0 /* Don't fail SDL_Init() if audio isn't available.
242 SDL_OpenAudio() will handle it at that point. *sigh*
243 */
244 return(-1);
245 #endif
246 }
247 }
248 current_audio = audio;
249 if ( current_audio ) {
250 current_audio->name = bootstrap[i]->name;
251 }
252 return(0);
253 }
254
255 char *SDL_AudioDriverName(char *namebuf, int maxlen)
256 {
257 if ( current_audio != NULL ) {
258 strncpy(namebuf, current_audio->name, maxlen-1);
259 namebuf[maxlen-1] = '\0';
260 return(namebuf);
261 }
262 return(NULL);
263 }
264
265 int SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
266 {
267 SDL_AudioDevice *audio;
268
269 /* Start up the audio driver, if necessary */
270 if ( ! current_audio ) {
271 if ( (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) ||
272 (current_audio == NULL) ) {
273 return(-1);
274 }
275 }
276 audio = current_audio;
277
278 D(bug("Chiamata SDL_OpenAudio...\n"));
279
280 /* Verify some parameters */
281 if ( desired->callback == NULL ) {
282 SDL_SetError("SDL_OpenAudio() passed a NULL callback");
283 return(-1);
284 }
285 switch ( desired->channels ) {
286 case 1: /* Mono */
287 case 2: /* Stereo */
288 break;
289 default:
290 SDL_SetError("1 (mono) and 2 (stereo) channels supported");
291 return(-1);
292 }
293
294 /* Create a semaphore for locking the sound buffers */
295 InitSemaphore(&audio->mixer_lock);
296
297 /* Calculate the silence and size of the audio specification */
298 SDL_CalculateAudioSpec(desired);
299
300 /* Open the audio subsystem */
301 memcpy(&audio->spec, desired, sizeof(audio->spec));
302 audio->convert.needed = 0;
303 audio->enabled = 1;
304 audio->paused = 1;
305
306 ObtainSemaphore(&AudioSem);
307
308 audio->thread = SDL_CreateThread(RunAudio, audio);
309
310 if ( audio->thread == NULL ) {
311 ReleaseSemaphore(&AudioSem);
312 SDL_CloseAudio();
313 SDL_SetError("Couldn't create audio thread");
314 return(-1);
315 }
316
317 /* If the audio driver changes the buffer size, accept it */
318 if ( audio->spec.samples != desired->samples ) {
319 desired->samples = audio->spec.samples;
320 SDL_CalculateAudioSpec(desired);
321 }
322
323 /* Allocate a fake audio memory buffer */
324 audio->fake_stream = SDL_AllocAudioMem(audio->spec.size);
325 if ( audio->fake_stream == NULL ) {
326 ReleaseSemaphore(&AudioSem);
327 SDL_CloseAudio();
328 SDL_OutOfMemory();
329 return(-1);
330 }
331
332 /* See if we need to do any conversion */
333 if ( memcmp(desired, &audio->spec, sizeof(audio->spec)) == 0 ) {
334 /* Just copy over the desired audio specification */
335 if ( obtained != NULL ) {
336 memcpy(obtained, &audio->spec, sizeof(audio->spec));
337 }
338 } else {
339 /* Copy over the audio specification if possible */
340 if ( obtained != NULL ) {
341 memcpy(obtained, &audio->spec, sizeof(audio->spec));
342 } else {
343 /* Build an audio conversion block */
344 D(bug("Need conversion:\n desired: C:%ld F:%ld T:%lx\navailable: C:%ld F:%ld T:%lx\n",
345 desired->channels, desired->freq, desired->format,
346 audio->spec.channels,audio->spec.freq,audio->spec.format));
347
348 Forbid();
349
350 // Magari poi lo sostiutisco con un semaforo.
351
352 if ( SDL_BuildAudioCVT(&audio->convert,
353 desired->format, desired->channels,
354 desired->freq,
355 audio->spec.format, audio->spec.channels,
356 audio->spec.freq) < 0 ) {
357 ReleaseSemaphore(&AudioSem);
358 SDL_CloseAudio();
359 return(-1);
360 }
361 if ( audio->convert.needed ) {
362 audio->convert.len = desired->size;
363 audio->convert.buf =(Uint8 *)SDL_AllocAudioMem(
364 audio->convert.len*audio->convert.len_mult);
365 if ( audio->convert.buf == NULL ) {
366 ReleaseSemaphore(&AudioSem);
367 SDL_CloseAudio();
368 SDL_OutOfMemory();
369 return(-1);
370 }
371 }
372 }
373 }
374
375 ReleaseSemaphore(&AudioSem);
376
377 D(bug("SDL_OpenAudio USCITA...\n"));
378
379 return(0);
380 }
381
382 SDL_audiostatus SDL_GetAudioStatus(void)
383 {
384 SDL_AudioDevice *audio = current_audio;
385 SDL_audiostatus status;
386
387 status = SDL_AUDIO_STOPPED;
388 if ( audio && audio->enabled ) {
389 if ( audio->paused ) {
390 status = SDL_AUDIO_PAUSED;
391 } else {
392 status = SDL_AUDIO_PLAYING;
393 }
394 }
395 return(status);
396 }
397
398 void SDL_PauseAudio (int pause_on)
399 {
400 SDL_AudioDevice *audio = current_audio;
401
402 if ( audio ) {
403 audio->paused = pause_on;
404 }
405 }
406
407 void SDL_LockAudio (void)
408 {
409 SDL_AudioDevice *audio = current_audio;
410
411 /* Obtain a lock on the mixing buffers */
412 if ( audio ) {
413 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
414 return;
415 }
416 ObtainSemaphore(&audio->mixer_lock);
417 }
418 }
419
420 void SDL_UnlockAudio (void)
421 {
422 SDL_AudioDevice *audio = current_audio;
423
424 /* Release lock on the mixing buffers */
425 if ( audio ) {
426 if ( audio->thread && (SDL_ThreadID() == audio->threadid) ) {
427 return;
428 }
429 ReleaseSemaphore(&audio->mixer_lock);
430 }
431 }
432
433 void SDL_CloseAudio (void)
434 {
435 SDL_AudioDevice *audio = current_audio;
436
437 if ( audio ) {
438 if(audio->enabled)
439 {
440 audio->enabled = 0;
441
442 if ( audio->thread != NULL ) {
443 D(bug("Waiting audio thread...\n"));
444 SDL_WaitThread(audio->thread, NULL);
445 D(bug("...audio replied\n"));
446 }
447 }
448
449 if ( audio->fake_stream != NULL ) {
450 SDL_FreeAudioMem(audio->fake_stream);
451 audio->fake_stream=NULL;
452 }
453 if ( audio->convert.needed && current_audio->convert.buf!=NULL) {
454 SDL_FreeAudioMem(audio->convert.buf);
455 current_audio->convert.buf=NULL;
456 }
457 }
458 SDL_QuitSubSystem(SDL_INIT_AUDIO);
459 }
460
461 void SDL_AudioQuit(void)
462 {
463 if ( current_audio ) {
464 if(current_audio->enabled)
465 {
466 D(bug("Closing audio in AudioQuit...\n"));
467 current_audio->enabled = 0;
468
469 if ( current_audio->thread != NULL ) {
470 D(bug("Waiting audio thread...\n"));
471 SDL_WaitThread(current_audio->thread, NULL);
472 D(bug("...audio replied\n"));
473 }
474 }
475 if ( current_audio->fake_stream != NULL ) {
476 SDL_FreeAudioMem(current_audio->fake_stream);
477 }
478 if ( current_audio->convert.needed &&
479 current_audio->convert.buf) {
480 SDL_FreeAudioMem(current_audio->convert.buf);
481 }
482
483 current_audio->free(current_audio);
484 current_audio = NULL;
485 }
486 }
487
488 #define NUM_FORMATS 6
489 static int format_idx;
490 static int format_idx_sub;
491 static Uint16 format_list[NUM_FORMATS][NUM_FORMATS] = {
492 { AUDIO_U8, AUDIO_S8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
493 { AUDIO_S8, AUDIO_U8, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB },
494 { AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_U8, AUDIO_S8 },
495 { AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_U8, AUDIO_S8 },
496 { AUDIO_U16LSB, AUDIO_U16MSB, AUDIO_S16LSB, AUDIO_S16MSB, AUDIO_U8, AUDIO_S8 },
497 { AUDIO_U16MSB, AUDIO_U16LSB, AUDIO_S16MSB, AUDIO_S16LSB, AUDIO_U8, AUDIO_S8 },
498 };
499
500 Uint16 SDL_FirstAudioFormat(Uint16 format)
501 {
502 for ( format_idx=0; format_idx < NUM_FORMATS; ++format_idx ) {
503 if ( format_list[format_idx][0] == format ) {
504 break;
505 }
506 }
507 format_idx_sub = 0;
508 return(SDL_NextAudioFormat());
509 }
510
511 Uint16 SDL_NextAudioFormat(void)
512 {
513 if ( (format_idx == NUM_FORMATS) || (format_idx_sub == NUM_FORMATS) ) {
514 return(0);
515 }
516 return(format_list[format_idx][format_idx_sub++]);
517 }
518
519 void SDL_CalculateAudioSpec(SDL_AudioSpec *spec)
520 {
521 switch (spec->format) {
522 case AUDIO_U8:
523 spec->silence = 0x80;
524 break;
525 default:
526 spec->silence = 0x00;
527 break;
528 }
529 spec->size = (spec->format&0xFF)/8;
530 spec->size *= spec->channels;
531 spec->size *= spec->samples;
532 }