From 0420181d59e56e0dfd46d6f0a7966144545938f1 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 26 Oct 2019 06:18:02 +0200 Subject: [PATCH] Add built-in SDL_sound r599 This commit contains several files imported from SDL_sound Mercurial repo: https://hg.icculus.org/icculus/SDL_sound/ r599 (also tagged as "final-lgpl-revision"). --- src/libs/decoders/SDL_sound.c | 895 +++++++++++++++++++++++++ src/libs/decoders/SDL_sound.h | 737 ++++++++++++++++++++ src/libs/decoders/SDL_sound_internal.h | 334 +++++++++ src/libs/decoders/audio_convert.c | 735 ++++++++++++++++++++ src/libs/decoders/docs/CREDITS.txt | 67 ++ src/libs/decoders/docs/LICENSE.txt | 528 +++++++++++++++ 6 files changed, 3296 insertions(+) create mode 100644 src/libs/decoders/SDL_sound.c create mode 100644 src/libs/decoders/SDL_sound.h create mode 100644 src/libs/decoders/SDL_sound_internal.h create mode 100644 src/libs/decoders/audio_convert.c create mode 100644 src/libs/decoders/docs/CREDITS.txt create mode 100644 src/libs/decoders/docs/LICENSE.txt diff --git a/src/libs/decoders/SDL_sound.c b/src/libs/decoders/SDL_sound.c new file mode 100644 index 00000000..2422f9ca --- /dev/null +++ b/src/libs/decoders/SDL_sound.c @@ -0,0 +1,895 @@ +/* + * SDL_sound -- An abstract sound format decoding API. + * Copyright (C) 2001 Ryan C. Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * This file implements the core API, which is relatively simple. + * The real meat of SDL_sound is in the decoders directory. + * + * Documentation is in SDL_sound.h ... It's verbose, honest. :) + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. (icculus@icculus.org) + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "SDL.h" +#include "SDL_thread.h" +#include "SDL_sound.h" + +#define __SDL_SOUND_INTERNAL__ +#include "SDL_sound_internal.h" + + +/* The various decoder drivers... */ + +/* All these externs may be missing; we check SOUND_SUPPORTS_xxx before use. */ +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MPG123; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MIKMOD; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MODPLUG; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_AIFF; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_AU; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_OGG; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_VOC; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_RAW; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SHN; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_MIDI; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_FLAC; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_QuickTime; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_SPEEX; +extern const Sound_DecoderFunctions __Sound_DecoderFunctions_CoreAudio; + +typedef struct +{ + int available; + const Sound_DecoderFunctions *funcs; +} decoder_element; + +static decoder_element decoders[] = +{ +#if (defined SOUND_SUPPORTS_MPG123) + { 0, &__Sound_DecoderFunctions_MPG123 }, +#endif + +#if (defined SOUND_SUPPORTS_MODPLUG) + { 0, &__Sound_DecoderFunctions_MODPLUG }, +#endif + +#if (defined SOUND_SUPPORTS_MIKMOD) + { 0, &__Sound_DecoderFunctions_MIKMOD }, +#endif + +#if (defined SOUND_SUPPORTS_WAV) + { 0, &__Sound_DecoderFunctions_WAV }, +#endif + +#if (defined SOUND_SUPPORTS_AIFF) + { 0, &__Sound_DecoderFunctions_AIFF }, +#endif + +#if (defined SOUND_SUPPORTS_AU) + { 0, &__Sound_DecoderFunctions_AU }, +#endif + +#if (defined SOUND_SUPPORTS_OGG) + { 0, &__Sound_DecoderFunctions_OGG }, +#endif + +#if (defined SOUND_SUPPORTS_VOC) + { 0, &__Sound_DecoderFunctions_VOC }, +#endif + +#if (defined SOUND_SUPPORTS_RAW) + { 0, &__Sound_DecoderFunctions_RAW }, +#endif + +#if (defined SOUND_SUPPORTS_SHN) + { 0, &__Sound_DecoderFunctions_SHN }, +#endif + +#if (defined SOUND_SUPPORTS_FLAC) + { 0, &__Sound_DecoderFunctions_FLAC }, +#endif + +#if (defined SOUND_SUPPORTS_MIDI) + { 0, &__Sound_DecoderFunctions_MIDI }, +#endif + +#if (defined SOUND_SUPPORTS_QUICKTIME) + { 0, &__Sound_DecoderFunctions_QuickTime }, +#endif + +#if (defined SOUND_SUPPORTS_SPEEX) + { 0, &__Sound_DecoderFunctions_SPEEX }, +#endif + +#if (defined SOUND_SUPPORTS_COREAUDIO) + { 0, &__Sound_DecoderFunctions_CoreAudio }, +#endif + + { 0, NULL } +}; + + + +/* General SDL_sound state ... */ + +typedef struct __SOUND_ERRMSGTYPE__ +{ + Uint32 tid; + int error_available; + char error_string[128]; + struct __SOUND_ERRMSGTYPE__ *next; +} ErrMsg; + +static ErrMsg *error_msgs = NULL; +static SDL_mutex *errorlist_mutex = NULL; + +static Sound_Sample *sample_list = NULL; /* this is a linked list. */ +static SDL_mutex *samplelist_mutex = NULL; + +static const Sound_DecoderInfo **available_decoders = NULL; +static int initialized = 0; + + +/* functions ... */ + +void Sound_GetLinkedVersion(Sound_Version *ver) +{ + if (ver != NULL) + { + ver->major = SOUND_VER_MAJOR; + ver->minor = SOUND_VER_MINOR; + ver->patch = SOUND_VER_PATCH; + } /* if */ +} /* Sound_GetLinkedVersion */ + + +int Sound_Init(void) +{ + size_t i; + size_t pos = 0; + size_t total = sizeof (decoders) / sizeof (decoders[0]); + BAIL_IF_MACRO(initialized, ERR_IS_INITIALIZED, 0); + + sample_list = NULL; + error_msgs = NULL; + + available_decoders = (const Sound_DecoderInfo **) + malloc((total) * sizeof (Sound_DecoderInfo *)); + BAIL_IF_MACRO(available_decoders == NULL, ERR_OUT_OF_MEMORY, 0); + + SDL_InitSubSystem(SDL_INIT_AUDIO); + + errorlist_mutex = SDL_CreateMutex(); + samplelist_mutex = SDL_CreateMutex(); + + for (i = 0; decoders[i].funcs != NULL; i++) + { + decoders[i].available = decoders[i].funcs->init(); + if (decoders[i].available) + { + available_decoders[pos] = &(decoders[i].funcs->info); + pos++; + } /* if */ + } /* for */ + + available_decoders[pos] = NULL; + + initialized = 1; + return(1); +} /* Sound_Init */ + + +int Sound_Quit(void) +{ + ErrMsg *err; + ErrMsg *nexterr = NULL; + size_t i; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + + while (((volatile Sound_Sample *) sample_list) != NULL) + Sound_FreeSample(sample_list); + + initialized = 0; + + SDL_DestroyMutex(samplelist_mutex); + samplelist_mutex = NULL; + sample_list = NULL; + + for (i = 0; decoders[i].funcs != NULL; i++) + { + if (decoders[i].available) + { + decoders[i].funcs->quit(); + decoders[i].available = 0; + } /* if */ + } /* for */ + + if (available_decoders != NULL) + free((void *) available_decoders); + available_decoders = NULL; + + /* clean up error state for each thread... */ + SDL_LockMutex(errorlist_mutex); + for (err = error_msgs; err != NULL; err = nexterr) + { + nexterr = err->next; + free(err); + } /* for */ + error_msgs = NULL; + SDL_UnlockMutex(errorlist_mutex); + SDL_DestroyMutex(errorlist_mutex); + errorlist_mutex = NULL; + + return(1); +} /* Sound_Quit */ + + +const Sound_DecoderInfo **Sound_AvailableDecoders(void) +{ + return(available_decoders); /* READ. ONLY. */ +} /* Sound_AvailableDecoders */ + + +static ErrMsg *findErrorForCurrentThread(void) +{ + ErrMsg *i; + Uint32 tid; + + if (error_msgs != NULL) + { + tid = SDL_ThreadID(); + + SDL_LockMutex(errorlist_mutex); + for (i = error_msgs; i != NULL; i = i->next) + { + if (i->tid == tid) + { + SDL_UnlockMutex(errorlist_mutex); + return(i); + } /* if */ + } /* for */ + SDL_UnlockMutex(errorlist_mutex); + } /* if */ + + return(NULL); /* no error available. */ +} /* findErrorForCurrentThread */ + + +const char *Sound_GetError(void) +{ + const char *retval = NULL; + ErrMsg *err; + + if (!initialized) + return(ERR_NOT_INITIALIZED); + + err = findErrorForCurrentThread(); + if ((err != NULL) && (err->error_available)) + { + retval = err->error_string; + err->error_available = 0; + } /* if */ + + return(retval); +} /* Sound_GetError */ + + +void Sound_ClearError(void) +{ + ErrMsg *err; + + if (!initialized) + return; + + err = findErrorForCurrentThread(); + if (err != NULL) + err->error_available = 0; +} /* Sound_ClearError */ + + +/* + * This is declared in the internal header. + */ +void __Sound_SetError(const char *str) +{ + ErrMsg *err; + + if (str == NULL) + return; + + SNDDBG(("__Sound_SetError(\"%s\");%s\n", str, + (initialized) ? "" : " [NOT INITIALIZED!]")); + + if (!initialized) + return; + + err = findErrorForCurrentThread(); + if (err == NULL) + { + err = (ErrMsg *) malloc(sizeof (ErrMsg)); + if (err == NULL) + return; /* uhh...? */ + + memset((void *) err, '\0', sizeof (ErrMsg)); + err->tid = SDL_ThreadID(); + + SDL_LockMutex(errorlist_mutex); + err->next = error_msgs; + error_msgs = err; + SDL_UnlockMutex(errorlist_mutex); + } /* if */ + + err->error_available = 1; + strncpy(err->error_string, str, sizeof (err->error_string)); + err->error_string[sizeof (err->error_string) - 1] = '\0'; +} /* __Sound_SetError */ + + +Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms) +{ + /* "frames" == "sample frames" */ + float frames_per_ms = ((float) info->rate) / 1000.0f; + Uint32 frame_offset = (Uint32) (frames_per_ms * ((float) ms)); + Uint32 frame_size = (Uint32) ((info->format & 0xFF) / 8) * info->channels; + return(frame_offset * frame_size); +} /* __Sound_convertMsToBytePos */ + + +/* + * -ansi and -pedantic flags prevent use of strcasecmp() on Linux, and + * I honestly don't want to mess around with figuring out if a given + * platform has "strcasecmp", "stricmp", or + * "compare_two_damned_strings_case_insensitive", which I hear is in the + * next release of Carbon. :) This is exported so decoders may use it if + * they like. + */ +int __Sound_strcasecmp(const char *x, const char *y) +{ + int ux, uy; + + if (x == y) /* same pointer? Both NULL? */ + return(0); + + if (x == NULL) + return(-1); + + if (y == NULL) + return(1); + + do + { + ux = toupper((int) *x); + uy = toupper((int) *y); + if (ux > uy) + return(1); + else if (ux < uy) + return(-1); + x++; + y++; + } while ((ux) && (uy)); + + return(0); +} /* __Sound_strcasecmp */ + + +/* + * Allocate a Sound_Sample, and fill in most of its fields. Those that need + * to be filled in later, by a decoder, will be initialized to zero. + */ +static Sound_Sample *alloc_sample(SDL_RWops *rw, Sound_AudioInfo *desired, + Uint32 bufferSize) +{ + /* + * !!! FIXME: We're going to need to pool samples, since the mixer + * !!! FIXME: might be allocating tons of these on a regular basis. + */ + Sound_Sample *retval = malloc(sizeof (Sound_Sample)); + Sound_SampleInternal *internal = malloc(sizeof (Sound_SampleInternal)); + if ((retval == NULL) || (internal == NULL)) + { + __Sound_SetError(ERR_OUT_OF_MEMORY); + if (retval) + free(retval); + if (internal) + free(internal); + + return(NULL); + } /* if */ + + memset(retval, '\0', sizeof (Sound_Sample)); + memset(internal, '\0', sizeof (Sound_SampleInternal)); + + assert(bufferSize > 0); + retval->buffer = malloc(bufferSize); /* pure ugly. */ + if (!retval->buffer) + { + __Sound_SetError(ERR_OUT_OF_MEMORY); + free(internal); + free(retval); + return(NULL); + } /* if */ + memset(retval->buffer, '\0', bufferSize); + retval->buffer_size = bufferSize; + + if (desired != NULL) + memcpy(&retval->desired, desired, sizeof (Sound_AudioInfo)); + + internal->rw = rw; + retval->opaque = internal; + return(retval); +} /* alloc_sample */ + + +#if (defined DEBUG_CHATTER) +static __inline__ const char *fmt_to_str(Uint16 fmt) +{ + switch(fmt) + { + case AUDIO_U8: + return("U8"); + case AUDIO_S8: + return("S8"); + case AUDIO_U16LSB: + return("U16LSB"); + case AUDIO_S16LSB: + return("S16LSB"); + case AUDIO_U16MSB: + return("U16MSB"); + case AUDIO_S16MSB: + return("S16MSB"); + } /* switch */ + + return("Unknown"); +} /* fmt_to_str */ +#endif + + +/* + * The bulk of the Sound_NewSample() work is done here... + * Ask the specified decoder to handle the data in (rw), and if + * so, construct the Sound_Sample. Otherwise, try to wind (rw)'s stream + * back to where it was, and return false. + */ +static int init_sample(const Sound_DecoderFunctions *funcs, + Sound_Sample *sample, const char *ext, + Sound_AudioInfo *_desired) +{ + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + Sound_AudioInfo desired; + int pos = SDL_RWtell(internal->rw); + + /* fill in the funcs for this decoder... */ + sample->decoder = &funcs->info; + internal->funcs = funcs; + if (!funcs->open(sample, ext)) + { + SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ + return(0); + } /* if */ + + /* success; we've got a decoder! */ + + /* Now we need to set up the conversion buffer... */ + + memcpy(&desired, (_desired != NULL) ? _desired : &sample->actual, + sizeof (Sound_AudioInfo)); + + if (desired.format == 0) + desired.format = sample->actual.format; + if (desired.channels == 0) + desired.channels = sample->actual.channels; + if (desired.rate == 0) + desired.rate = sample->actual.rate; + + if (Sound_BuildAudioCVT(&internal->sdlcvt, + sample->actual.format, + sample->actual.channels, + sample->actual.rate, + desired.format, + desired.channels, + desired.rate, + sample->buffer_size) == -1) + { + __Sound_SetError(SDL_GetError()); + funcs->close(sample); + SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ + return(0); + } /* if */ + + if (internal->sdlcvt.len_mult > 1) + { + void *rc = realloc(sample->buffer, + sample->buffer_size * internal->sdlcvt.len_mult); + if (rc == NULL) + { + funcs->close(sample); + SDL_RWseek(internal->rw, pos, SEEK_SET); /* set for next try... */ + return(0); + } /* if */ + + sample->buffer = rc; + } /* if */ + + /* these pointers are all one and the same. */ + memcpy(&sample->desired, &desired, sizeof (Sound_AudioInfo)); + internal->sdlcvt.buf = internal->buffer = sample->buffer; + internal->buffer_size = sample->buffer_size / internal->sdlcvt.len_mult; + internal->sdlcvt.len = internal->buffer_size; + + /* Prepend our new Sound_Sample to the sample_list... */ + SDL_LockMutex(samplelist_mutex); + internal->next = sample_list; + if (sample_list != NULL) + ((Sound_SampleInternal *) sample_list->opaque)->prev = sample; + sample_list = sample; + SDL_UnlockMutex(samplelist_mutex); + + SNDDBG(("New sample DESIRED format: %s format, %d rate, %d channels.\n", + fmt_to_str(sample->desired.format), + sample->desired.rate, + sample->desired.channels)); + + SNDDBG(("New sample ACTUAL format: %s format, %d rate, %d channels.\n", + fmt_to_str(sample->actual.format), + sample->actual.rate, + sample->actual.channels)); + + SNDDBG(("On-the-fly conversion: %s.\n", + internal->sdlcvt.needed ? "ENABLED" : "DISABLED")); + + return(1); +} /* init_sample */ + + +Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext, + Sound_AudioInfo *desired, Uint32 bSize) +{ + Sound_Sample *retval; + decoder_element *decoder; + + /* sanity checks. */ + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); + BAIL_IF_MACRO(rw == NULL, ERR_INVALID_ARGUMENT, NULL); + + retval = alloc_sample(rw, desired, bSize); + if (!retval) + return(NULL); /* alloc_sample() sets error message... */ + + if (ext != NULL) + { + for (decoder = &decoders[0]; decoder->funcs != NULL; decoder++) + { + if (decoder->available) + { + const char **decoderExt = decoder->funcs->info.extensions; + while (*decoderExt) + { + if (__Sound_strcasecmp(*decoderExt, ext) == 0) + { + if (init_sample(decoder->funcs, retval, ext, desired)) + return(retval); + break; /* done with this decoder either way. */ + } /* if */ + decoderExt++; + } /* while */ + } /* if */ + } /* for */ + } /* if */ + + /* no direct extension match? Try everything we've got... */ + for (decoder = &decoders[0]; decoder->funcs != NULL; decoder++) + { + if (decoder->available) + { + int should_try = 1; + const char **decoderExt = decoder->funcs->info.extensions; + + /* skip if we would have tried decoder above... */ + while (*decoderExt) + { + if (__Sound_strcasecmp(*decoderExt, ext) == 0) + { + should_try = 0; + break; + } /* if */ + decoderExt++; + } /* while */ + + if (should_try) + { + if (init_sample(decoder->funcs, retval, ext, desired)) + return(retval); + } /* if */ + } /* if */ + } /* for */ + + /* nothing could handle the sound data... */ + free(retval->opaque); + if (retval->buffer != NULL) + free(retval->buffer); + free(retval); + SDL_RWclose(rw); + __Sound_SetError(ERR_UNSUPPORTED_FORMAT); + return(NULL); +} /* Sound_NewSample */ + + +Sound_Sample *Sound_NewSampleFromFile(const char *filename, + Sound_AudioInfo *desired, + Uint32 bufferSize) +{ + const char *ext; + SDL_RWops *rw; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); + BAIL_IF_MACRO(filename == NULL, ERR_INVALID_ARGUMENT, NULL); + + ext = strrchr(filename, '.'); + rw = SDL_RWFromFile(filename, "rb"); + /* !!! FIXME: rw = RWops_FromFile(filename, "rb");*/ + BAIL_IF_MACRO(rw == NULL, SDL_GetError(), NULL); + + if (ext != NULL) + ext++; + + return(Sound_NewSample(rw, ext, desired, bufferSize)); +} /* Sound_NewSampleFromFile */ + + +Sound_Sample *Sound_NewSampleFromMem(const Uint8 *data, + Uint32 size, + const char *ext, + Sound_AudioInfo *desired, + Uint32 bufferSize) +{ + SDL_RWops *rw; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, NULL); + BAIL_IF_MACRO(data == NULL, ERR_INVALID_ARGUMENT, NULL); + BAIL_IF_MACRO(size == 0, ERR_INVALID_ARGUMENT, NULL); + + rw = SDL_RWFromMem(data, size); + /* !!! FIXME: rw = RWops_FromMem(data, size);*/ + BAIL_IF_MACRO(rw == NULL, SDL_GetError(), NULL); + + return(Sound_NewSample(rw, ext, desired, bufferSize)); +} /* Sound_NewSampleFromMem */ + + +void Sound_FreeSample(Sound_Sample *sample) +{ + Sound_SampleInternal *internal; + + if (!initialized) + { + __Sound_SetError(ERR_NOT_INITIALIZED); + return; + } /* if */ + + if (sample == NULL) + { + __Sound_SetError(ERR_INVALID_ARGUMENT); + return; + } /* if */ + + internal = (Sound_SampleInternal *) sample->opaque; + + SDL_LockMutex(samplelist_mutex); + + /* update the sample_list... */ + if (internal->prev != NULL) + { + Sound_SampleInternal *prevInternal; + prevInternal = (Sound_SampleInternal *) internal->prev->opaque; + prevInternal->next = internal->next; + } /* if */ + else + { + assert(sample_list == sample); + sample_list = internal->next; + } /* else */ + + if (internal->next != NULL) + { + Sound_SampleInternal *nextInternal; + nextInternal = (Sound_SampleInternal *) internal->next->opaque; + nextInternal->prev = internal->prev; + } /* if */ + + SDL_UnlockMutex(samplelist_mutex); + + /* nuke it... */ + internal->funcs->close(sample); + + if (internal->rw != NULL) /* this condition is a "just in case" thing. */ + SDL_RWclose(internal->rw); + + if ((internal->buffer != NULL) && (internal->buffer != sample->buffer)) + free(internal->buffer); + + free(internal); + + if (sample->buffer != NULL) + free(sample->buffer); + + free(sample); +} /* Sound_FreeSample */ + + +int Sound_SetBufferSize(Sound_Sample *sample, Uint32 newSize) +{ + void *newBuf = NULL; + Sound_SampleInternal *internal = NULL; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0); + internal = ((Sound_SampleInternal *) sample->opaque); + newBuf = realloc(sample->buffer, newSize * internal->sdlcvt.len_mult); + BAIL_IF_MACRO(newBuf == NULL, ERR_OUT_OF_MEMORY, 0); + + internal->sdlcvt.buf = internal->buffer = sample->buffer = newBuf; + sample->buffer_size = newSize; + internal->buffer_size = newSize / internal->sdlcvt.len_mult; + internal->sdlcvt.len = internal->buffer_size; + + return(1); +} /* Sound_SetBufferSize */ + + +Uint32 Sound_Decode(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = NULL; + Uint32 retval = 0; + + /* a boatload of sanity checks... */ + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + BAIL_IF_MACRO(sample == NULL, ERR_INVALID_ARGUMENT, 0); + BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0); + BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0); + + internal = (Sound_SampleInternal *) sample->opaque; + + assert(sample->buffer != NULL); + assert(sample->buffer_size > 0); + assert(internal->buffer != NULL); + assert(internal->buffer_size > 0); + + /* reset EAGAIN. Decoder can flip it back on if it needs to. */ + sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; + retval = internal->funcs->read(sample); + + if (retval > 0 && internal->sdlcvt.needed) + { + internal->sdlcvt.len = retval; + Sound_ConvertAudio(&internal->sdlcvt); + retval = internal->sdlcvt.len_cvt; + } /* if */ + + return(retval); +} /* Sound_Decode */ + + +Uint32 Sound_DecodeAll(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = NULL; + void *buf = NULL; + Uint32 newBufSize = 0; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_EOF, ERR_PREV_EOF, 0); + BAIL_IF_MACRO(sample->flags & SOUND_SAMPLEFLAG_ERROR, ERR_PREV_ERROR, 0); + + internal = (Sound_SampleInternal *) sample->opaque; + + while ( ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) && + ((sample->flags & SOUND_SAMPLEFLAG_ERROR) == 0) ) + { + Uint32 br = Sound_Decode(sample); + void *ptr = realloc(buf, newBufSize + br); + if (ptr == NULL) + { + sample->flags |= SOUND_SAMPLEFLAG_ERROR; + __Sound_SetError(ERR_OUT_OF_MEMORY); + } /* if */ + else + { + buf = ptr; + memcpy( ((char *) buf) + newBufSize, sample->buffer, br ); + newBufSize += br; + } /* else */ + } /* while */ + + if (buf == NULL) /* ...in case first call to realloc() fails... */ + return(sample->buffer_size); + + if (internal->buffer != sample->buffer) + free(internal->buffer); + + free(sample->buffer); + + internal->sdlcvt.buf = internal->buffer = sample->buffer = buf; + sample->buffer_size = newBufSize; + internal->buffer_size = newBufSize / internal->sdlcvt.len_mult; + internal->sdlcvt.len = internal->buffer_size; + + return(newBufSize); +} /* Sound_DecodeAll */ + + +int Sound_Rewind(Sound_Sample *sample) +{ + Sound_SampleInternal *internal; + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + + internal = (Sound_SampleInternal *) sample->opaque; + if (!internal->funcs->rewind(sample)) + { + sample->flags |= SOUND_SAMPLEFLAG_ERROR; + return(0); + } /* if */ + + sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; + sample->flags &= ~SOUND_SAMPLEFLAG_ERROR; + sample->flags &= ~SOUND_SAMPLEFLAG_EOF; + + return(1); +} /* Sound_Rewind */ + + +int Sound_Seek(Sound_Sample *sample, Uint32 ms) +{ + Sound_SampleInternal *internal; + + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, 0); + if (!(sample->flags & SOUND_SAMPLEFLAG_CANSEEK)) + BAIL_MACRO(ERR_CANNOT_SEEK, 0); + + internal = (Sound_SampleInternal *) sample->opaque; + BAIL_IF_MACRO(!internal->funcs->seek(sample, ms), NULL, 0); + + sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; + sample->flags &= ~SOUND_SAMPLEFLAG_ERROR; + sample->flags &= ~SOUND_SAMPLEFLAG_EOF; + + return(1); +} /* Sound_Rewind */ + + +Sint32 Sound_GetDuration(Sound_Sample *sample) +{ + Sound_SampleInternal *internal; + BAIL_IF_MACRO(!initialized, ERR_NOT_INITIALIZED, -1); + internal = (Sound_SampleInternal *) sample->opaque; + return(internal->total_time); +} /* Sound_GetDuration */ + +/* end of SDL_sound.c ... */ + diff --git a/src/libs/decoders/SDL_sound.h b/src/libs/decoders/SDL_sound.h new file mode 100644 index 00000000..7004a03c --- /dev/null +++ b/src/libs/decoders/SDL_sound.h @@ -0,0 +1,737 @@ +/** \file SDL_sound.h */ + +/* + * SDL_sound -- An abstract sound format decoding API. + * Copyright (C) 2001 Ryan C. Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/** + * \mainpage SDL_sound + * + * The latest version of SDL_sound can be found at: + * http://icculus.org/SDL_sound/ + * + * The basic gist of SDL_sound is that you use an SDL_RWops to get sound data + * into this library, and SDL_sound will take that data, in one of several + * popular formats, and decode it into raw waveform data in the format of + * your choice. This gives you a nice abstraction for getting sound into your + * game or application; just feed it to SDL_sound, and it will handle + * decoding and converting, so you can just pass it to your SDL audio + * callback (or whatever). Since it gets data from an SDL_RWops, you can get + * the initial sound data from any number of sources: file, memory buffer, + * network connection, etc. + * + * As the name implies, this library depends on SDL: Simple Directmedia Layer, + * which is a powerful, free, and cross-platform multimedia library. It can + * be found at http://www.libsdl.org/ + * + * Support is in place or planned for the following sound formats: + * - .WAV (Microsoft WAVfile RIFF data, internal.) + * - .VOC (Creative Labs' Voice format, internal.) + * - .MP3 (MPEG-1 Layer 3 support, via libmpg123.) + * - .MID (MIDI music converted to Waveform data, internal.) + * - .MOD (MOD files, via MikMod and ModPlug.) + * - .OGG (Ogg files, via Ogg Vorbis libraries.) + * - .SPX (Speex files, via libspeex.) + * - .SHN (Shorten files, internal.) + * - .RAW (Raw sound data in any format, internal.) + * - .AU (Sun's Audio format, internal.) + * - .AIFF (Audio Interchange format, internal.) + * - .FLAC (Lossless audio compression, via libFLAC.) + * + * (...and more to come...) + * + * Please see the file LICENSE.txt in the source's root directory. + * + * \author Ryan C. Gordon (icculus@icculus.org) + * \author many others, please see CREDITS in the source's root directory. + */ + +#ifndef _INCLUDE_SDL_SOUND_H_ +#define _INCLUDE_SDL_SOUND_H_ + +#include "SDL.h" +#include "SDL_endian.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DOXYGEN_SHOULD_IGNORE_THIS + +#ifndef SDLCALL /* may not be defined with older SDL releases. */ +#define SDLCALL +#endif + +#ifdef SDL_SOUND_DLL_EXPORTS +# define SNDDECLSPEC __declspec(dllexport) +#elif (__GNUC__ >= 3) +# define SNDDECLSPEC __attribute__((visibility("default"))) +#else +# define SNDDECLSPEC +#endif + +#define SOUND_VER_MAJOR 1 +#define SOUND_VER_MINOR 0 +#define SOUND_VER_PATCH 1 +#endif + + +/** + * \enum Sound_SampleFlags + * \brief Flags that are used in a Sound_Sample to show various states. + * + * To use: + * \code + * if (sample->flags & SOUND_SAMPLEFLAG_ERROR) { dosomething(); } + * \endcode + * + * \sa Sound_SampleNew + * \sa Sound_SampleNewFromFile + * \sa Sound_SampleDecode + * \sa Sound_SampleDecodeAll + * \sa Sound_SampleSeek + */ +typedef enum +{ + SOUND_SAMPLEFLAG_NONE = 0, /**< No special attributes. */ + + /* these are set at sample creation time... */ + SOUND_SAMPLEFLAG_CANSEEK = 1, /**< Sample can seek to arbitrary points. */ + + /* these are set during decoding... */ + SOUND_SAMPLEFLAG_EOF = 1 << 29, /**< End of input stream. */ + SOUND_SAMPLEFLAG_ERROR = 1 << 30, /**< Unrecoverable error. */ + SOUND_SAMPLEFLAG_EAGAIN = 1 << 31 /**< Function would block, or temp error. */ +} Sound_SampleFlags; + + +/** + * \struct Sound_AudioInfo + * \brief Information about an existing sample's format. + * + * These are the basics of a decoded sample's data structure: data format + * (see AUDIO_U8 and friends in SDL_audio.h), number of channels, and sample + * rate. If you need more explanation than that, you should stop developing + * sound code right now. + * + * \sa Sound_SampleNew + * \sa Sound_SampleNewFromFile + */ +typedef struct +{ + Uint16 format; /**< Equivalent of SDL_AudioSpec.format. */ + Uint8 channels; /**< Number of sound channels. 1 == mono, 2 == stereo. */ + Uint32 rate; /**< Sample rate; frequency of sample points per second. */ +} Sound_AudioInfo; + + +/** + * \struct Sound_DecoderInfo + * \brief Information about available soudn decoders. + * + * Each decoder sets up one of these structs, which can be retrieved via + * the Sound_AvailableDecoders() function. EVERY FIELD IN THIS IS READ-ONLY. + * + * The extensions field is a NULL-terminated list of ASCIZ strings. You + * should read it like this: + * + * \code + * const char **ext; + * for (ext = info->extensions; *ext != NULL; ext++) { + * printf(" File extension \"%s\"\n", *ext); + * } + * \endcode + * + * \sa Sound_AvailableDecoders + */ +typedef struct +{ + const char **extensions; /**< File extensions, list ends with NULL. */ + const char *description; /**< Human readable description of decoder. */ + const char *author; /**< "Name Of Author \" */ + const char *url; /**< URL specific to this decoder. */ +} Sound_DecoderInfo; + + + +/** + * \struct Sound_Sample + * \brief Represents sound data in the process of being decoded. + * + * The Sound_Sample structure is the heart of SDL_sound. This holds + * information about a source of sound data as it is being decoded. + * EVERY FIELD IN THIS IS READ-ONLY. Please use the API functions to + * change them. + */ +typedef struct +{ + void *opaque; /**< Internal use only. Don't touch. */ + const Sound_DecoderInfo *decoder; /**< Decoder used for this sample. */ + Sound_AudioInfo desired; /**< Desired audio format for conversion. */ + Sound_AudioInfo actual; /**< Actual audio format of sample. */ + void *buffer; /**< Decoded sound data lands in here. */ + Uint32 buffer_size; /**< Current size of (buffer), in bytes (Uint8). */ + Sound_SampleFlags flags; /**< Flags relating to this sample. */ +} Sound_Sample; + + +/** + * \struct Sound_Version + * \brief Information the version of SDL_sound in use. + * + * Represents the library's version as three levels: major revision + * (increments with massive changes, additions, and enhancements), + * minor revision (increments with backwards-compatible changes to the + * major revision), and patchlevel (increments with fixes to the minor + * revision). + * + * \sa SOUND_VERSION + * \sa Sound_GetLinkedVersion + */ +typedef struct +{ + int major; /**< major revision */ + int minor; /**< minor revision */ + int patch; /**< patchlevel */ +} Sound_Version; + + +/* functions and macros... */ + +/** + * \def SOUND_VERSION(x) + * \brief Macro to determine SDL_sound version program was compiled against. + * + * This macro fills in a Sound_Version structure with the version of the + * library you compiled against. This is determined by what header the + * compiler uses. Note that if you dynamically linked the library, you might + * have a slightly newer or older version at runtime. That version can be + * determined with Sound_GetLinkedVersion(), which, unlike SOUND_VERSION, + * is not a macro. + * + * \param x A pointer to a Sound_Version struct to initialize. + * + * \sa Sound_Version + * \sa Sound_GetLinkedVersion + */ +#define SOUND_VERSION(x) \ +{ \ + (x)->major = SOUND_VER_MAJOR; \ + (x)->minor = SOUND_VER_MINOR; \ + (x)->patch = SOUND_VER_PATCH; \ +} + + +/** + * \fn void Sound_GetLinkedVersion(Sound_Version *ver) + * \brief Get the version of SDL_sound that is linked against your program. + * + * If you are using a shared library (DLL) version of SDL_sound, then it is + * possible that it will be different than the version you compiled against. + * + * This is a real function; the macro SOUND_VERSION tells you what version + * of SDL_sound you compiled against: + * + * \code + * Sound_Version compiled; + * Sound_Version linked; + * + * SOUND_VERSION(&compiled); + * Sound_GetLinkedVersion(&linked); + * printf("We compiled against SDL_sound version %d.%d.%d ...\n", + * compiled.major, compiled.minor, compiled.patch); + * printf("But we linked against SDL_sound version %d.%d.%d.\n", + * linked.major, linked.minor, linked.patch); + * \endcode + * + * This function may be called safely at any time, even before Sound_Init(). + * + * \param ver Sound_Version structure to fill with shared library's version. + * + * \sa Sound_Version + * \sa SOUND_VERSION + */ +SNDDECLSPEC void SDLCALL Sound_GetLinkedVersion(Sound_Version *ver); + + +/** + * \fn Sound_Init(void) + * \brief Initialize SDL_sound. + * + * This must be called before any other SDL_sound function (except perhaps + * Sound_GetLinkedVersion()). You should call SDL_Init() before calling this. + * Sound_Init() will attempt to call SDL_Init(SDL_INIT_AUDIO), just in case. + * This is a safe behaviour, but it may not configure SDL to your liking by + * itself. + * + * \return nonzero on success, zero on error. Specifics of the + * error can be gleaned from Sound_GetError(). + * + * \sa Sound_Quit + */ +SNDDECLSPEC int SDLCALL Sound_Init(void); + + +/** + * \fn Sound_Quit(void) + * \brief Shutdown SDL_sound. + * + * This closes any SDL_RWops that were being used as sound sources, and frees + * any resources in use by SDL_sound. + * + * All Sound_Sample pointers you had prior to this call are INVALIDATED. + * + * Once successfully deinitialized, Sound_Init() can be called again to + * restart the subsystem. All default API states are restored at this + * point. + * + * You should call this BEFORE SDL_Quit(). This will NOT call SDL_Quit() + * for you! + * + * \return nonzero on success, zero on error. Specifics of the error + * can be gleaned from Sound_GetError(). If failure, state of + * SDL_sound is undefined, and probably badly screwed up. + * + * \sa Sound_Init + */ +SNDDECLSPEC int SDLCALL Sound_Quit(void); + + +/** + * \fn const Sound_DecoderInfo **Sound_AvailableDecoders(void) + * \brief Get a list of sound formats supported by this version of SDL_sound. + * + * This is for informational purposes only. Note that the extension listed is + * merely convention: if we list "MP3", you can open an MPEG-1 Layer 3 audio + * file with an extension of "XYZ", if you like. The file extensions are + * informational, and only required as a hint to choosing the correct + * decoder, since the sound data may not be coming from a file at all, thanks + * to the abstraction that an SDL_RWops provides. + * + * The returned value is an array of pointers to Sound_DecoderInfo structures, + * with a NULL entry to signify the end of the list: + * + * \code + * Sound_DecoderInfo **i; + * + * for (i = Sound_AvailableDecoders(); *i != NULL; i++) + * { + * printf("Supported sound format: [%s], which is [%s].\n", + * i->extension, i->description); + * // ...and other fields... + * } + * \endcode + * + * The return values are pointers to static internal memory, and should + * be considered READ ONLY, and never freed. + * + * \return READ ONLY Null-terminated array of READ ONLY structures. + * + * \sa Sound_DecoderInfo + */ +SNDDECLSPEC const Sound_DecoderInfo ** SDLCALL Sound_AvailableDecoders(void); + + +/** + * \fn const char *Sound_GetError(void) + * \brief Get the last SDL_sound error message as a null-terminated string. + * + * This will be NULL if there's been no error since the last call to this + * function. The pointer returned by this call points to an internal buffer, + * and should not be deallocated. Each thread has a unique error state + * associated with it, but each time a new error message is set, it will + * overwrite the previous one associated with that thread. It is safe to call + * this function at anytime, even before Sound_Init(). + * + * \return READ ONLY string of last error message. + * + * \sa Sound_ClearError + */ +SNDDECLSPEC const char * SDLCALL Sound_GetError(void); + + +/** + * \fn void Sound_ClearError(void) + * \brief Clear the current error message. + * + * The next call to Sound_GetError() after Sound_ClearError() will return NULL. + * + * \sa Sound_GetError + */ +SNDDECLSPEC void SDLCALL Sound_ClearError(void); + + +/** + * \fn Sound_Sample *Sound_NewSample(SDL_RWops *rw, const char *ext, Sound_AudioInfo *desired, Uint32 bufferSize) + * \brief Start decoding a new sound sample. + * + * The data is read via an SDL_RWops structure (see SDL_rwops.h in the SDL + * include directory), so it may be coming from memory, disk, network stream, + * etc. The (ext) parameter is merely a hint to determining the correct + * decoder; if you specify, for example, "mp3" for an extension, and one of + * the decoders lists that as a handled extension, then that decoder is given + * first shot at trying to claim the data for decoding. If none of the + * extensions match (or the extension is NULL), then every decoder examines + * the data to determine if it can handle it, until one accepts it. In such a + * case your SDL_RWops will need to be capable of rewinding to the start of + * the stream. + * + * If no decoders can handle the data, a NULL value is returned, and a human + * readable error message can be fetched from Sound_GetError(). + * + * Optionally, a desired audio format can be specified. If the incoming data + * is in a different format, SDL_sound will convert it to the desired format + * on the fly. Note that this can be an expensive operation, so it may be + * wise to convert data before you need to play it back, if possible, or + * make sure your data is initially in the format that you need it in. + * If you don't want to convert the data, you can specify NULL for a desired + * format. The incoming format of the data, preconversion, can be found + * in the Sound_Sample structure. + * + * Note that the raw sound data "decoder" needs you to specify both the + * extension "RAW" and a "desired" format, or it will refuse to handle + * the data. This is to prevent it from catching all formats unsupported + * by the other decoders. + * + * Finally, specify an initial buffer size; this is the number of bytes that + * will be allocated to store each read from the sound buffer. The more you + * can safely allocate, the more decoding can be done in one block, but the + * more resources you have to use up, and the longer each decoding call will + * take. Note that different data formats require more or less space to + * store. This buffer can be resized via Sound_SetBufferSize() ... + * + * The buffer size specified must be a multiple of the size of a single + * sample point. So, if you want 16-bit, stereo samples, then your sample + * point size is (2 channels * 16 bits), or 32 bits per sample, which is four + * bytes. In such a case, you could specify 128 or 132 bytes for a buffer, + * but not 129, 130, or 131 (although in reality, you'll want to specify a + * MUCH larger buffer). + * + * When you are done with this Sound_Sample pointer, you can dispose of it + * via Sound_FreeSample(). + * + * You do not have to keep a reference to (rw) around. If this function + * suceeds, it stores (rw) internally (and disposes of it during the call + * to Sound_FreeSample()). If this function fails, it will dispose of the + * SDL_RWops for you. + * + * \param rw SDL_RWops with sound data. + * \param ext File extension normally associated with a data format. + * Can usually be NULL. + * \param desired Format to convert sound data into. Can usually be NULL, + * if you don't need conversion. + * \param bufferSize Size, in bytes, to allocate for the decoding buffer. + * \return Sound_Sample pointer, which is used as a handle to several other + * SDL_sound APIs. NULL on error. If error, use + * Sound_GetError() to see what went wrong. + * + * \sa Sound_NewSampleFromFile + * \sa Sound_SetBufferSize + * \sa Sound_Decode + * \sa Sound_DecodeAll + * \sa Sound_Seek + * \sa Sound_Rewind + * \sa Sound_FreeSample + */ +SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSample(SDL_RWops *rw, + const char *ext, + Sound_AudioInfo *desired, + Uint32 bufferSize); + +/** + * \fn Sound_Sample *Sound_NewSampleFromMem(const Uint8 *data, Sound_AudioInfo *desired, Uint32 bufferSize) + * \brief Start decoding a new sound sample from a file on disk. + * + * This is identical to Sound_NewSample(), but it creates an SDL_RWops for you + * from the (size) bytes of memory referenced by (data). + * + * This can pool RWops structures, so it may fragment the heap less over time + * than using SDL_RWFromMem(). + * + * \param filename file containing sound data. + * \param desired Format to convert sound data into. Can usually be NULL, + * if you don't need conversion. + * \param bufferSize size, in bytes, of initial read buffer. + * \return Sound_Sample pointer, which is used as a handle to several other + * SDL_sound APIs. NULL on error. If error, use + * Sound_GetError() to see what went wrong. + * + * \sa Sound_NewSample + * \sa Sound_SetBufferSize + * \sa Sound_Decode + * \sa Sound_DecodeAll + * \sa Sound_Seek + * \sa Sound_Rewind + * \sa Sound_FreeSample + */ +SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSampleFromMem(const Uint8 *data, + Uint32 size, + const char *ext, + Sound_AudioInfo *desired, + Uint32 bufferSize); + + +/** + * \fn Sound_Sample *Sound_NewSampleFromFile(const char *filename, Sound_AudioInfo *desired, Uint32 bufferSize) + * \brief Start decoding a new sound sample from a file on disk. + * + * This is identical to Sound_NewSample(), but it creates an SDL_RWops for you + * from the file located in (filename). Note that (filename) is specified in + * platform-dependent notation. ("C:\\music\\mysong.mp3" on windows, and + * "/home/icculus/music/mysong.mp3" or whatever on Unix, etc.) + * Sound_NewSample()'s "ext" parameter is gleaned from the contents of + * (filename). + * + * This can pool RWops structures, so it may fragment the heap less over time + * than using SDL_RWFromFile(). + * + * \param filename file containing sound data. + * \param desired Format to convert sound data into. Can usually be NULL, + * if you don't need conversion. + * \param bufferSize size, in bytes, of initial read buffer. + * \return Sound_Sample pointer, which is used as a handle to several other + * SDL_sound APIs. NULL on error. If error, use + * Sound_GetError() to see what went wrong. + * + * \sa Sound_NewSample + * \sa Sound_SetBufferSize + * \sa Sound_Decode + * \sa Sound_DecodeAll + * \sa Sound_Seek + * \sa Sound_Rewind + * \sa Sound_FreeSample + */ +SNDDECLSPEC Sound_Sample * SDLCALL Sound_NewSampleFromFile(const char *fname, + Sound_AudioInfo *desired, + Uint32 bufferSize); + +/** + * \fn void Sound_FreeSample(Sound_Sample *sample) + * \brief Dispose of a Sound_Sample. + * + * This will also close/dispose of the SDL_RWops that was used at creation + * time, so there's no need to keep a reference to that around. + * The Sound_Sample pointer is invalid after this call, and will almost + * certainly result in a crash if you attempt to keep using it. + * + * \param sample The Sound_Sample to delete. + * + * \sa Sound_NewSample + * \sa Sound_NewSampleFromFile + */ +SNDDECLSPEC void SDLCALL Sound_FreeSample(Sound_Sample *sample); + + +/** + * \fn Sint32 Sound_GetDuration(Sound_Sample *sample) + * \brief Retrieve total play time of sample, in milliseconds. + * + * Report total time length of sample, in milliseconds. This is a fast + * call. Duration is calculated during Sound_NewSample*, so this is just + * an accessor into otherwise opaque data. + * + * Please note that not all formats can determine a total time, some can't + * be exact without fully decoding the data, and thus will estimate the + * duration. Many decoders will require the ability to seek in the data + * stream to calculate this, so even if we can tell you how long an .ogg + * file will be, the same data set may fail if it's, say, streamed over an + * HTTP connection. Plan accordingly. + * + * Most people won't need this function to just decode and playback, but it + * can be useful for informational purposes in, say, a music player's UI. + * + * \param sample Sound_Sample from which to retrieve duration information. + * \return Sample length in milliseconds, or -1 if duration can't be + * determined for any reason. + */ +SNDDECLSPEC Sint32 SDLCALL Sound_GetDuration(Sound_Sample *sample); + + +/** + * \fn int Sound_SetBufferSize(Sound_Sample *sample, Uint32 new_size) + * \brief Change the current buffer size for a sample. + * + * If the buffer size could be changed, then the sample->buffer and + * sample->buffer_size fields will reflect that. If they could not be + * changed, then your original sample state is preserved. If the buffer is + * shrinking, the data at the end of buffer is truncated. If the buffer is + * growing, the contents of the new space at the end is undefined until you + * decode more into it or initialize it yourself. + * + * The buffer size specified must be a multiple of the size of a single + * sample point. So, if you want 16-bit, stereo samples, then your sample + * point size is (2 channels * 16 bits), or 32 bits per sample, which is four + * bytes. In such a case, you could specify 128 or 132 bytes for a buffer, + * but not 129, 130, or 131 (although in reality, you'll want to specify a + * MUCH larger buffer). + * + * \param sample The Sound_Sample whose buffer to modify. + * \param new_size The desired size, in bytes, of the new buffer. + * \return non-zero if buffer size changed, zero on failure. + * + * \sa Sound_Decode + * \sa Sound_DecodeAll + */ +SNDDECLSPEC int SDLCALL Sound_SetBufferSize(Sound_Sample *sample, + Uint32 new_size); + + +/** + * \fn Uint32 Sound_Decode(Sound_Sample *sample) + * \brief Decode more of the sound data in a Sound_Sample. + * + * It will decode at most sample->buffer_size bytes into sample->buffer in the + * desired format, and return the number of decoded bytes. + * If sample->buffer_size bytes could not be decoded, then please refer to + * sample->flags to determine if this was an end-of-stream or error condition. + * + * \param sample Do more decoding to this Sound_Sample. + * \return number of bytes decoded into sample->buffer. If it is less than + * sample->buffer_size, then you should check sample->flags to see + * what the current state of the sample is (EOF, error, read again). + * + * \sa Sound_DecodeAll + * \sa Sound_SetBufferSize + * \sa Sound_Seek + * \sa Sound_Rewind + */ +SNDDECLSPEC Uint32 SDLCALL Sound_Decode(Sound_Sample *sample); + + +/** + * \fn Uint32 Sound_DecodeAll(Sound_Sample *sample) + * \brief Decode the remainder of the sound data in a Sound_Sample. + * + * This will dynamically allocate memory for the ENTIRE remaining sample. + * sample->buffer_size and sample->buffer will be updated to reflect the + * new buffer. Please refer to sample->flags to determine if the decoding + * finished due to an End-of-stream or error condition. + * + * Be aware that sound data can take a large amount of memory, and that + * this function may block for quite awhile while processing. Also note + * that a streaming source (for example, from a SDL_RWops that is getting + * fed from an Internet radio feed that doesn't end) may fill all available + * memory before giving up...be sure to use this on finite sound sources + * only! + * + * When decoding the sample in its entirety, the work is done one buffer at a + * time. That is, sound is decoded in sample->buffer_size blocks, and + * appended to a continually-growing buffer until the decoding completes. + * That means that this function will need enough RAM to hold approximately + * sample->buffer_size bytes plus the complete decoded sample at most. The + * larger your buffer size, the less overhead this function needs, but beware + * the possibility of paging to disk. Best to make this user-configurable if + * the sample isn't specific and small. + * + * \param sample Do all decoding for this Sound_Sample. + * \return number of bytes decoded into sample->buffer. You should check + * sample->flags to see what the current state of the sample is + * (EOF, error, read again). + * + * \sa Sound_Decode + * \sa Sound_SetBufferSize + */ +SNDDECLSPEC Uint32 SDLCALL Sound_DecodeAll(Sound_Sample *sample); + + +/** + * \fn int Sound_Rewind(Sound_Sample *sample) + * \brief Rewind a sample to the start. + * + * Restart a sample at the start of its waveform data, as if newly + * created with Sound_NewSample(). If successful, the next call to + * Sound_Decode[All]() will give audio data from the earliest point + * in the stream. + * + * Beware that this function will fail if the SDL_RWops that feeds the + * decoder can not be rewound via it's seek method, but this can + * theoretically be avoided by wrapping it in some sort of buffering + * SDL_RWops. + * + * This function should ONLY fail if the RWops is not seekable, or + * SDL_sound is not initialized. Both can be controlled by the application, + * and thus, it is up to the developer's paranoia to dictate whether this + * function's return value need be checked at all. + * + * If this function fails, the state of the sample is undefined, but it + * is still safe to call Sound_FreeSample() to dispose of it. + * + * On success, ERROR, EOF, and EAGAIN are cleared from sample->flags. The + * ERROR flag is set on error. + * + * \param sample The Sound_Sample to rewind. + * \return nonzero on success, zero on error. Specifics of the + * error can be gleaned from Sound_GetError(). + * + * \sa Sound_Seek + */ +SNDDECLSPEC int SDLCALL Sound_Rewind(Sound_Sample *sample); + + +/** + * \fn int Sound_Seek(Sound_Sample *sample, Uint32 ms) + * \brief Seek to a different point in a sample. + * + * Reposition a sample's stream. If successful, the next call to + * Sound_Decode[All]() will give audio data from the offset you + * specified. + * + * The offset is specified in milliseconds from the start of the + * sample. + * + * Beware that this function can fail for several reasons. If the + * SDL_RWops that feeds the decoder can not seek, this call will almost + * certainly fail, but this can theoretically be avoided by wrapping it + * in some sort of buffering SDL_RWops. Some decoders can never seek, + * others can only seek with certain files. The decoders will set a flag + * in the sample at creation time to help you determine this. + * + * You should check sample->flags & SOUND_SAMPLEFLAG_CANSEEK + * before attempting. Sound_Seek() reports failure immediately if this + * flag isn't set. This function can still fail for other reasons if the + * flag is set. + * + * This function can be emulated in the application with Sound_Rewind() + * and predecoding a specific amount of the sample, but this can be + * extremely inefficient. Sound_Seek() accelerates the seek on a + * with decoder-specific code. + * + * If this function fails, the sample should continue to function as if + * this call was never made. If there was an unrecoverable error, + * sample->flags & SOUND_SAMPLEFLAG_ERROR will be set, which you regular + * decoding loop can pick up. + * + * On success, ERROR, EOF, and EAGAIN are cleared from sample->flags. + * + * \param sample The Sound_Sample to seek. + * \param ms The new position, in milliseconds from start of sample. + * \return nonzero on success, zero on error. Specifics of the + * error can be gleaned from Sound_GetError(). + * + * \sa Sound_Rewind + */ +SNDDECLSPEC int SDLCALL Sound_Seek(Sound_Sample *sample, Uint32 ms); + +#ifdef __cplusplus +} +#endif + +#endif /* !defined _INCLUDE_SDL_SOUND_H_ */ + +/* end of SDL_sound.h ... */ + diff --git a/src/libs/decoders/SDL_sound_internal.h b/src/libs/decoders/SDL_sound_internal.h new file mode 100644 index 00000000..caf00588 --- /dev/null +++ b/src/libs/decoders/SDL_sound_internal.h @@ -0,0 +1,334 @@ +/* + * SDL_sound -- An abstract sound format decoding API. + * Copyright (C) 2001 Ryan C. Gordon. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 + * Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Internal function/structure declaration. Do NOT include in your + * application. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * This file written by Ryan C. Gordon. (icculus@icculus.org) + */ + +#ifndef _INCLUDE_SDL_SOUND_INTERNAL_H_ +#define _INCLUDE_SDL_SOUND_INTERNAL_H_ + +#ifndef __SDL_SOUND_INTERNAL__ +#error Do not include this header from your applications. +#endif + +#include "SDL.h" + +/* SDL 1.2.4 defines this, but better safe than sorry. */ +#if (!defined(__inline__)) +# define __inline__ +#endif + +#if (defined DEBUG_CHATTER) +#define SNDDBG(x) printf x +#else +#define SNDDBG(x) +#endif + +#if HAVE_ASSERT_H +# include +#endif + +#ifdef _WIN32_WCE + extern char *strrchr(const char *s, int c); +# ifdef NDEBUG +# define assert(x) +# else +# define assert(x) if(!x) { fprintf(stderr,"Assertion failed in %s, line %s.\n",__FILE__,__LINE__); fclose(stderr); fclose(stdout); exit(1); } +# endif +#endif + + +#if (!defined assert) /* if all else fails. */ +# define assert(x) +#endif + + +/* + * SDL itself only supports mono and stereo output, but hopefully we can + * raise this value someday...there's probably a lot of assumptions in + * SDL_sound that rely on it, though. + */ +#define MAX_CHANNELS 2 + + +typedef struct __SOUND_DECODERFUNCTIONS__ +{ + /* This is a block of info about your decoder. See SDL_sound.h. */ + const Sound_DecoderInfo info; + + /* + * This is called during the Sound_Init() function. Use this to + * set up any global state that your decoder needs, such as + * initializing an external library, etc. + * + * Return non-zero if initialization is successful, zero if there's + * a fatal error. If this method fails, then this decoder is + * flagged as unavailable until SDL_sound() is shut down and + * reinitialized, in which case this method will be tried again. + * + * Note that the decoders quit() method won't be called if this + * method fails, so if you can't intialize, you'll have to clean + * up the half-initialized state in this method. + */ + int (*init)(void); + + /* + * This is called during the Sound_Quit() function. Use this to + * clean up any global state that your decoder has used during its + * lifespan. + */ + void (*quit)(void); + + /* + * Returns non-zero if (sample) has a valid fileformat that this + * driver can handle. Zero if this driver can NOT handle the data. + * + * Extension, which may be NULL, is just a hint as to the form of + * data that is being passed in. Most decoders should determine if + * they can handle the data by the data itself, but others, like + * the raw data handler, need this hint to know if they should + * accept the data in the first place. + * + * (sample)'s (opaque) field should be cast to a Sound_SampleInternal + * pointer: + * + * Sound_SampleInternal *internal; + * internal = (Sound_SampleInternal *) sample->opaque; + * + * Certain fields of sample will be filled in for the decoder before + * this call, and others should be filled in by the decoder. Some + * fields are offlimits, and should NOT be modified. The list: + * + * in Sound_SampleInternal section: + * Sound_Sample *next; (offlimits) + * Sound_Sample *prev; (offlimits) + * SDL_RWops *rw; (can use, but do NOT close it) + * const Sound_DecoderFunctions *funcs; (that's this structure) + * Sound_AudioCVT sdlcvt; (offlimits) + * void *buffer; (offlimits until read() method) + * Uint32 buffer_size; (offlimits until read() method) + * void *decoder_private; (read and write access) + * + * in rest of Sound_Sample: + * void *opaque; (this was internal section, above) + * const Sound_DecoderInfo *decoder; (read only) + * Sound_AudioInfo desired; (read only, usually not needed here) + * Sound_AudioInfo actual; (please fill this in) + * void *buffer; (offlimits) + * Uint32 buffer_size; (offlimits) + * Sound_SampleFlags flags; (set appropriately) + */ + int (*open)(Sound_Sample *sample, const char *ext); + + /* + * Clean up. SDL_sound is done with this sample, so the decoder should + * clean up any resources it allocated. Anything that wasn't + * explicitly allocated by the decoder should be LEFT ALONE, since + * the higher-level SDL_sound layer will clean up its own mess. + */ + void (*close)(Sound_Sample *sample); + + /* + * Get more data from (sample). The decoder should get a pointer to + * the internal structure... + * + * Sound_SampleInternal *internal; + * internal = (Sound_SampleInternal *) sample->opaque; + * + * ...and then start decoding. Fill in up to internal->buffer_size + * bytes of decoded sound in the space pointed to by + * internal->buffer. The encoded data is read in from internal->rw. + * Data should be decoded in the format specified during the + * decoder's open() method in the sample->actual field. The + * conversion to the desired format is done at a higher level. + * + * The return value is the number of bytes decoded into + * internal->buffer, which can be no more than internal->buffer_size, + * but can be less. If it is less, you should set a state flag: + * + * If there's just no more data (end of file, etc), then do: + * sample->flags |= SOUND_SAMPLEFLAG_EOF; + * + * If there's an unrecoverable error, then do: + * __Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG); + * sample->flags |= SOUND_SAMPLEFLAG_ERROR; + * + * If there's more data, but you'd have to block for considerable + * amounts of time to get at it, or there's a recoverable error, + * then do: + * __Sound_SetError(ERR_EXPLAIN_WHAT_WENT_WRONG); + * sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; + * + * SDL_sound will not call your read() method for any samples with + * SOUND_SAMPLEFLAG_EOF or SOUND_SAMPLEFLAG_ERROR set. The + * SOUND_SAMPLEFLAG_EAGAIN flag is reset before each call to this + * method. + */ + Uint32 (*read)(Sound_Sample *sample); + + /* + * Reset the decoding to the beginning of the stream. Nonzero on + * success, zero on failure. + * + * The purpose of this method is to allow for higher efficiency than + * an application could get by just recreating the sample externally; + * not only do they not have to reopen the RWops, reallocate buffers, + * and potentially pass the data through several rejecting decoders, + * but certain decoders will not have to recreate their existing + * state (search for metadata, etc) since they already know they + * have a valid audio stream with a given set of characteristics. + * + * The decoder is responsible for calling seek() on the associated + * SDL_RWops. A failing call to seek() should be the ONLY reason that + * this method should ever fail! + */ + int (*rewind)(Sound_Sample *sample); + + /* + * Reposition the decoding to an arbitrary point. Nonzero on + * success, zero on failure. + * + * The purpose of this method is to allow for higher efficiency than + * an application could get by just rewinding the sample and + * decoding to a given point. + * + * The decoder is responsible for calling seek() on the associated + * SDL_RWops. + * + * If there is an error, try to recover so that the next read will + * continue as if nothing happened. + */ + int (*seek)(Sound_Sample *sample, Uint32 ms); +} Sound_DecoderFunctions; + + +/* A structure to hold a set of audio conversion filters and buffers */ +typedef struct Sound_AudioCVT +{ + int needed; /* Set to 1 if conversion possible */ + Uint16 src_format; /* Source audio format */ + Uint16 dst_format; /* Target audio format */ + double rate_incr; /* Rate conversion increment */ + Uint8 *buf; /* Buffer to hold entire audio data */ + int len; /* Length of original audio buffer */ + int len_cvt; /* Length of converted audio buffer */ + int len_mult; /* buffer must be len*len_mult big */ + double len_ratio; /* Given len, final size is len*len_ratio */ + void (*filters[20])(struct Sound_AudioCVT *cvt, Uint16 *format); + int filter_index; /* Current audio conversion function */ +} Sound_AudioCVT; + +extern SNDDECLSPEC int Sound_BuildAudioCVT(Sound_AudioCVT *cvt, + Uint16 src_format, Uint8 src_channels, Uint32 src_rate, + Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate, + Uint32 dst_size); + +extern SNDDECLSPEC int Sound_ConvertAudio(Sound_AudioCVT *cvt); + + +typedef void (*MixFunc)(float *dst, void *src, Uint32 frames, float *gains); + +typedef struct __SOUND_SAMPLEINTERNAL__ +{ + Sound_Sample *next; + Sound_Sample *prev; + SDL_RWops *rw; + const Sound_DecoderFunctions *funcs; + Sound_AudioCVT sdlcvt; + void *buffer; + Uint32 buffer_size; + void *decoder_private; + Sint32 total_time; + Uint32 mix_position; + MixFunc mix; +} Sound_SampleInternal; + + +/* error messages... */ +#define ERR_IS_INITIALIZED "Already initialized" +#define ERR_NOT_INITIALIZED "Not initialized" +#define ERR_INVALID_ARGUMENT "Invalid argument" +#define ERR_OUT_OF_MEMORY "Out of memory" +#define ERR_NOT_SUPPORTED "Operation not supported" +#define ERR_UNSUPPORTED_FORMAT "Sound format unsupported" +#define ERR_NOT_A_HANDLE "Not a file handle" +#define ERR_NO_SUCH_FILE "No such file" +#define ERR_PAST_EOF "Past end of file" +#define ERR_IO_ERROR "I/O error" +#define ERR_COMPRESSION "(De)compression error" +#define ERR_PREV_ERROR "Previous decoding already caused an error" +#define ERR_PREV_EOF "Previous decoding already triggered EOF" +#define ERR_CANNOT_SEEK "Sample is not seekable" + +/* + * Call this to set the message returned by Sound_GetError(). + * Please only use the ERR_* constants above, or add new constants to the + * above group, but I want these all in one place. + * + * Calling this with a NULL argument is a safe no-op. + */ +void __Sound_SetError(const char *err); + +/* + * Call this to convert milliseconds to an actual byte position, based on + * audio data characteristics. + */ +Uint32 __Sound_convertMsToBytePos(Sound_AudioInfo *info, Uint32 ms); + +/* + * Use this if you need a cross-platform stricmp(). + */ +int __Sound_strcasecmp(const char *x, const char *y); + + +/* These get used all over for lessening code clutter. */ +#define BAIL_MACRO(e, r) { __Sound_SetError(e); return r; } +#define BAIL_IF_MACRO(c, e, r) if (c) { __Sound_SetError(e); return r; } + + + + +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ +/*------------ ----------------*/ +/*------------ You MUST implement the following functions ----------------*/ +/*------------ if porting to a new platform. ----------------*/ +/*------------ (see platform/unix.c for an example) ----------------*/ +/*------------ ----------------*/ +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ + + +/* (None, right now.) */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* defined _INCLUDE_SDL_SOUND_INTERNAL_H_ */ + +/* end of SDL_sound_internal.h ... */ + diff --git a/src/libs/decoders/audio_convert.c b/src/libs/decoders/audio_convert.c new file mode 100644 index 00000000..39027552 --- /dev/null +++ b/src/libs/decoders/audio_convert.c @@ -0,0 +1,735 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +/* + * This file was derived from SDL's SDL_audiocvt.c and is an attempt to + * address the shortcomings of it. + * + * Perhaps we can adapt some good filters from SoX? + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include "SDL.h" +#include "SDL_sound.h" + +#define __SDL_SOUND_INTERNAL__ +#include "SDL_sound_internal.h" + +/* Functions for audio drivers to perform runtime conversion of audio format */ + + +/* + * Toggle endianness. This filter is, of course, only applied to 16-bit + * audio data. + */ + +static void Sound_ConvertEndian(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Uint8 *data, tmp; + + /* SNDDBG(("Converting audio endianness\n")); */ + + data = cvt->buf; + + for (i = cvt->len_cvt / 2; i; --i) + { + tmp = data[0]; + data[0] = data[1]; + data[1] = tmp; + data += 2; + } /* for */ + + *format = (*format ^ 0x1000); +} /* Sound_ConvertEndian */ + + +/* + * Toggle signed/unsigned. Apparently this is done by toggling the most + * significant bit of each sample. + */ + +static void Sound_ConvertSign(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Uint8 *data; + + /* SNDDBG(("Converting audio signedness\n")); */ + + data = cvt->buf; + + /* 16-bit sound? */ + if ((*format & 0xFF) == 16) + { + /* Little-endian? */ + if ((*format & 0x1000) != 0x1000) + ++data; + + for (i = cvt->len_cvt / 2; i; --i) + { + *data ^= 0x80; + data += 2; + } /* for */ + } /* if */ + else + { + for (i = cvt->len_cvt; i; --i) + *data++ ^= 0x80; + } /* else */ + + *format = (*format ^ 0x8000); +} /* Sound_ConvertSign */ + + +/* + * Convert 16-bit to 8-bit. This is done by taking the most significant byte + * of each 16-bit sample. + */ + +static void Sound_Convert8(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Uint8 *src, *dst; + + /* SNDDBG(("Converting to 8-bit\n")); */ + + src = cvt->buf; + dst = cvt->buf; + + /* Little-endian? */ + if ((*format & 0x1000) != 0x1000) + ++src; + + for (i = cvt->len_cvt / 2; i; --i) + { + *dst = *src; + src += 2; + dst += 1; + } /* for */ + + *format = ((*format & ~0x9010) | AUDIO_U8); + cvt->len_cvt /= 2; +} /* Sound_Convert8 */ + + +/* Convert 8-bit to 16-bit - LSB */ + +static void Sound_Convert16LSB(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Uint8 *src, *dst; + + /* SNDDBG(("Converting to 16-bit LSB\n")); */ + + src = cvt->buf + cvt->len_cvt; + dst = cvt->buf + cvt->len_cvt * 2; + + for (i = cvt->len_cvt; i; --i) + { + src -= 1; + dst -= 2; + dst[1] = *src; + dst[0] = 0; + } /* for */ + + *format = ((*format & ~0x0008) | AUDIO_U16LSB); + cvt->len_cvt *= 2; +} /* Sound_Convert16LSB */ + + +/* Convert 8-bit to 16-bit - MSB */ + +static void Sound_Convert16MSB(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Uint8 *src, *dst; + + /* SNDDBG(("Converting to 16-bit MSB\n")); */ + + src = cvt->buf + cvt->len_cvt; + dst = cvt->buf + cvt->len_cvt * 2; + + for (i = cvt->len_cvt; i; --i) + { + src -= 1; + dst -= 2; + dst[0] = *src; + dst[1] = 0; + } /* for */ + + *format = ((*format & ~0x0008) | AUDIO_U16MSB); + cvt->len_cvt *= 2; +} /* Sound_Convert16MSB */ + + +/* Duplicate a mono channel to both stereo channels */ + +static void Sound_ConvertStereo(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + + /* SNDDBG(("Converting to stereo\n")); */ + + /* 16-bit sound? */ + if ((*format & 0xFF) == 16) + { + Uint16 *src, *dst; + + src = (Uint16 *) (cvt->buf + cvt->len_cvt); + dst = (Uint16 *) (cvt->buf + cvt->len_cvt * 2); + + for (i = cvt->len_cvt/2; i; --i) + { + dst -= 2; + src -= 1; + dst[0] = src[0]; + dst[1] = src[0]; + } /* for */ + } /* if */ + else + { + Uint8 *src, *dst; + + src = cvt->buf + cvt->len_cvt; + dst = cvt->buf + cvt->len_cvt * 2; + + for (i = cvt->len_cvt; i; --i) + { + dst -= 2; + src -= 1; + dst[0] = src[0]; + dst[1] = src[0]; + } /* for */ + } /* else */ + + cvt->len_cvt *= 2; +} /* Sound_ConvertStereo */ + + +/* Effectively mix right and left channels into a single channel */ + +static void Sound_ConvertMono(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Sint32 sample; + Uint8 *u_src, *u_dst; + Sint8 *s_src, *s_dst; + + /* SNDDBG(("Converting to mono\n")); */ + + switch (*format) + { + case AUDIO_U8: + u_src = cvt->buf; + u_dst = cvt->buf; + + for (i = cvt->len_cvt / 2; i; --i) + { + sample = u_src[0] + u_src[1]; + *u_dst = (sample > 255) ? 255 : sample; + u_src += 2; + u_dst += 1; + } /* for */ + break; + + case AUDIO_S8: + s_src = (Sint8 *) cvt->buf; + s_dst = (Sint8 *) cvt->buf; + + for (i = cvt->len_cvt / 2; i; --i) + { + sample = s_src[0] + s_src[1]; + if (sample > 127) + *s_dst = 127; + else if (sample < -128) + *s_dst = -128; + else + *s_dst = sample; + + s_src += 2; + s_dst += 1; + } /* for */ + break; + + case AUDIO_U16MSB: + u_src = cvt->buf; + u_dst = cvt->buf; + + for (i = cvt->len_cvt / 4; i; --i) + { + sample = (Uint16) ((u_src[0] << 8) | u_src[1]) + + (Uint16) ((u_src[2] << 8) | u_src[3]); + if (sample > 65535) + { + u_dst[0] = 0xFF; + u_dst[1] = 0xFF; + } /* if */ + else + { + u_dst[1] = (sample & 0xFF); + sample >>= 8; + u_dst[0] = (sample & 0xFF); + } /* else */ + u_src += 4; + u_dst += 2; + } /* for */ + break; + + case AUDIO_U16LSB: + u_src = cvt->buf; + u_dst = cvt->buf; + + for (i = cvt->len_cvt / 4; i; --i) + { + sample = (Uint16) ((u_src[1] << 8) | u_src[0]) + + (Uint16) ((u_src[3] << 8) | u_src[2]); + if (sample > 65535) + { + u_dst[0] = 0xFF; + u_dst[1] = 0xFF; + } /* if */ + else + { + u_dst[0] = (sample & 0xFF); + sample >>= 8; + u_dst[1] = (sample & 0xFF); + } /* else */ + u_src += 4; + u_dst += 2; + } /* for */ + break; + + case AUDIO_S16MSB: + u_src = cvt->buf; + u_dst = cvt->buf; + + for (i = cvt->len_cvt / 4; i; --i) + { + sample = (Sint16) ((u_src[0] << 8) | u_src[1]) + + (Sint16) ((u_src[2] << 8) | u_src[3]); + if (sample > 32767) + { + u_dst[0] = 0x7F; + u_dst[1] = 0xFF; + } /* if */ + else if (sample < -32768) + { + u_dst[0] = 0x80; + u_dst[1] = 0x00; + } /* else if */ + else + { + u_dst[1] = (sample & 0xFF); + sample >>= 8; + u_dst[0] = (sample & 0xFF); + } /* else */ + u_src += 4; + u_dst += 2; + } /* for */ + break; + + case AUDIO_S16LSB: + u_src = cvt->buf; + u_dst = cvt->buf; + + for (i = cvt->len_cvt / 4; i; --i) + { + sample = (Sint16) ((u_src[1] << 8) | u_src[0]) + + (Sint16) ((u_src[3] << 8) | u_src[2]); + if (sample > 32767) + { + u_dst[1] = 0x7F; + u_dst[0] = 0xFF; + } /* if */ + else if (sample < -32768) + { + u_dst[1] = 0x80; + u_dst[0] = 0x00; + } /* else if */ + else + { + u_dst[0] = (sample & 0xFF); + sample >>= 8; + u_dst[1] = (sample & 0xFF); + } /* else */ + u_src += 4; + u_dst += 2; + } /* for */ + break; + } /* switch */ + + cvt->len_cvt /= 2; +} /* Sound_ConvertMono */ + + +/* Convert rate up by multiple of 2 */ + +static void Sound_RateMUL2(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Uint8 *src, *dst; + + /* SNDDBG(("Converting audio rate * 2\n")); */ + + src = cvt->buf + cvt->len_cvt; + dst = cvt->buf + cvt->len_cvt*2; + + /* 8- or 16-bit sound? */ + switch (*format & 0xFF) + { + case 8: + for (i = cvt->len_cvt; i; --i) + { + src -= 1; + dst -= 2; + dst[0] = src[0]; + dst[1] = src[0]; + } /* for */ + break; + + case 16: + for (i = cvt->len_cvt / 2; i; --i) + { + src -= 2; + dst -= 4; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[0]; + dst[3] = src[1]; + } /* for */ + break; + } /* switch */ + + cvt->len_cvt *= 2; +} /* Sound_RateMUL2 */ + + +/* Convert rate down by multiple of 2 */ + +static void Sound_RateDIV2(Sound_AudioCVT *cvt, Uint16 *format) +{ + int i; + Uint8 *src, *dst; + + /* SNDDBG(("Converting audio rate / 2\n")); */ + + src = cvt->buf; + dst = cvt->buf; + + /* 8- or 16-bit sound? */ + switch (*format & 0xFF) + { + case 8: + for (i = cvt->len_cvt / 2; i; --i) + { + dst[0] = src[0]; + src += 2; + dst += 1; + } /* for */ + break; + + case 16: + for (i = cvt->len_cvt / 4; i; --i) + { + dst[0] = src[0]; + dst[1] = src[1]; + src += 4; + dst += 2; + } + break; + } /* switch */ + + cvt->len_cvt /= 2; +} /* Sound_RateDIV2 */ + + +/* Very slow rate conversion routine */ + +static void Sound_RateSLOW(Sound_AudioCVT *cvt, Uint16 *format) +{ + double ipos; + int i, clen; + Uint8 *output8; + Uint16 *output16; + + /* SNDDBG(("Converting audio rate * %4.4f\n", 1.0/cvt->rate_incr)); */ + + clen = (int) ((double) cvt->len_cvt / cvt->rate_incr); + + if (cvt->rate_incr > 1.0) + { + /* 8- or 16-bit sound? */ + switch (*format & 0xFF) + { + case 8: + output8 = cvt->buf; + + ipos = 0.0; + for (i = clen; i; --i) + { + *output8 = cvt->buf[(int) ipos]; + ipos += cvt->rate_incr; + output8 += 1; + } /* for */ + break; + + case 16: + output16 = (Uint16 *) cvt->buf; + + clen &= ~1; + ipos = 0.0; + for (i = clen / 2; i; --i) + { + *output16 = ((Uint16 *) cvt->buf)[(int) ipos]; + ipos += cvt->rate_incr; + output16 += 1; + } /* for */ + break; + } /* switch */ + } /* if */ + else + { + /* 8- or 16-bit sound */ + switch (*format & 0xFF) + { + case 8: + output8 = cvt->buf + clen; + + ipos = (double) cvt->len_cvt; + for (i = clen; i; --i) + { + ipos -= cvt->rate_incr; + output8 -= 1; + *output8 = cvt->buf[(int) ipos]; + } /* for */ + break; + + case 16: + clen &= ~1; + output16 = (Uint16 *) (cvt->buf + clen); + ipos = (double) cvt->len_cvt / 2; + for (i = clen / 2; i; --i) + { + ipos -= cvt->rate_incr; + output16 -= 1; + *output16 = ((Uint16 *) cvt->buf)[(int) ipos]; + } /* for */ + break; + } /* switch */ + } /* else */ + + cvt->len_cvt = clen; +} /* Sound_RateSLOW */ + + +int Sound_ConvertAudio(Sound_AudioCVT *cvt) +{ + Uint16 format; + + /* Make sure there's data to convert */ + if (cvt->buf == NULL) + { + __Sound_SetError("No buffer allocated for conversion"); + return(-1); + } /* if */ + + /* Return okay if no conversion is necessary */ + cvt->len_cvt = cvt->len; + if (cvt->filters[0] == NULL) + return(0); + + /* Set up the conversion and go! */ + format = cvt->src_format; + for (cvt->filter_index = 0; cvt->filters[cvt->filter_index]; + cvt->filter_index++) + { + cvt->filters[cvt->filter_index](cvt, &format); + } + return(0); +} /* Sound_ConvertAudio */ + + +/* + * Creates a set of audio filters to convert from one format to another. + * Returns -1 if the format conversion is not supported, or 1 if the + * audio filter is set up. + */ + +int Sound_BuildAudioCVT(Sound_AudioCVT *cvt, + Uint16 src_format, Uint8 src_channels, Uint32 src_rate, + Uint16 dst_format, Uint8 dst_channels, Uint32 dst_rate, + Uint32 dst_size) +{ + /* Start off with no conversion necessary */ + cvt->needed = 0; + cvt->filter_index = 0; + cvt->filters[0] = NULL; + cvt->len_mult = 1; + cvt->len_ratio = 1.0; + + /* First filter: Endian conversion from src to dst */ + if ((src_format & 0x1000) != (dst_format & 0x1000) && + ((src_format & 0xff) != 8)) + { + SNDDBG(("Adding filter: Sound_ConvertEndian\n")); + cvt->filters[cvt->filter_index++] = Sound_ConvertEndian; + } /* if */ + + /* Second filter: Sign conversion -- signed/unsigned */ + if ((src_format & 0x8000) != (dst_format & 0x8000)) + { + SNDDBG(("Adding filter: Sound_ConvertSign\n")); + cvt->filters[cvt->filter_index++] = Sound_ConvertSign; + } /* if */ + + /* Next filter: Convert 16 bit <--> 8 bit PCM. */ + if ((src_format & 0xFF) != (dst_format & 0xFF)) + { + switch (dst_format & 0x10FF) + { + case AUDIO_U8: + SNDDBG(("Adding filter: Sound_Convert8\n")); + cvt->filters[cvt->filter_index++] = Sound_Convert8; + cvt->len_ratio /= 2; + break; + + case AUDIO_U16LSB: + SNDDBG(("Adding filter: Sound_Convert16LSB\n")); + cvt->filters[cvt->filter_index++] = Sound_Convert16LSB; + cvt->len_mult *= 2; + cvt->len_ratio *= 2; + break; + + case AUDIO_U16MSB: + SNDDBG(("Adding filter: Sound_Convert16MSB\n")); + cvt->filters[cvt->filter_index++] = Sound_Convert16MSB; + cvt->len_mult *= 2; + cvt->len_ratio *= 2; + break; + } /* switch */ + } /* if */ + + /* Next filter: Mono/Stereo conversion */ + if (src_channels != dst_channels) + { + while ((src_channels * 2) <= dst_channels) + { + SNDDBG(("Adding filter: Sound_ConvertStereo\n")); + cvt->filters[cvt->filter_index++] = Sound_ConvertStereo; + cvt->len_mult *= 2; + src_channels *= 2; + cvt->len_ratio *= 2; + } /* while */ + + /* This assumes that 4 channel audio is in the format: + * Left {front/back} + Right {front/back} + * so converting to L/R stereo works properly. + */ + while (((src_channels % 2) == 0) && + ((src_channels / 2) >= dst_channels)) + { + SNDDBG(("Adding filter: Sound_ConvertMono\n")); + cvt->filters[cvt->filter_index++] = Sound_ConvertMono; + src_channels /= 2; + cvt->len_ratio /= 2; + } /* while */ + + if ( src_channels != dst_channels ) { + /* Uh oh.. */; + } /* if */ + } /* if */ + + /* Do rate conversion */ + cvt->rate_incr = 0.0; + if ((src_rate / 100) != (dst_rate / 100)) + { + Uint32 hi_rate, lo_rate; + int len_mult; + double len_ratio; + void (*rate_cvt)(Sound_AudioCVT *cvt, Uint16 *format); + + if (src_rate > dst_rate) + { + hi_rate = src_rate; + lo_rate = dst_rate; + SNDDBG(("Adding filter: Sound_RateDIV2\n")); + rate_cvt = Sound_RateDIV2; + len_mult = 1; + len_ratio = 0.5; + } /* if */ + else + { + hi_rate = dst_rate; + lo_rate = src_rate; + SNDDBG(("Adding filter: Sound_RateMUL2\n")); + rate_cvt = Sound_RateMUL2; + len_mult = 2; + len_ratio = 2.0; + } /* else */ + + /* If hi_rate = lo_rate*2^x then conversion is easy */ + while (((lo_rate * 2) / 100) <= (hi_rate / 100)) + { + cvt->filters[cvt->filter_index++] = rate_cvt; + cvt->len_mult *= len_mult; + lo_rate *= 2; + cvt->len_ratio *= len_ratio; + } /* while */ + + /* We may need a slow conversion here to finish up */ + if ((lo_rate / 100) != (hi_rate / 100)) + { + if (src_rate < dst_rate) + { + cvt->rate_incr = (double) lo_rate / hi_rate; + cvt->len_mult *= 2; + cvt->len_ratio /= cvt->rate_incr; + } /* if */ + else + { + cvt->rate_incr = (double) hi_rate / lo_rate; + cvt->len_ratio *= cvt->rate_incr; + } /* else */ + SNDDBG(("Adding filter: Sound_RateSLOW\n")); + cvt->filters[cvt->filter_index++] = Sound_RateSLOW; + } /* if */ + } /* if */ + + /* Set up the filter information */ + if (cvt->filter_index != 0) + { + cvt->needed = 1; + cvt->src_format = src_format; + cvt->dst_format = dst_format; + cvt->len = 0; + cvt->buf = NULL; + cvt->filters[cvt->filter_index] = NULL; + } /* if */ + + return(cvt->needed); +} /* Sound_BuildAudioCVT */ + +/* end of audio_convert.c ... */ + diff --git a/src/libs/decoders/docs/CREDITS.txt b/src/libs/decoders/docs/CREDITS.txt new file mode 100644 index 00000000..ffcc4b4b --- /dev/null +++ b/src/libs/decoders/docs/CREDITS.txt @@ -0,0 +1,67 @@ + ---------------------- + | SDL_sound credits. | + ---------------------- + +Initial API interface and implementation, +RAW driver, +VOC driver, +MPG123 driver, +WAV driver, +OGG driver, +SHN driver, +Unix support, +BeOS support: + Ryan C. Gordon + +Bug fixes, +FreeBSD testing: + Tsuyoshi Iguchi + +Code cleanups and fixes, +AIFF driver, +MikMod driver, +MIDI driver, +ModPlug driver, +FLAC driver: + Torbjörn Andersson + +autoconf, +MacOS X support: + Max Horn + +win32 support, +PocketPC support, +other fixes: + Tyler Montbriand + +AU driver, + Mattias Engdegård + +MacOS Classic support, +quicktime decoder, +OS X fixes: + Darrell Walisser + +Alternate audio conversion code: + Frank Ranostaj + +Initial Borland C++ project files: + Dominique Louis + +Bugfixes and stuff: + Eric Wing + +FLAC 1.1.3 updates: + Josh Coalson + +Fixes: + Chris Nelson + +Fixes: + Ozkan Sezer + +Other stuff: + Your name here! Patches go to icculus@icculus.org ... + +/* end of CREDITS ... */ + diff --git a/src/libs/decoders/docs/LICENSE.txt b/src/libs/decoders/docs/LICENSE.txt new file mode 100644 index 00000000..18b8e25a --- /dev/null +++ b/src/libs/decoders/docs/LICENSE.txt @@ -0,0 +1,528 @@ +Please note that the included source from Timidity, the MIDI decoder, is also + licensed under the following terms (GNU LGPL), but can also be used + separately under the GNU GPL, or the Perl Artistic License. Those licensing + terms are not reprinted here, but can be found on the web easily. + +The included source for libmpg123, the MP3 decoder, is also licensed under the + following terms (GNU LGPL). We make no promises about patents you might + violate or royalty payments you might have to pay with this or any decoder. + +Other external libraries (such as Ogg Vorbis, mikmod, etc) have their own + licenses which you should be aware of before including the related code + in your configuration. Most (if not all) are also under the LGPL, but are + external projects and we've got no control over them. + +If you want to use SDL_sound under a closed-source license, please contact + Ryan (icculus@icculus.org), and we can discuss an alternate license for + money to be distributed between the contributors to this work, but I'd + encourage you to abide by the LGPL, since the usual concern is whether you + can use this library without releasing your own source code (you can). + + +------------------- + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + 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 + Lesser General Public License for more details. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +