diff options
-rw-r--r-- | src/pcm_resample.h | 8 | ||||
-rw-r--r-- | src/pcm_resample_fallback.c | 33 | ||||
-rw-r--r-- | src/pcm_resample_libsamplerate.c | 53 |
3 files changed, 94 insertions, 0 deletions
diff --git a/src/pcm_resample.h b/src/pcm_resample.h index d6001550a..c80dfa8a3 100644 --- a/src/pcm_resample.h +++ b/src/pcm_resample.h @@ -60,4 +60,12 @@ pcm_resample_16(uint8_t channels, int16_t *dest_buffer, size_t dest_size, struct pcm_resample_state *state); +size_t +pcm_resample_24(uint8_t channels, + unsigned src_rate, + const int32_t *src_buffer, size_t src_size, + unsigned dest_rate, + int32_t *dest_buffer, size_t dest_size, + struct pcm_resample_state *state); + #endif diff --git a/src/pcm_resample_fallback.c b/src/pcm_resample_fallback.c index 0a913406c..da7dcaabe 100644 --- a/src/pcm_resample_fallback.c +++ b/src/pcm_resample_fallback.c @@ -58,3 +58,36 @@ pcm_resample_16(uint8_t channels, return dest_size; } + +size_t +pcm_resample_24(uint8_t channels, + unsigned src_rate, + const int32_t *src_buffer, mpd_unused size_t src_size, + unsigned dest_rate, + int32_t *dest_buffer, size_t dest_size, + mpd_unused struct pcm_resample_state *state) +{ + unsigned src_pos, dest_pos = 0; + unsigned dest_samples = dest_size / sizeof(*dest_buffer); + + switch (channels) { + case 1: + while (dest_pos < dest_samples) { + src_pos = dest_pos * src_rate / dest_rate; + + dest_buffer[dest_pos++] = src_buffer[src_pos]; + } + break; + case 2: + while (dest_pos < dest_samples) { + src_pos = dest_pos * src_rate / dest_rate; + src_pos &= ~1; + + dest_buffer[dest_pos++] = src_buffer[src_pos]; + dest_buffer[dest_pos++] = src_buffer[src_pos + 1]; + } + break; + } + + return dest_size; +} diff --git a/src/pcm_resample_libsamplerate.c b/src/pcm_resample_libsamplerate.c index 503a049b4..43a2a2f26 100644 --- a/src/pcm_resample_libsamplerate.c +++ b/src/pcm_resample_libsamplerate.c @@ -153,3 +153,56 @@ pcm_resample_16(uint8_t channels, return data->output_frames_gen * sizeof(*dest_buffer) * channels; } + +size_t +pcm_resample_24(uint8_t channels, + unsigned src_rate, + const int32_t *src_buffer, size_t src_size, + unsigned dest_rate, + int32_t *dest_buffer, size_t dest_size, + struct pcm_resample_state *state) +{ + SRC_DATA *data = &state->data; + size_t data_in_size; + size_t data_out_size; + int error; + + assert((src_size % (sizeof(*src_buffer) * channels)) == 0); + assert((dest_size % (sizeof(*dest_buffer) * channels)) == 0); + + pcm_resample_set(state, channels, src_rate, dest_rate); + + /* there was an error previously, and nothing has changed */ + if (state->error) + return 0; + + data->input_frames = src_size / sizeof(*src_buffer) / channels; + data_in_size = data->input_frames * sizeof(float) * channels; + if (data_in_size > state->data_in_size) { + state->data_in_size = data_in_size; + data->data_in = xrealloc(data->data_in, data_in_size); + } + + data->output_frames = dest_size / sizeof(*dest_buffer) / channels; + data_out_size = data->output_frames * sizeof(float) * channels; + if (data_out_size > state->data_out_size) { + state->data_out_size = data_out_size; + data->data_out = xrealloc(data->data_out, data_out_size); + } + + src_int_to_float_array(src_buffer, data->data_in, + data->input_frames * channels); + + error = src_process(state->state, data); + if (error) { + ERROR("error processing samples with libsamplerate: %s\n", + src_strerror(error)); + state->error = true; + return 0; + } + + src_float_to_int_array(data->data_out, dest_buffer, + data->output_frames_gen * channels); + + return data->output_frames_gen * sizeof(*dest_buffer) * channels; +} |