1
0
Fork 0

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").
This commit is contained in:
Ryan C. Gordon 2019-10-26 06:18:02 +02:00 committed by Patryk Obara
parent 52a958270f
commit 0420181d59
6 changed files with 3296 additions and 0 deletions

View file

@ -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 <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#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 ... */

View file

@ -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 \<email@emailhost.dom\>" */
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 ... */

View file

@ -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 <assert.h>
#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 ... */

View file

@ -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 <config.h>
#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 ... */

View file

@ -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 ... */

View file

@ -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.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!