diff options
Diffstat (limited to 'tinyDAV/src/audio/tdav_speex_resampler.c')
-rwxr-xr-x | tinyDAV/src/audio/tdav_speex_resampler.c | 355 |
1 files changed, 176 insertions, 179 deletions
diff --git a/tinyDAV/src/audio/tdav_speex_resampler.c b/tinyDAV/src/audio/tdav_speex_resampler.c index f71ddd2..75c51e5 100755 --- a/tinyDAV/src/audio/tdav_speex_resampler.c +++ b/tinyDAV/src/audio/tdav_speex_resampler.c @@ -29,168 +29,167 @@ #define TDAV_SPEEX_RESAMPLER_MAX_QUALITY 10 /** Speex resampler*/ -typedef struct tdav_speex_resampler_s -{ - TMEDIA_DECLARE_RESAMPLER; +typedef struct tdav_speex_resampler_s { + TMEDIA_DECLARE_RESAMPLER; - tsk_size_t in_size; - tsk_size_t out_size; - uint32_t in_channels; - uint32_t out_channels; - uint32_t bytes_per_sample; + tsk_size_t in_size; + tsk_size_t out_size; + uint32_t in_channels; + uint32_t out_channels; + uint32_t bytes_per_sample; - struct{ - void* ptr; - tsk_size_t size_in_samples; - } tmp_buffer; + struct { + void* ptr; + tsk_size_t size_in_samples; + } tmp_buffer; - SpeexResamplerState *state; + SpeexResamplerState *state; } tdav_speex_resampler_t; static int tdav_speex_resampler_open(tmedia_resampler_t* self, uint32_t in_freq, uint32_t out_freq, uint32_t frame_duration, uint32_t in_channels, uint32_t out_channels, uint32_t quality, uint32_t bits_per_sample) { - tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; - int ret = 0; - uint32_t bytes_per_sample = (bits_per_sample >> 3); - - if (in_channels != 1 && in_channels != 2) { - TSK_DEBUG_ERROR("%d not valid as input channel", in_channels); - return -1; - } - if (out_channels != 1 && out_channels != 2) { - TSK_DEBUG_ERROR("%d not valid as output channel", out_channels); - return -1; - } - if (bytes_per_sample != sizeof(spx_int16_t) && bytes_per_sample != sizeof(float)) { - TSK_DEBUG_ERROR("%d not valid as bits_per_sample", bits_per_sample); - return -1; - } - - if (!(resampler->state = speex_resampler_init(in_channels, in_freq, out_freq, TSK_CLAMP(0, quality, TDAV_SPEEX_RESAMPLER_MAX_QUALITY), &ret))) { - TSK_DEBUG_ERROR("speex_resampler_init() returned %d", ret); - return -2; - } - - resampler->bytes_per_sample = bytes_per_sample; - resampler->in_size = ((in_freq * frame_duration) / 1000) << (in_channels == 2 ? 1 : 0); - resampler->out_size = ((out_freq * frame_duration) / 1000) << (out_channels == 2 ? 1 : 0); - resampler->in_channels = in_channels; - resampler->out_channels = out_channels; - - if (in_channels != out_channels) { - resampler->tmp_buffer.size_in_samples = ((TSK_MAX(in_freq, out_freq) * frame_duration) / 1000) << (TSK_MAX(in_channels, out_channels) == 2 ? 1 : 0); - if (!(resampler->tmp_buffer.ptr = tsk_realloc(resampler->tmp_buffer.ptr, resampler->tmp_buffer.size_in_samples * resampler->bytes_per_sample))) { - resampler->tmp_buffer.size_in_samples = 0; - return -2; - } - } - - return 0; + tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; + int ret = 0; + uint32_t bytes_per_sample = (bits_per_sample >> 3); + + if (in_channels != 1 && in_channels != 2) { + TSK_DEBUG_ERROR("%d not valid as input channel", in_channels); + return -1; + } + if (out_channels != 1 && out_channels != 2) { + TSK_DEBUG_ERROR("%d not valid as output channel", out_channels); + return -1; + } + if (bytes_per_sample != sizeof(spx_int16_t) && bytes_per_sample != sizeof(float)) { + TSK_DEBUG_ERROR("%d not valid as bits_per_sample", bits_per_sample); + return -1; + } + + if (!(resampler->state = speex_resampler_init(in_channels, in_freq, out_freq, TSK_CLAMP(0, quality, TDAV_SPEEX_RESAMPLER_MAX_QUALITY), &ret))) { + TSK_DEBUG_ERROR("speex_resampler_init() returned %d", ret); + return -2; + } + + resampler->bytes_per_sample = bytes_per_sample; + resampler->in_size = ((in_freq * frame_duration) / 1000) << (in_channels == 2 ? 1 : 0); + resampler->out_size = ((out_freq * frame_duration) / 1000) << (out_channels == 2 ? 1 : 0); + resampler->in_channels = in_channels; + resampler->out_channels = out_channels; + + if (in_channels != out_channels) { + resampler->tmp_buffer.size_in_samples = ((TSK_MAX(in_freq, out_freq) * frame_duration) / 1000) << (TSK_MAX(in_channels, out_channels) == 2 ? 1 : 0); + if (!(resampler->tmp_buffer.ptr = tsk_realloc(resampler->tmp_buffer.ptr, resampler->tmp_buffer.size_in_samples * resampler->bytes_per_sample))) { + resampler->tmp_buffer.size_in_samples = 0; + return -2; + } + } + + return 0; } static tsk_size_t tdav_speex_resampler_process(tmedia_resampler_t* self, const void* in_data, tsk_size_t in_size_in_sample, void* out_data, tsk_size_t out_size_in_sample) { - tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; - int err = RESAMPLER_ERR_SUCCESS; - spx_uint32_t _out_size_in_sample = (spx_uint32_t)out_size_in_sample; - if (!resampler->state || !out_data) { - TSK_DEBUG_ERROR("Invalid parameter"); - return 0; - } - - if (in_size_in_sample != resampler->in_size) { - TSK_DEBUG_ERROR("Input data has wrong size"); - return 0; - } - - if (out_size_in_sample < resampler->out_size) { - TSK_DEBUG_ERROR("Output data is too short"); - return 0; - } - - if (resampler->in_channels == resampler->out_channels) { - if (resampler->bytes_per_sample == sizeof(spx_int16_t)) { - err = speex_resampler_process_int(resampler->state, 0, - (const spx_int16_t *)in_data, (spx_uint32_t *)&in_size_in_sample, - (spx_int16_t *)out_data, &_out_size_in_sample); - } - else { - err = speex_resampler_process_float(resampler->state, 0, - (const float *)in_data, (spx_uint32_t *)&in_size_in_sample, - (float *)out_data, &_out_size_in_sample); - } - } - else { - spx_uint32_t i, j; - // in_channels = 1, out_channels = 2 - if (resampler->in_channels == 1) { - if (resampler->bytes_per_sample == sizeof(spx_int16_t)) { - err = speex_resampler_process_int(resampler->state, 0, (const spx_int16_t *)in_data, (spx_uint32_t *)&in_size_in_sample, resampler->tmp_buffer.ptr, &_out_size_in_sample); - if (err == RESAMPLER_ERR_SUCCESS) { - spx_int16_t* pout_data = (spx_int16_t*)(out_data); - for (i = 0, j = 0; i < _out_size_in_sample; ++i, j += 2) { - pout_data[j] = pout_data[j + 1] = *(((const spx_int16_t*)resampler->tmp_buffer.ptr) + i); - } - } - } - else { - err = speex_resampler_process_float(resampler->state, 0, (const float *)in_data, (spx_uint32_t *)&in_size_in_sample, resampler->tmp_buffer.ptr, &_out_size_in_sample); - if (err == RESAMPLER_ERR_SUCCESS) { - float* pout_data = (float*)(out_data); - for (i = 0, j = 0; i < _out_size_in_sample; ++i, j += 2) { - pout_data[j] = pout_data[j + 1] = *(((const float*)resampler->tmp_buffer.ptr) + i); - } - } - } - - } - else { - // in_channels = 2, out_channels = 1 - spx_uint32_t _out_size2_in_sample = (_out_size_in_sample << 1); - if (resampler->bytes_per_sample == sizeof(spx_int16_t)) { - err = speex_resampler_process_int(resampler->state, 0, - (const spx_int16_t *)in_data, (spx_uint32_t *)&in_size_in_sample, - (spx_int16_t *)resampler->tmp_buffer.ptr, &_out_size2_in_sample); - if (err == RESAMPLER_ERR_SUCCESS) { - spx_int16_t* pout_data = (spx_int16_t*)(out_data); - _out_size_in_sample = (spx_uint32_t)resampler->out_size; - for (i = 0, j = 0; j < _out_size2_in_sample; ++i, j += 2) { - pout_data[i] = *(((const spx_int16_t*)resampler->tmp_buffer.ptr) + j); - } - } - } - else { - err = speex_resampler_process_float(resampler->state, 0, - (const float *)in_data, (spx_uint32_t *)&in_size_in_sample, - (float *)resampler->tmp_buffer.ptr, &_out_size2_in_sample); - if (err == RESAMPLER_ERR_SUCCESS) { - float* pout_data = (float*)(out_data); - for (i = 0, j = 0; j < _out_size2_in_sample; ++i, j += 2) { - pout_data[i] = *(((const float*)resampler->tmp_buffer.ptr) + j); - } - } - } - } - } - - if (err != RESAMPLER_ERR_SUCCESS) { - TSK_DEBUG_ERROR("speex_resampler_process_int() failed with error code %d", err); - return 0; - } - return (tsk_size_t)_out_size_in_sample; + tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; + int err = RESAMPLER_ERR_SUCCESS; + spx_uint32_t _out_size_in_sample = (spx_uint32_t)out_size_in_sample; + if (!resampler->state || !out_data) { + TSK_DEBUG_ERROR("Invalid parameter"); + return 0; + } + + if (in_size_in_sample != resampler->in_size) { + TSK_DEBUG_ERROR("Input data has wrong size"); + return 0; + } + + if (out_size_in_sample < resampler->out_size) { + TSK_DEBUG_ERROR("Output data is too short"); + return 0; + } + + if (resampler->in_channels == resampler->out_channels) { + if (resampler->bytes_per_sample == sizeof(spx_int16_t)) { + err = speex_resampler_process_int(resampler->state, 0, + (const spx_int16_t *)in_data, (spx_uint32_t *)&in_size_in_sample, + (spx_int16_t *)out_data, &_out_size_in_sample); + } + else { + err = speex_resampler_process_float(resampler->state, 0, + (const float *)in_data, (spx_uint32_t *)&in_size_in_sample, + (float *)out_data, &_out_size_in_sample); + } + } + else { + spx_uint32_t i, j; + // in_channels = 1, out_channels = 2 + if (resampler->in_channels == 1) { + if (resampler->bytes_per_sample == sizeof(spx_int16_t)) { + err = speex_resampler_process_int(resampler->state, 0, (const spx_int16_t *)in_data, (spx_uint32_t *)&in_size_in_sample, resampler->tmp_buffer.ptr, &_out_size_in_sample); + if (err == RESAMPLER_ERR_SUCCESS) { + spx_int16_t* pout_data = (spx_int16_t*)(out_data); + for (i = 0, j = 0; i < _out_size_in_sample; ++i, j += 2) { + pout_data[j] = pout_data[j + 1] = *(((const spx_int16_t*)resampler->tmp_buffer.ptr) + i); + } + } + } + else { + err = speex_resampler_process_float(resampler->state, 0, (const float *)in_data, (spx_uint32_t *)&in_size_in_sample, resampler->tmp_buffer.ptr, &_out_size_in_sample); + if (err == RESAMPLER_ERR_SUCCESS) { + float* pout_data = (float*)(out_data); + for (i = 0, j = 0; i < _out_size_in_sample; ++i, j += 2) { + pout_data[j] = pout_data[j + 1] = *(((const float*)resampler->tmp_buffer.ptr) + i); + } + } + } + + } + else { + // in_channels = 2, out_channels = 1 + spx_uint32_t _out_size2_in_sample = (_out_size_in_sample << 1); + if (resampler->bytes_per_sample == sizeof(spx_int16_t)) { + err = speex_resampler_process_int(resampler->state, 0, + (const spx_int16_t *)in_data, (spx_uint32_t *)&in_size_in_sample, + (spx_int16_t *)resampler->tmp_buffer.ptr, &_out_size2_in_sample); + if (err == RESAMPLER_ERR_SUCCESS) { + spx_int16_t* pout_data = (spx_int16_t*)(out_data); + _out_size_in_sample = (spx_uint32_t)resampler->out_size; + for (i = 0, j = 0; j < _out_size2_in_sample; ++i, j += 2) { + pout_data[i] = *(((const spx_int16_t*)resampler->tmp_buffer.ptr) + j); + } + } + } + else { + err = speex_resampler_process_float(resampler->state, 0, + (const float *)in_data, (spx_uint32_t *)&in_size_in_sample, + (float *)resampler->tmp_buffer.ptr, &_out_size2_in_sample); + if (err == RESAMPLER_ERR_SUCCESS) { + float* pout_data = (float*)(out_data); + for (i = 0, j = 0; j < _out_size2_in_sample; ++i, j += 2) { + pout_data[i] = *(((const float*)resampler->tmp_buffer.ptr) + j); + } + } + } + } + } + + if (err != RESAMPLER_ERR_SUCCESS) { + TSK_DEBUG_ERROR("speex_resampler_process_int() failed with error code %d", err); + return 0; + } + return (tsk_size_t)_out_size_in_sample; } static int tdav_speex_resampler_close(tmedia_resampler_t* self) { - tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; + tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; - if (resampler->state) { - speex_resampler_destroy(resampler->state); - resampler->state = tsk_null; - } - return 0; + if (resampler->state) { + speex_resampler_destroy(resampler->state); + resampler->state = tsk_null; + } + return 0; } @@ -202,51 +201,49 @@ static int tdav_speex_resampler_close(tmedia_resampler_t* self) /* constructor */ static tsk_object_t* tdav_speex_resampler_ctor(tsk_object_t * self, va_list * app) { - tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; - if (resampler){ - /* init base */ - tmedia_resampler_init(TMEDIA_RESAMPLER(resampler)); - /* init self */ - } - return self; + tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; + if (resampler) { + /* init base */ + tmedia_resampler_init(TMEDIA_RESAMPLER(resampler)); + /* init self */ + } + return self; } /* destructor */ static tsk_object_t* tdav_speex_resampler_dtor(tsk_object_t * self) { - tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; - if (resampler){ - /* deinit base */ - tmedia_resampler_deinit(TMEDIA_RESAMPLER(resampler)); - /* deinit self */ - if (resampler->state) { - speex_resampler_destroy(resampler->state); - resampler->state = tsk_null; - } - TSK_FREE(resampler->tmp_buffer.ptr); - - TSK_DEBUG_INFO("*** SpeexDSP resampler (plugin) destroyed ***"); - } - - return self; + tdav_speex_resampler_t *resampler = (tdav_speex_resampler_t *)self; + if (resampler) { + /* deinit base */ + tmedia_resampler_deinit(TMEDIA_RESAMPLER(resampler)); + /* deinit self */ + if (resampler->state) { + speex_resampler_destroy(resampler->state); + resampler->state = tsk_null; + } + TSK_FREE(resampler->tmp_buffer.ptr); + + TSK_DEBUG_INFO("*** SpeexDSP resampler (plugin) destroyed ***"); + } + + return self; } /* object definition */ -static const tsk_object_def_t tdav_speex_resampler_def_s = -{ - sizeof(tdav_speex_resampler_t), - tdav_speex_resampler_ctor, - tdav_speex_resampler_dtor, - tsk_null, +static const tsk_object_def_t tdav_speex_resampler_def_s = { + sizeof(tdav_speex_resampler_t), + tdav_speex_resampler_ctor, + tdav_speex_resampler_dtor, + tsk_null, }; /* plugin definition*/ -static const tmedia_resampler_plugin_def_t tdav_speex_resampler_plugin_def_s = -{ - &tdav_speex_resampler_def_s, +static const tmedia_resampler_plugin_def_t tdav_speex_resampler_plugin_def_s = { + &tdav_speex_resampler_def_s, - "Audio Resampler based on Speex", + "Audio Resampler based on Speex", - tdav_speex_resampler_open, - tdav_speex_resampler_process, - tdav_speex_resampler_close, + tdav_speex_resampler_open, + tdav_speex_resampler_process, + tdav_speex_resampler_close, }; const tmedia_resampler_plugin_def_t *tdav_speex_resampler_plugin_def_t = &tdav_speex_resampler_plugin_def_s; |