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 */
/* * 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 */
/* * 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) { 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 */
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 */
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 */
/* * 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 */