Mercurial > sdl-ios-xcode
diff src/audio/arts/SDL_artsaudio.c @ 3812:35d1367020a3 SDL-ryan-multiple-audio-device
Updated arts driver for 1.3 audio API.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 06 Oct 2006 02:40:02 +0000 |
parents | 7852b5b78af5 |
children | 92f7304e50ff |
line wrap: on
line diff
--- a/src/audio/arts/SDL_artsaudio.c Fri Oct 06 01:13:09 2006 +0000 +++ b/src/audio/arts/SDL_artsaudio.c Fri Oct 06 02:40:02 2006 +0000 @@ -40,11 +40,12 @@ #define ARTS_DRIVER_NAME "arts" /* Audio driver functions */ -static int ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec); -static void ARTS_WaitAudio(_THIS); -static void ARTS_PlayAudio(_THIS); -static Uint8 *ARTS_GetAudioBuf(_THIS); -static void ARTS_CloseAudio(_THIS); +static int ARTS_OpenDevice(_THIS, const char *devname, int iscapture); +static void ARTS_WaitDevice(_THIS); +static void ARTS_PlayDevice(_THIS); +static Uint8 *ARTS_GetDeviceBuf(_THIS); +static void ARTS_CloseDevice(_THIS); +static void ARTS_WaitDone(_THIS); #ifdef SDL_AUDIO_DRIVER_ARTS_DYNAMIC @@ -52,6 +53,7 @@ static void *arts_handle = NULL; static int arts_loaded = 0; +/* !!! FIXME: I hate this SDL_NAME clutter...it makes everything so messy! */ static int (*SDL_NAME(arts_init)) (void); static void (*SDL_NAME(arts_free)) (void); static arts_stream_t(*SDL_NAME(arts_play_stream)) (int rate, int bits, @@ -64,20 +66,25 @@ static int (*SDL_NAME(arts_write)) (arts_stream_t s, const void *buffer, int count); static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); +static void (*SDL_NAME(arts_close_stream)) (arts_stream_t s); +static const char *(*SDL_NAME(arts_error_text)) (int errorcode); +#define SDL_ARTS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) } static struct { const char *name; void **func; } arts_functions[] = { - { - "arts_init", (void **) &SDL_NAME(arts_init)}, { - "arts_free", (void **) &SDL_NAME(arts_free)}, { - "arts_play_stream", (void **) &SDL_NAME(arts_play_stream)}, { - "arts_stream_set", (void **) &SDL_NAME(arts_stream_set)}, { - "arts_stream_get", (void **) &SDL_NAME(arts_stream_get)}, { - "arts_write", (void **) &SDL_NAME(arts_write)}, { -"arts_close_stream", (void **) &SDL_NAME(arts_close_stream)},}; + SDL_ARTS_SYM(arts_init), + SDL_ARTS_SYM(arts_free), + SDL_ARTS_SYM(arts_play_stream), + SDL_ARTS_SYM(arts_stream_set), + SDL_ARTS_SYM(arts_stream_get), + SDL_ARTS_SYM(arts_write), + SDL_ARTS_SYM(arts_close_stream), + SDL_ARTS_SYM(arts_error_text), +}; +#undef SDL_ARTS_SYM static void UnloadARTSLibrary() @@ -94,20 +101,23 @@ { int i, retval = -1; - arts_handle = SDL_LoadObject(arts_library); - if (arts_handle) { - arts_loaded = 1; - retval = 0; - for (i = 0; i < SDL_arraysize(arts_functions); ++i) { - *arts_functions[i].func = - SDL_LoadFunction(arts_handle, arts_functions[i].name); - if (!*arts_functions[i].func) { - retval = -1; - UnloadARTSLibrary(); - break; + if (!arts_loaded) { + arts_handle = SDL_LoadObject(arts_library); + if (arts_handle) { + arts_loaded = 1; + retval = 0; + for (i = 0; i < SDL_arraysize(arts_functions); ++i) { + *arts_functions[i].func = + SDL_LoadFunction(arts_handle, arts_functions[i].name); + if (!*arts_functions[i].func) { + retval = -1; + UnloadARTSLibrary(); + break; + } } } } + return retval; } @@ -130,114 +140,90 @@ /* Audio driver bootstrap functions */ static int -Audio_Available(void) +ARTS_Available(void) { int available = 0; - if (LoadARTSLibrary() < 0) { - return available; - } - if (SDL_NAME(arts_init) () == 0) { + if (LoadARTSLibrary() == 0) { + if (SDL_NAME(arts_init) () == 0) { #define ARTS_CRASH_HACK /* Play a stream so aRts doesn't crash */ #ifdef ARTS_CRASH_HACK - arts_stream_t stream2; - stream2 = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL"); - SDL_NAME(arts_write) (stream2, "", 0); - SDL_NAME(arts_close_stream) (stream2); + arts_stream_t stream; + stream = SDL_NAME(arts_play_stream) (44100, 16, 2, "SDL"); + SDL_NAME(arts_write) (stream, "", 0); + SDL_NAME(arts_close_stream) (stream); #endif - available = 1; - SDL_NAME(arts_free) (); + available = 1; + SDL_NAME(arts_free) (); + } + UnloadARTSLibrary(); } - UnloadARTSLibrary(); return available; } -static void -Audio_DeleteDevice(SDL_AudioDevice * device) + +static int +ARTS_Init(SDL_AudioDriverImpl *impl) { - SDL_free(device->hidden); - SDL_free(device); - UnloadARTSLibrary(); + /* Set the function pointers */ + impl->OpenDevice = ARTS_OpenDevice; + impl->PlayDevice = ARTS_PlayDevice; + impl->WaitDevice = ARTS_WaitDevice; + impl->GetDeviceBuf = ARTS_GetDeviceBuf; + impl->CloseDevice = ARTS_CloseDevice; + impl->WaitDone = ARTS_WaitDone; + impl->OnlyHasDefaultOutputDevice = 1; + + return 1; } -static SDL_AudioDevice * -Audio_CreateDevice(int devindex) -{ - SDL_AudioDevice *this; - - /* Initialize all variables that we clean on shutdown */ - LoadARTSLibrary(); - this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice)); - if (this) { - SDL_memset(this, 0, (sizeof *this)); - this->hidden = (struct SDL_PrivateAudioData *) - SDL_malloc((sizeof *this->hidden)); - } - if ((this == NULL) || (this->hidden == NULL)) { - SDL_OutOfMemory(); - if (this) { - SDL_free(this); - } - return (0); - } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); - stream = 0; - - /* Set the function pointers */ - this->OpenAudio = ARTS_OpenAudio; - this->WaitAudio = ARTS_WaitAudio; - this->PlayAudio = ARTS_PlayAudio; - this->GetAudioBuf = ARTS_GetAudioBuf; - this->CloseAudio = ARTS_CloseAudio; - - this->free = Audio_DeleteDevice; - - return this; -} AudioBootStrap ARTS_bootstrap = { - ARTS_DRIVER_NAME, "Analog Realtime Synthesizer", - Audio_Available, Audio_CreateDevice, 0 + ARTS_DRIVER_NAME, "Analog RealTime Synthesizer", + ARTS_Available, ARTS_Init, 0 }; + /* This function waits until it is possible to write a full sound buffer */ static void -ARTS_WaitAudio(_THIS) +ARTS_WaitDevice(_THIS) { Sint32 ticks; /* Check to see if the thread-parent process is still alive */ { static int cnt = 0; - /* Note that this only works with thread implementations + /* Note that this only works with thread implementations that use a different process id for each thread. */ - if (parent && (((++cnt) % 10) == 0)) { /* Check every 10 loops */ - if (kill(parent, 0) < 0) { + /* Check every 10 loops */ + if (this->hidden->parent && (((++cnt) % 10) == 0)) { + if (kill(this->hidden->parent, 0) < 0) { this->enabled = 0; } } } /* Use timer for general audio synchronization */ - ticks = ((Sint32) (next_frame - SDL_GetTicks())) - FUDGE_TICKS; + ticks = ((Sint32) (this->hidden->next_frame-SDL_GetTicks())) - FUDGE_TICKS; if (ticks > 0) { SDL_Delay(ticks); } } static void -ARTS_PlayAudio(_THIS) +ARTS_PlayDevice(_THIS) { - int written; - /* Write the audio data */ - written = SDL_NAME(arts_write) (stream, mixbuf, mixlen); + int written = SDL_NAME(arts_write) ( + this->hidden->stream, + this->hidden->mixbuf, + this->hidden->mixlen); /* If timer synchronization is enabled, set the next write frame */ - if (frame_ticks) { - next_frame += frame_ticks; + if (this->hidden->frame_ticks) { + this->hidden->next_frame += this->hidden->frame_ticks; } /* If we couldn't write, assume fatal error for now */ @@ -249,41 +235,66 @@ #endif } -static Uint8 * -ARTS_GetAudioBuf(_THIS) +static void +ARTS_WaitDone(_THIS) { - return (mixbuf); + /* !!! FIXME: camp here until buffer drains... SDL_Delay(???); */ } + +static Uint8 * +ARTS_GetDeviceBuf(_THIS) +{ + return (this->hidden->mixbuf); +} + + static void -ARTS_CloseAudio(_THIS) +ARTS_CloseDevice(_THIS) { - if (mixbuf != NULL) { - SDL_FreeAudioMem(mixbuf); - mixbuf = NULL; + if (this->hidden != NULL) { + if (this->hidden->mixbuf != NULL) { + SDL_FreeAudioMem(this->hidden->mixbuf); + this->hidden->mixbuf = NULL; + } + if (this->hidden->stream) { + SDL_NAME(arts_close_stream) (this->hidden->stream); + this->hidden->stream = 0; + } + SDL_NAME(arts_free) (); + SDL_free(this->hidden); + this->hidden = NULL; } - if (stream) { - SDL_NAME(arts_close_stream) (stream); - stream = 0; - } - SDL_NAME(arts_free) (); + UnloadARTSLibrary(); } + static int -ARTS_OpenAudio(_THIS, SDL_AudioSpec * spec) +ARTS_OpenDevice(_THIS, const char *devname, int iscapture) { + int rc = 0; int bits, frag_spec; SDL_AudioFormat test_format, format; - /* Reset the timer synchronization flag */ - frame_ticks = 0.0; + /* Initialize all variables that we clean on shutdown */ + this->hidden = (struct SDL_PrivateAudioData *) + SDL_malloc((sizeof *this->hidden)); + if (this->hidden == NULL) { + SDL_OutOfMemory(); + return 0; + } + SDL_memset(this->hidden, 0, (sizeof *this->hidden)); - mixbuf = NULL; + if (LoadARTSLibrary() < 0) { + ARTS_CloseDevice(this); + SDL_SetError("ARTS: failed to load library: %s", SDL_GetError()); + return 0; + } /* Try for a closest match on audio format */ format = 0; bits = 0; - for (test_format = SDL_FirstAudioFormat(spec->format); + for (test_format = SDL_FirstAudioFormat(this->spec.format); !format && test_format;) { #ifdef DEBUG_AUDIO fprintf(stderr, "Trying format 0x%4.4x\n", test_format); @@ -306,51 +317,62 @@ } } if (format == 0) { + ARTS_CloseDevice(this); SDL_SetError("Couldn't find any hardware audio formats"); - return (-1); + return 0; } - spec->format = test_format; + this->spec.format = test_format; - if (SDL_NAME(arts_init) () != 0) { - SDL_SetError("Unable to initialize ARTS"); - return (-1); + if ((rc = SDL_NAME(arts_init) ()) != 0) { + ARTS_CloseDevice(this); + SDL_SetError( "Unable to initialize ARTS: %s", + SDL_NAME(arts_error_text)(rc) ); + return 0; } - stream = - SDL_NAME(arts_play_stream) (spec->freq, bits, spec->channels, "SDL"); + this->hidden->stream = SDL_NAME(arts_play_stream) ( + this->spec.freq, + bits, this->spec.channels, + "SDL"); /* Calculate the final parameters for this audio specification */ - SDL_CalculateAudioSpec(spec); + SDL_CalculateAudioSpec(&this->spec); /* Determine the power of two of the fragment size */ - for (frag_spec = 0; (0x01 << frag_spec) < spec->size; ++frag_spec); - if ((0x01 << frag_spec) != spec->size) { + for (frag_spec = 0; (0x01 << frag_spec) < this->spec.size; ++frag_spec); + if ((0x01 << frag_spec) != this->spec.size) { + ARTS_CloseDevice(this); SDL_SetError("Fragment size must be a power of two"); - return (-1); + return 0; } frag_spec |= 0x00020000; /* two fragments, for low latency */ #ifdef ARTS_P_PACKET_SETTINGS - SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SETTINGS, frag_spec); + SDL_NAME(arts_stream_set) (this->hidden->stream, + ARTS_P_PACKET_SETTINGS, frag_spec); #else - SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_SIZE, + SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_SIZE, frag_spec & 0xffff); - SDL_NAME(arts_stream_set) (stream, ARTS_P_PACKET_COUNT, frag_spec >> 16); + SDL_NAME(arts_stream_set) (this->hidden->stream, ARTS_P_PACKET_COUNT, + frag_spec >> 16); #endif - spec->size = SDL_NAME(arts_stream_get) (stream, ARTS_P_PACKET_SIZE); + this->spec.size = SDL_NAME(arts_stream_get) (this->hidden->stream, + ARTS_P_PACKET_SIZE); /* Allocate mixing buffer */ - mixlen = spec->size; - mixbuf = (Uint8 *) SDL_AllocAudioMem(mixlen); - if (mixbuf == NULL) { - return (-1); + this->hidden->mixlen = this->spec.size; + this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); + if (this->hidden->mixbuf == NULL) { + ARTS_CloseDevice(this); + SDL_OutOfMemory(); + return 0; } - SDL_memset(mixbuf, spec->silence, spec->size); + SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size); /* Get the parent process id (we're the parent of the audio thread) */ - parent = getpid(); + this->hidden->parent = getpid(); /* We're ready to rock and roll. :-) */ - return (0); + return 1; } /* vi: set ts=4 sw=4 expandtab: */