# HG changeset patch # User Ryan C. Gordon # Date 1109534005 0 # Node ID 137c0b00ea4cc39fe5bd90d8ee09e57869a81b75 # Parent 1c09756bc0388c242b318d1905326115ecbf2983 Added Sound_NewSampleFromMem(), and implementation of RWops pooling. diff -r 1c09756bc038 -r 137c0b00ea4c SDL_sound.c --- a/SDL_sound.c Sun Feb 27 19:50:54 2005 +0000 +++ b/SDL_sound.c Sun Feb 27 19:53:25 2005 +0000 @@ -450,6 +450,10 @@ 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)) @@ -693,6 +697,7 @@ 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) @@ -702,6 +707,26 @@ } /* 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; diff -r 1c09756bc038 -r 137c0b00ea4c SDL_sound.h --- a/SDL_sound.h Sun Feb 27 19:50:54 2005 +0000 +++ b/SDL_sound.h Sun Feb 27 19:53:25 2005 +0000 @@ -452,6 +452,39 @@ 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. * @@ -462,6 +495,9 @@ * 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. diff -r 1c09756bc038 -r 137c0b00ea4c SDL_sound_internal.h --- a/SDL_sound_internal.h Sun Feb 27 19:50:54 2005 +0000 +++ b/SDL_sound_internal.h Sun Feb 27 19:53:25 2005 +0000 @@ -65,6 +65,14 @@ #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. */ @@ -240,6 +248,7 @@ extern SNDDECLSPEC int Sound_ConvertAudio(Sound_AudioCVT *cvt); +typedef void (*MixFunc)(float *dst, void *src, Uint32 frames, float *gains); typedef struct __SOUND_SAMPLEINTERNAL__ { @@ -252,6 +261,8 @@ Uint32 buffer_size; void *decoder_private; Sint32 total_time; + Uint32 mix_position; + MixFunc mix; } Sound_SampleInternal; diff -r 1c09756bc038 -r 137c0b00ea4c TODO --- a/TODO Sun Feb 27 19:50:54 2005 +0000 +++ b/TODO Sun Feb 27 19:53:25 2005 +0000 @@ -15,6 +15,8 @@ - Hack on the experimental audio conversion routines. - Handle compression and other chunks in WAV files. - Handle compression and other chunks in AIFF-C files. +- Reduce malloc() pressure. +- Maybe allow an external allocator? Quicktime stuff that'd be cool, but isn't crucial: - Integrate decoders/quicktime.c with build system (for OS X)? diff -r 1c09756bc038 -r 137c0b00ea4c extra_rwops.c --- a/extra_rwops.c Sun Feb 27 19:50:54 2005 +0000 +++ b/extra_rwops.c Sun Feb 27 19:53:25 2005 +0000 @@ -130,6 +130,88 @@ } /* RWops_RWRefCounter_new */ + + /* + * RWops pooling... + */ + +static SDL_RWops *rwops_pool = NULL; +static SDL_mutex *rwops_pool_mutex = NULL; + +int RWops_pooled_init(void) +{ + const int preallocate = 50; + int i; + + rwops_pool_mutex = SDL_CreateMutex(); + if (rwops_pool_mutex == NULL) + return(0); + + for (i = 0; i < preallocate; i++) + free_pooled_rwops(alloc_pooled_rwops()); + + return(1); +} /* RWops_pooled_init */ + + +void RWops_pooled_deinit(void) +{ + SDL_RWops *cur; + SDL_RWops *next; + + if (rwops_pool_mutex == NULL) + return; /* never initialized. */ + + SDL_LockMutex(rwops_pool_mutex); + /* all allocated rwops must be in the pool now, or the memory leaks. */ + cur = rwops_pool; + rwops_pool = NULL; + SDL_UnlockMutex(rwops_pool_mutex); + SDL_DestroyMutex(rwops_pool_mutex); + rwops_pool_mutex = NULL; + + while (cur) + { + next = (SDL_RWops *) (cur->hidden.unknown.data1); + free(cur); + cur = next; + } /* while */ +} /* RWops_pooled_deinit */ + + +SDL_RWops *RWops_pooled_alloc(void) +{ + SDL_RWops *rw; + if (rwops_pool_mutex == NULL) + return(NULL); /* never initialized. */ + + SDL_LockMutex(rwops_pool_mutex); + rw = rwops_pool; + if (rw) + rwops_pool = (SDL_RWops *) (rw->hidden.unknown.data1); + SDL_UnlockMutex(rwops_pool_mutex); + + if (!rw) + rw = (SDL_RWops *) malloc(sizeof (SDL_RWops)); + + return(rw); +} /* RWops_pooled_alloc */ + + +void RWops_pooled_free(SDL_RWops *rw) +{ + if (rwops_pool_mutex == NULL) + return; /* never initialized...why are we here? */ + + if (rw == NULL) + return; + + SDL_LockMutex(rwops_pool_mutex); + rw->hidden.unknown.data1 = rwops_pool; + rwops_pool = rw; + SDL_UnlockMutex(rwops_pool_mutex); +} /* RWops_pooled_free */ + /* end of extra_rwops.c ... */ diff -r 1c09756bc038 -r 137c0b00ea4c extra_rwops.h --- a/extra_rwops.h Sun Feb 27 19:50:54 2005 +0000 +++ b/extra_rwops.h Sun Feb 27 19:53:25 2005 +0000 @@ -61,6 +61,24 @@ /* Increment a reference counting RWops's refcount by one. */ void RWops_RWRefCounter_addRef(SDL_RWops *rw); + +/* + * RWops pooling. This is to reduce malloc() pressure for audio that is + * placed into Sound_Samples over and over again. + */ + +/* Call this first. */ +int RWops_pooled_init(void); + +/* Call this last. */ +int RWops_pooled_deinit(void); + +/* Get a new RWops, allocating if needed. */ +SDL_RWops *RWops_pooled_alloc(void); + +/* Return a RWops to the pool for reuse. */ +void RWops_pooled_free(SDL_RWops *rw) + #ifdef __cplusplus } #endif