SoundDecoder_Sample* SoundDecoder_NewSampleFromFile(const char* file_name, SoundDecoder_AudioInfo* desired_format, size_t buffer_size) { const char* file_extension; ALmixer_RWops* rw_ops; SoundDecoder_Sample* new_sample; if(0 == s_isInitialized) { SoundDecoder_SetError(ERR_NOT_INITIALIZED); return NULL; } if(NULL == file_name) { SoundDecoder_SetError("No file specified"); return NULL; } file_extension = strrchr(file_name, '.'); if(NULL != file_extension) { file_extension++; } rw_ops = ALmixer_RWFromFile(file_name, "rb"); new_sample = SoundDecoder_NewSample(rw_ops, file_extension, desired_format, buffer_size); return new_sample; }
int SoundDecoder_Init() { size_t total_number_of_decoders; size_t i; size_t current_pos = 0; if(1 == s_isInitialized) { return 1; } if(NULL == s_errorPool) { s_errorPool = TError_CreateErrorPool(); } if(NULL == s_errorPool) { return 0; } total_number_of_decoders = sizeof(s_linkedDecoders) / sizeof(s_linkedDecoders[0]); s_availableDecoders = (const SoundDecoder_DecoderInfo **)malloc((total_number_of_decoders) * sizeof(SoundDecoder_DecoderInfo*)); if(NULL == s_availableDecoders) { SoundDecoder_SetError(ERR_OUT_OF_MEMORY); return 0; } /* Allocate memory for linked list of sound samples. */ s_listOfLoadedSamples = LinkedList_Create(); if(NULL == s_listOfLoadedSamples) { free(s_availableDecoders); s_availableDecoders = NULL; SoundDecoder_SetError(ERR_OUT_OF_MEMORY); return 0; } for(i = 0; s_linkedDecoders[i].funcs != NULL; i++) { s_linkedDecoders[i].available = s_linkedDecoders[i].funcs->init(); if(s_linkedDecoders[i].available) { s_availableDecoders[current_pos] = &(s_linkedDecoders[i].funcs->info); current_pos++; } } s_availableDecoders[current_pos] = NULL; s_isInitialized = 1; return 1; }
int SoundDecoder_Seek(SoundDecoder_Sample* sound_sample, size_t ms) { SoundDecoder_SampleInternal* internal_sample; int ret_val; BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0); BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0); BAIL_IF_MACRO(!(sound_sample->flags & SOUND_SAMPLEFLAG_CANSEEK), "Sound sample is not seekable", 0); internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque; ret_val = internal_sample->funcs->seek(sound_sample, ms); if(0 == ret_val) { sound_sample->flags |= SOUND_SAMPLEFLAG_ERROR; SoundDecoder_SetError("Seek failed"); return 0; } /* reset flags */ sound_sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; sound_sample->flags &= ~SOUND_SAMPLEFLAG_ERROR; sound_sample->flags &= ~SOUND_SAMPLEFLAG_EOF; return 1; }
void SoundDecoder_FreeSample(SoundDecoder_Sample* sound_sample) { SoundDecoder_SampleInternal* sample_internal; LinkedListNode* the_node; /* Quit unloads all samples, so it is not possible to free a sample * when not initialized. */ if(0 == s_isInitialized) { return; } if(sound_sample == NULL) { return; } /* SDL_sound keeps a linked list of all the loaded samples. * We want to remove the current sample from that list. */ the_node = LinkedList_Find(s_listOfLoadedSamples, sound_sample, NULL); if(NULL == the_node) { SoundDecoder_SetError("SoundDecoder_FreeSample: Internal Error, sample does not exist in linked list."); return; } LinkedList_Remove(s_listOfLoadedSamples, the_node); sample_internal = (SoundDecoder_SampleInternal*)sound_sample->opaque; /* Ugh...SDL_sound has a lot of pointers. * I hope I didn't miss any dynamic memory. */ /* Call close on the decoder */ sample_internal->funcs->close(sound_sample); if(NULL != sample_internal->rw) { sample_internal->rw->close(sample_internal->rw); } /* Ooops. The public buffer might be shared with the internal buffer. * Make sure to not accidentally double delete. */ if((NULL != sample_internal->buffer) && (sample_internal->buffer != sound_sample->buffer) ) { free(sample_internal->buffer); } free(sample_internal); if(NULL != sound_sample->buffer) { free(sound_sample->buffer); } free(sound_sample); }
size_t SoundDecoder_DecodeAll(SoundDecoder_Sample* sound_sample) { SoundDecoder_SampleInternal* internal_sample = NULL; void* data_buffer = NULL; size_t updated_buffer_size = 0; BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0); BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0); /* My original thought was to call SetBufferSize and resize to * the size needed to hold the entire decoded file utilizing total_time, * but it appears SDL_sound simply loops on SoundDecoder_Decode. * I suppose it is possible to partially decode or seek a file, and then * call DecodeAll so you won't have the whole thing in which case * my idea would waste memory. */ while( (0 == (sound_sample->flags & SOUND_SAMPLEFLAG_EOF) ) && (0 == (sound_sample->flags & SOUND_SAMPLEFLAG_ERROR)) ) { size_t bytes_decoded = SoundDecoder_Decode(sound_sample); void* realloced_ptr = realloc(data_buffer, updated_buffer_size + bytes_decoded); if(NULL == realloced_ptr) { sound_sample->flags |= SOUND_SAMPLEFLAG_ERROR; SoundDecoder_SetError(ERR_OUT_OF_MEMORY); if(NULL != data_buffer) { free(data_buffer); } return bytes_decoded; } data_buffer = realloced_ptr; /* copy the chunk of decoded PCM to the end of our new data buffer */ memcpy( ((char*)data_buffer) + updated_buffer_size, sound_sample->buffer, bytes_decoded ); updated_buffer_size += bytes_decoded; } internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque; if(internal_sample->buffer != sound_sample->buffer) { free(internal_sample->buffer); } free(sound_sample->buffer); sound_sample->buffer = data_buffer; sound_sample->buffer_size = updated_buffer_size; internal_sample->buffer = sound_sample->buffer; internal_sample->buffer_size = sound_sample->buffer_size; return sound_sample->buffer_size; }
int SoundDecoder_Init() { size_t total_number_of_decoders; size_t i; size_t current_pos = 0; if(1 == s_isInitialized) { return 1; } if(NULL == s_errorPool) { s_errorPool = TError_CreateErrorPool(); } if(NULL == s_errorPool) { return 0; } s_errorPool = TError_CreateErrorPool(); total_number_of_decoders = sizeof(s_linkedDecoders) / sizeof(s_linkedDecoders[0]); s_availableDecoders = (const SoundDecoder_DecoderInfo **)malloc((total_number_of_decoders) * sizeof(SoundDecoder_DecoderInfo*)); if(NULL == s_availableDecoders) { SoundDecoder_SetError(ERR_OUT_OF_MEMORY); return 0; } for(i = 0; s_linkedDecoders[i].funcs != NULL; i++) { s_linkedDecoders[i].available = s_linkedDecoders[i].funcs->init(); if(s_linkedDecoders[i].available) { s_availableDecoders[current_pos] = &(s_linkedDecoders[i].funcs->info); current_pos++; } } s_availableDecoders[current_pos] = NULL; s_isInitialized = 1; return 1; }
int SoundDecoder_Rewind(SoundDecoder_Sample* sound_sample) { SoundDecoder_SampleInternal* internal_sample; int ret_val; BAIL_IF_MACRO(!s_isInitialized, ERR_NOT_INITIALIZED, 0); BAIL_IF_MACRO(NULL == sound_sample, ERR_NULL_SAMPLE, 0); internal_sample = (SoundDecoder_SampleInternal*)sound_sample->opaque; ret_val = internal_sample->funcs->rewind(sound_sample); if(0 == ret_val) { sound_sample->flags |= SOUND_SAMPLEFLAG_ERROR; SoundDecoder_SetError("Rewind failed"); return 0; } /* reset flags */ sound_sample->flags &= ~SOUND_SAMPLEFLAG_EAGAIN; sound_sample->flags &= ~SOUND_SAMPLEFLAG_ERROR; sound_sample->flags &= ~SOUND_SAMPLEFLAG_EOF; return 1; }
SoundDecoder_Sample* SoundDecoder_NewSample(ALmixer_RWops* rw_ops, const char* file_extension, SoundDecoder_AudioInfo* desired_format, size_t buffer_size) { SoundDecoder_Sample* new_sample; SoundDecoder_SampleInternal* internal_sample; SoundElement* current_decoder; if(0 == s_isInitialized) { SoundDecoder_SetError(ERR_NOT_INITIALIZED); return NULL; } if(NULL == rw_ops) { SoundDecoder_SetError("No file specified"); return NULL; } new_sample = (SoundDecoder_Sample*)calloc(1, sizeof(SoundDecoder_Sample)); if(NULL == new_sample) { SoundDecoder_SetError(ERR_OUT_OF_MEMORY); return NULL; } internal_sample = (SoundDecoder_SampleInternal*)calloc(1, sizeof(SoundDecoder_SampleInternal)); if(NULL == internal_sample) { free(new_sample); SoundDecoder_SetError(ERR_OUT_OF_MEMORY); return NULL; } new_sample->buffer = calloc(1, buffer_size); if(NULL == new_sample->buffer) { free(internal_sample); free(new_sample); SoundDecoder_SetError(ERR_OUT_OF_MEMORY); return NULL; } new_sample->buffer_size = buffer_size; if(NULL != desired_format) { memcpy(&new_sample->desired, desired_format, sizeof(SoundDecoder_AudioInfo)); } internal_sample->rw = rw_ops; new_sample->opaque = internal_sample; /* if (rw_ops->file_name != NULL) { SoundDecoderInternal_SetOptionalFileName(new_sample->opaque, rw_ops->file_name); } */ if(NULL != file_extension) { for(current_decoder = &s_linkedDecoders[0]; current_decoder->funcs != NULL; current_decoder++) { if(current_decoder->available) { const char** decoder_file_extension = current_decoder->funcs->info.extensions; while(*decoder_file_extension) { if(0 == (SoundDecoder_strcasecmp(*decoder_file_extension, file_extension))) { if(Internal_LoadSample(current_decoder->funcs, new_sample, file_extension)) { return(new_sample); } break; /* go to the next decoder */ } decoder_file_extension++; } } } } /* no direct file_extensionension match? Try everything we've got... */ for(current_decoder = &s_linkedDecoders[0]; current_decoder->funcs != NULL; current_decoder++) { if(current_decoder->available) { int already_tried_decoder = 0; const char** decoder_file_extension = current_decoder->funcs->info.extensions; /* skip decoders we already tried from the above loop */ while(*decoder_file_extension) { if(SoundDecoder_strcasecmp(*decoder_file_extension, file_extension) == 0) { already_tried_decoder = 1; break; } decoder_file_extension++; } if(0 == already_tried_decoder) { if (Internal_LoadSample(current_decoder->funcs, new_sample, file_extension)) { return new_sample; } } } } /* could not find a decoder */ SoundDecoder_SetError(ERR_UNSUPPORTED_FORMAT); /* clean up the memory */ free(new_sample->opaque); if(NULL != new_sample->buffer) { free(new_sample->buffer); } free(new_sample); rw_ops->close(rw_ops); return NULL; }