From 4be49546e16eb5d7aa783285e1f0c2c5ed179d1a Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 22 Apr 2013 21:29:49 +0200 Subject: decoder api: use AVFrame for passing data to the decoder. Switch to libavresample for format conversion. --- src/Makefile | 5 - src/audio_format.c | 14 ++ src/audio_format.h | 4 + src/decoder/libav_decoder_plugin.c | 93 ++----- src/decoder_api.c | 48 ++-- src/decoder_api.h | 8 +- src/filter/convert_filter_plugin.c | 4 + src/main.c | 7 - src/pcm_channels.c | 246 ------------------- src/pcm_channels.h | 80 ------ src/pcm_convert.c | 385 ++++++----------------------- src/pcm_convert.h | 29 +-- src/pcm_format.c | 487 ------------------------------------- src/pcm_format.h | 93 ------- src/pcm_resample.c | 159 ------------ src/pcm_resample.h | 164 ------------- src/pcm_resample_fallback.c | 118 --------- src/pcm_resample_internal.h | 97 -------- src/pcm_resample_libsamplerate.c | 312 ------------------------ 19 files changed, 165 insertions(+), 2188 deletions(-) delete mode 100644 src/pcm_channels.c delete mode 100644 src/pcm_channels.h delete mode 100644 src/pcm_format.c delete mode 100644 src/pcm_format.h delete mode 100644 src/pcm_resample.c delete mode 100644 src/pcm_resample.h delete mode 100644 src/pcm_resample_fallback.c delete mode 100644 src/pcm_resample_internal.h delete mode 100644 src/pcm_resample_libsamplerate.c diff --git a/src/Makefile b/src/Makefile index c6820dff..d62f0b9b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -86,18 +86,13 @@ OBJS = aiff.o \ page.o \ path.o \ pcm_buffer.o \ - pcm_channels.o \ pcm_convert.o \ pcm_dither.o \ pcm_dsd.o \ pcm_dsd_usb.o \ pcm_export.o \ - pcm_format.o \ pcm_mix.o \ pcm_pack.o \ - pcm_resample.o \ - pcm_resample_fallback.o \ - pcm_resample_libsamplerate.o \ pcm_volume.o \ permission.o \ pipe.o \ diff --git a/src/audio_format.c b/src/audio_format.c index 45d94a85..dc46604f 100644 --- a/src/audio_format.c +++ b/src/audio_format.c @@ -22,6 +22,8 @@ #include #include +#include + void audio_format_mask_apply(struct audio_format *af, const struct audio_format *mask) @@ -85,3 +87,15 @@ audio_format_to_string(const struct audio_format *af, return s->buffer; } + +enum AVSampleFormat sample_fmt_native_to_libav(enum sample_format sample_fmt) +{ + switch (sample_fmt) { + case SAMPLE_FORMAT_S8: return AV_SAMPLE_FMT_U8; + case SAMPLE_FORMAT_S16: return AV_SAMPLE_FMT_S16; + case SAMPLE_FORMAT_S24_P32: + case SAMPLE_FORMAT_S32: return AV_SAMPLE_FMT_S32; + case SAMPLE_FORMAT_FLOAT: return AV_SAMPLE_FMT_FLT; + default: return AV_SAMPLE_FMT_NONE; + } +} diff --git a/src/audio_format.h b/src/audio_format.h index bf77add3..c6527e6a 100644 --- a/src/audio_format.h +++ b/src/audio_format.h @@ -25,6 +25,8 @@ #include #include +#include + enum sample_format { SAMPLE_FORMAT_UNDEFINED = 0, @@ -304,4 +306,6 @@ const char * audio_format_to_string(const struct audio_format *af, struct audio_format_string *s); +enum AVSampleFormat sample_fmt_native_to_libav(enum sample_format); + #endif diff --git a/src/decoder/libav_decoder_plugin.c b/src/decoder/libav_decoder_plugin.c index 88dd4a8f..05b9b2fb 100644 --- a/src/decoder/libav_decoder_plugin.c +++ b/src/decoder/libav_decoder_plugin.c @@ -41,6 +41,7 @@ #include #include #include +#include #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "libav" @@ -159,40 +160,6 @@ static int64_t time_to_libav(double t, const AVRational time_base) return av_rescale_q((int64_t)(t * 1024), (AVRational){1, 1024}, time_base); } -/** - * Copy PCM data from a AVFrame to an interleaved buffer. - */ -static int copy_interleave_frame(const AVCodecContext *codec_context, - const AVFrame *frame, - uint8_t *buffer, size_t buffer_size) -{ - int plane_size; - const int data_size = - av_samples_get_buffer_size(&plane_size, - codec_context->channels, - frame->nb_samples, - codec_context->sample_fmt, 1); - uint16_t *dst = (uint16_t*)buffer; - - if (buffer_size < (size_t)data_size) - /* buffer is too small - shouldn't happen */ - return AVERROR(EINVAL); - - if (av_sample_fmt_is_planar(codec_context->sample_fmt) && - codec_context->channels > 1) { - for (int i = 0; i < frame->nb_samples; i++) { - for (int j = 0; j < codec_context->channels; j++) - dst[i * codec_context->channels + j] = ((uint16_t*)frame->extended_data[j])[i]; - } - } else { - memcpy(buffer, frame->extended_data[0], data_size); - } - - return data_size; -} - -#define AVCODEC_MAX_AUDIO_FRAME_SIZE 50000 - static enum decoder_command libav_send_packet(struct decoder *decoder, struct input_stream *is, const AVPacket *packet, @@ -200,9 +167,6 @@ static enum decoder_command libav_send_packet(struct decoder *decoder, const AVRational *time_base) { AVPacket packet2 = *packet; - uint8_t aligned_buffer[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 + 16]; - const size_t buffer_size = sizeof(aligned_buffer); - enum decoder_command cmd = DECODE_COMMAND_NONE; if (packet->pts != (int64_t)AV_NOPTS_VALUE) @@ -210,37 +174,31 @@ static enum decoder_command libav_send_packet(struct decoder *decoder, while (packet2.size > 0 && cmd == DECODE_COMMAND_NONE) { - int audio_size = buffer_size; - AVFrame frame; + AVFrame *frame = av_frame_alloc(); int got_frame = 0; - int len = avcodec_decode_audio4(codec_context, - &frame, &got_frame, - &packet2); - if (len >= 0 && got_frame) { - audio_size = copy_interleave_frame(codec_context, - &frame, - aligned_buffer, - buffer_size); - if (audio_size < 0) - len = audio_size; - } else if (len >= 0) - len = -1; - - if (len < 0) { - /* if error, we skip the frame */ + int ret; + + if (!frame) { + g_warning("Error allocating a frame for decoding.\n"); + break; + } + + ret = avcodec_decode_audio4(codec_context, frame, &got_frame, &packet2); + if (ret < 0) { g_message("decoding failed, frame skipped\n"); break; } - packet2.data += len; - packet2.size -= len; + packet2.data += ret; + packet2.size -= ret; - if (audio_size <= 0) + if (!got_frame) { + if (!ret) + break; continue; + } - cmd = decoder_data(decoder, is, - aligned_buffer, audio_size, - codec_context->bit_rate / 1000); + cmd = decoder_data(decoder, is, frame, codec_context->bit_rate / 1000); } return cmd; } @@ -248,17 +206,9 @@ static enum decoder_command libav_send_packet(struct decoder *decoder, static enum sample_format libav_sample_format(const AVCodecContext *codec_context) { switch (codec_context->sample_fmt) { - case AV_SAMPLE_FMT_S16: - case AV_SAMPLE_FMT_S16P: - return SAMPLE_FORMAT_S16; - - case AV_SAMPLE_FMT_S32: - return SAMPLE_FORMAT_S32; - - default: - g_warning("Unsupported libavcodec SampleFormat value: %d", - codec_context->sample_fmt); - return SAMPLE_FORMAT_UNDEFINED; + case AV_SAMPLE_FMT_S16: return SAMPLE_FORMAT_S16; + case AV_SAMPLE_FMT_S32: return SAMPLE_FORMAT_S32; + default: return SAMPLE_FORMAT_UNDEFINED; } } @@ -298,6 +248,7 @@ static void libav_decode(struct decoder *decoder, struct input_stream *input) values into AVCodecContext.channels - a change that will be reverted later by avcodec_decode_audio3() */ + av_opt_set_int(dec, "refcounted_frames", 1, 0); ret = avcodec_open2(dec, codec, NULL); if (ret < 0) { g_warning("Could not open codec\n"); diff --git a/src/decoder_api.c b/src/decoder_api.c index b8edb8aa..bcab6010 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -30,6 +30,10 @@ #include +#include +#include +#include + #include #include @@ -347,25 +351,24 @@ static bool update_stream_tag(struct decoder *decoder, struct input_stream *is) enum decoder_command decoder_data(struct decoder *decoder, struct input_stream *is, - const void *_data, size_t length, + AVFrame *frame, uint16_t kbit_rate) { struct decoder_control *dc = decoder->dc; - const char *data = _data; - GError *error = NULL; - enum decoder_command cmd; + enum decoder_command cmd = DECODE_COMMAND_NONE; + uint8_t *data; + int length; assert(dc->state == DECODE_STATE_DECODE); assert(dc->pipe != NULL); - assert(length % audio_format_frame_size(&dc->in_audio_format) == 0); decoder_lock(dc); cmd = decoder_get_virtual_command(decoder); decoder_unlock(dc); if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK || - length == 0) - return cmd; + !frame->nb_samples) + goto finish; /* send stream tags */ @@ -383,23 +386,27 @@ enum decoder_command decoder_data(struct decoder *decoder, cmd = do_send_tag(decoder, decoder->stream_tag); if (cmd != DECODE_COMMAND_NONE) - return cmd; + goto finish; } if (!audio_format_equals(&dc->in_audio_format, &dc->out_audio_format)) { - data = pcm_convert(&decoder->conv_state, - &dc->in_audio_format, data, length, - &dc->out_audio_format, &length, - &error); - if (data == NULL) { + AVFrame *tmp = pcm_convert(&decoder->conv_state, + &dc->in_audio_format, &dc->out_audio_format, frame); + if (!tmp) { /* the PCM conversion has failed - stop playback, since we have no better way to bail out */ - g_warning("%s", error->message); - return DECODE_COMMAND_STOP; + g_warning("Error converting to output format.\n"); + cmd = DECODE_COMMAND_STOP; + goto finish; } + av_frame_free(&frame); + frame = tmp; } + length = frame->nb_samples * av_get_bytes_per_sample(frame->format) * + dc->out_audio_format.channels; + data = frame->data[0]; while (length > 0) { struct music_chunk *chunk; char *dest; @@ -409,7 +416,8 @@ enum decoder_command decoder_data(struct decoder *decoder, chunk = decoder_get_chunk(decoder); if (chunk == NULL) { assert(dc->command != DECODE_COMMAND_NONE); - return dc->command; + cmd = dc->command; + goto finish; } dest = music_chunk_write(chunk, &dc->out_audio_format, @@ -448,12 +456,16 @@ enum decoder_command decoder_data(struct decoder *decoder, audio_format_time_to_size(&dc->out_audio_format); if (dc->end_ms > 0 && - decoder->timestamp >= dc->end_ms / 1000.0) + decoder->timestamp >= dc->end_ms / 1000.0) { /* the end of this range has been reached: stop decoding */ - return DECODE_COMMAND_STOP; + cmd = DECODE_COMMAND_STOP; + break; + } } +finish: + av_frame_free(&frame); return DECODE_COMMAND_NONE; } diff --git a/src/decoder_api.h b/src/decoder_api.h index 6e011c39..4ac00142 100644 --- a/src/decoder_api.h +++ b/src/decoder_api.h @@ -36,6 +36,8 @@ #include "audio_format.h" #include "conf.h" +#include + #include /** @@ -126,10 +128,8 @@ decoder_timestamp(struct decoder *decoder, double t); * @return the current command, or DECODE_COMMAND_NONE if there is no * command pending */ -enum decoder_command -decoder_data(struct decoder *decoder, struct input_stream *is, - const void *data, size_t length, - uint16_t kbit_rate); +enum decoder_command decoder_data(struct decoder *decoder, struct input_stream *is, + AVFrame *frame, uint16_t kbit_rate); /** * This function is called by the decoder plugin when it has diff --git a/src/filter/convert_filter_plugin.c b/src/filter/convert_filter_plugin.c index c55b69af..40be67f6 100644 --- a/src/filter/convert_filter_plugin.c +++ b/src/filter/convert_filter_plugin.c @@ -111,6 +111,9 @@ convert_filter_filter(struct filter *_filter, const void *src, size_t src_size, return src; } + // FIXME + return NULL; +#if 0 dest = pcm_convert(&filter->state, &filter->in_audio_format, src, src_size, &filter->out_audio_format, dest_size_r, @@ -119,6 +122,7 @@ convert_filter_filter(struct filter *_filter, const void *src, size_t src_size, return NULL; return dest; +#endif } const struct filter_plugin convert_filter_plugin = { diff --git a/src/main.c b/src/main.c index aa8d9e3b..aa021d64 100644 --- a/src/main.c +++ b/src/main.c @@ -44,7 +44,6 @@ #include "volume.h" #include "log.h" #include "permission.h" -#include "pcm_resample.h" #include "replay_gain_config.h" #include "decoder_list.h" #include "input_init.h" @@ -435,12 +434,6 @@ int mpd_main(int argc, char *argv[]) archive_plugin_init_all(); #endif - if (!pcm_resample_global_init(&error)) { - g_warning("%s", error->message); - g_error_free(error); - return EXIT_FAILURE; - } - decoder_plugin_init_all(); update_global_init(); diff --git a/src/pcm_channels.c b/src/pcm_channels.c deleted file mode 100644 index ec2bd69a..00000000 --- a/src/pcm_channels.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "pcm_channels.h" -#include "pcm_buffer.h" -#include "pcm_utils.h" - -#include - -static void -pcm_convert_channels_16_1_to_2(int16_t *restrict dest, - const int16_t *restrict src, - const int16_t *restrict src_end) -{ - while (src < src_end) { - int16_t value = *src++; - - *dest++ = value; - *dest++ = value; - } -} - -static void -pcm_convert_channels_16_2_to_1(int16_t *restrict dest, - const int16_t *restrict src, - const int16_t *restrict src_end) -{ - while (src < src_end) { - int32_t a = *src++, b = *src++; - - *dest++ = (a + b) / 2; - } -} - -static void -pcm_convert_channels_16_n_to_2(int16_t *restrict dest, - unsigned src_channels, - const int16_t *restrict src, - const int16_t *restrict src_end) -{ - unsigned c; - - assert(src_channels > 0); - - while (src < src_end) { - int32_t sum = 0; - int16_t value; - - for (c = 0; c < src_channels; ++c) - sum += *src++; - value = sum / (int)src_channels; - - /* XXX this is actually only mono ... */ - *dest++ = value; - *dest++ = value; - } -} - -const int16_t * -pcm_convert_channels_16(struct pcm_buffer *buffer, - unsigned dest_channels, - unsigned src_channels, const int16_t *src, - size_t src_size, size_t *dest_size_r) -{ - assert(src_size % (sizeof(*src) * src_channels) == 0); - - size_t dest_size = src_size / src_channels * dest_channels; - *dest_size_r = dest_size; - - int16_t *dest = pcm_buffer_get(buffer, dest_size); - const int16_t *src_end = pcm_end_pointer(src, src_size); - - if (src_channels == 1 && dest_channels == 2) - pcm_convert_channels_16_1_to_2(dest, src, src_end); - else if (src_channels == 2 && dest_channels == 1) - pcm_convert_channels_16_2_to_1(dest, src, src_end); - else if (dest_channels == 2) - pcm_convert_channels_16_n_to_2(dest, src_channels, src, - src_end); - else - return NULL; - - return dest; -} - -static void -pcm_convert_channels_24_1_to_2(int32_t *restrict dest, - const int32_t *restrict src, - const int32_t *restrict src_end) -{ - while (src < src_end) { - int32_t value = *src++; - - *dest++ = value; - *dest++ = value; - } -} - -static void -pcm_convert_channels_24_2_to_1(int32_t *restrict dest, - const int32_t *restrict src, - const int32_t *restrict src_end) -{ - while (src < src_end) { - int32_t a = *src++, b = *src++; - - *dest++ = (a + b) / 2; - } -} - -static void -pcm_convert_channels_24_n_to_2(int32_t *restrict dest, - unsigned src_channels, - const int32_t *restrict src, - const int32_t *restrict src_end) -{ - unsigned c; - - assert(src_channels > 0); - - while (src < src_end) { - int32_t sum = 0; - int32_t value; - - for (c = 0; c < src_channels; ++c) - sum += *src++; - value = sum / (int)src_channels; - - /* XXX this is actually only mono ... */ - *dest++ = value; - *dest++ = value; - } -} - -const int32_t * -pcm_convert_channels_24(struct pcm_buffer *buffer, - unsigned dest_channels, - unsigned src_channels, const int32_t *src, - size_t src_size, size_t *dest_size_r) -{ - assert(src_size % (sizeof(*src) * src_channels) == 0); - - size_t dest_size = src_size / src_channels * dest_channels; - *dest_size_r = dest_size; - - int32_t *dest = pcm_buffer_get(buffer, dest_size); - const int32_t *src_end = pcm_end_pointer(src, src_size); - - if (src_channels == 1 && dest_channels == 2) - pcm_convert_channels_24_1_to_2(dest, src, src_end); - else if (src_channels == 2 && dest_channels == 1) - pcm_convert_channels_24_2_to_1(dest, src, src_end); - else if (dest_channels == 2) - pcm_convert_channels_24_n_to_2(dest, src_channels, src, - src_end); - else - return NULL; - - return dest; -} - -static void -pcm_convert_channels_32_1_to_2(int32_t *dest, const int32_t *src, - const int32_t *src_end) -{ - pcm_convert_channels_24_1_to_2(dest, src, src_end); -} - -static void -pcm_convert_channels_32_2_to_1(int32_t *restrict dest, - const int32_t *restrict src, - const int32_t *restrict src_end) -{ - while (src < src_end) { - int64_t a = *src++, b = *src++; - - *dest++ = (a + b) / 2; - } -} - -static void -pcm_convert_channels_32_n_to_2(int32_t *dest, - unsigned src_channels, const int32_t *src, - const int32_t *src_end) -{ - unsigned c; - - assert(src_channels > 0); - - while (src < src_end) { - int64_t sum = 0; - int32_t value; - - for (c = 0; c < src_channels; ++c) - sum += *src++; - value = sum / (int64_t)src_channels; - - /* XXX this is actually only mono ... */ - *dest++ = value; - *dest++ = value; - } -} - -const int32_t * -pcm_convert_channels_32(struct pcm_buffer *buffer, - unsigned dest_channels, - unsigned src_channels, const int32_t *src, - size_t src_size, size_t *dest_size_r) -{ - assert(src_size % (sizeof(*src) * src_channels) == 0); - - size_t dest_size = src_size / src_channels * dest_channels; - *dest_size_r = dest_size; - - int32_t *dest = pcm_buffer_get(buffer, dest_size); - const int32_t *src_end = pcm_end_pointer(src, src_size); - - if (src_channels == 1 && dest_channels == 2) - pcm_convert_channels_32_1_to_2(dest, src, src_end); - else if (src_channels == 2 && dest_channels == 1) - pcm_convert_channels_32_2_to_1(dest, src, src_end); - else if (dest_channels == 2) - pcm_convert_channels_32_n_to_2(dest, src_channels, src, - src_end); - else - return NULL; - - return dest; -} diff --git a/src/pcm_channels.h b/src/pcm_channels.h deleted file mode 100644 index 1e4a0991..00000000 --- a/src/pcm_channels.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPD_PCM_CHANNELS_H -#define MPD_PCM_CHANNELS_H - -#include -#include - -struct pcm_buffer; - -/** - * Changes the number of channels in 16 bit PCM data. - * - * @param buffer the destination pcm_buffer object - * @param dest_channels the number of channels requested - * @param src_channels the number of channels in the source buffer - * @param src the source PCM buffer - * @param src_size the number of bytes in #src - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int16_t * -pcm_convert_channels_16(struct pcm_buffer *buffer, - unsigned dest_channels, - unsigned src_channels, const int16_t *src, - size_t src_size, size_t *dest_size_r); - -/** - * Changes the number of channels in 24 bit PCM data (aligned at 32 - * bit boundaries). - * - * @param buffer the destination pcm_buffer object - * @param dest_channels the number of channels requested - * @param src_channels the number of channels in the source buffer - * @param src the source PCM buffer - * @param src_size the number of bytes in #src - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int32_t * -pcm_convert_channels_24(struct pcm_buffer *buffer, - unsigned dest_channels, - unsigned src_channels, const int32_t *src, - size_t src_size, size_t *dest_size_r); - -/** - * Changes the number of channels in 32 bit PCM data. - * - * @param buffer the destination pcm_buffer object - * @param dest_channels the number of channels requested - * @param src_channels the number of channels in the source buffer - * @param src the source PCM buffer - * @param src_size the number of bytes in #src - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int32_t * -pcm_convert_channels_32(struct pcm_buffer *buffer, - unsigned dest_channels, - unsigned src_channels, const int32_t *src, - size_t src_size, size_t *dest_size_r); - -#endif diff --git a/src/pcm_convert.c b/src/pcm_convert.c index 63f9a1b9..34e6c32b 100644 --- a/src/pcm_convert.c +++ b/src/pcm_convert.c @@ -17,19 +17,18 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "config.h" -#include "pcm_convert.h" -#include "pcm_channels.h" -#include "pcm_format.h" -#include "pcm_pack.h" #include "audio_format.h" -#include "glib_compat.h" +#include "pcm_convert.h" -#include #include -#include + #include +#include +#include +#include +#include + #undef G_LOG_DOMAIN #define G_LOG_DOMAIN "pcm" @@ -38,292 +37,31 @@ void pcm_convert_init(struct pcm_convert_state *state) memset(state, 0, sizeof(*state)); pcm_dsd_init(&state->dsd); - pcm_resample_init(&state->resample); - pcm_dither_24_init(&state->dither); - - pcm_buffer_init(&state->format_buffer); - pcm_buffer_init(&state->channels_buffer); } void pcm_convert_deinit(struct pcm_convert_state *state) { pcm_dsd_deinit(&state->dsd); - pcm_resample_deinit(&state->resample); - pcm_buffer_deinit(&state->format_buffer); - pcm_buffer_deinit(&state->channels_buffer); + avresample_free(&state->avr); } void pcm_convert_reset(struct pcm_convert_state *state) { pcm_dsd_reset(&state->dsd); - pcm_resample_reset(&state->resample); -} - -static const void * -pcm_convert_channels(struct pcm_buffer *buffer, enum sample_format format, - uint8_t dest_channels, - uint8_t src_channels, const void *src, - size_t src_size, size_t *dest_size_r, - GError **error_r) -{ - const void *dest = NULL; - - switch (format) { - case SAMPLE_FORMAT_UNDEFINED: - case SAMPLE_FORMAT_S8: - case SAMPLE_FORMAT_FLOAT: - case SAMPLE_FORMAT_DSD: - g_set_error(error_r, pcm_convert_quark(), 0, - "Channel conversion not implemented for format '%s'", - sample_format_to_string(format)); - return NULL; - - case SAMPLE_FORMAT_S16: - dest = pcm_convert_channels_16(buffer, dest_channels, - src_channels, src, - src_size, dest_size_r); - break; - - case SAMPLE_FORMAT_S24_P32: - dest = pcm_convert_channels_24(buffer, dest_channels, - src_channels, src, - src_size, dest_size_r); - break; - - case SAMPLE_FORMAT_S32: - dest = pcm_convert_channels_32(buffer, dest_channels, - src_channels, src, - src_size, dest_size_r); - break; - } - - if (dest == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %u to %u channels " - "is not implemented", - src_channels, dest_channels); - return NULL; - } - - return dest; -} - -static const int16_t * -pcm_convert_16(struct pcm_convert_state *state, - const struct audio_format *src_format, - const void *src_buffer, size_t src_size, - const struct audio_format *dest_format, size_t *dest_size_r, - GError **error_r) -{ - const int16_t *buf; - size_t len; - - assert(dest_format->format == SAMPLE_FORMAT_S16); - - buf = pcm_convert_to_16(&state->format_buffer, &state->dither, - src_format->format, src_buffer, src_size, - &len); - if (buf == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %s to 16 bit is not implemented", - sample_format_to_string(src_format->format)); - return NULL; - } - - if (src_format->channels != dest_format->channels) { - buf = pcm_convert_channels_16(&state->channels_buffer, - dest_format->channels, - src_format->channels, - buf, len, &len); - if (buf == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %u to %u channels " - "is not implemented", - src_format->channels, - dest_format->channels); - return NULL; - } - } - - if (src_format->sample_rate != dest_format->sample_rate) { - buf = pcm_resample_16(&state->resample, - dest_format->channels, - src_format->sample_rate, buf, len, - dest_format->sample_rate, &len, - error_r); - if (buf == NULL) - return NULL; - } - - *dest_size_r = len; - return buf; -} - -static const int32_t * -pcm_convert_24(struct pcm_convert_state *state, - const struct audio_format *src_format, - const void *src_buffer, size_t src_size, - const struct audio_format *dest_format, size_t *dest_size_r, - GError **error_r) -{ - const int32_t *buf; - size_t len; - - assert(dest_format->format == SAMPLE_FORMAT_S24_P32); - - buf = pcm_convert_to_24(&state->format_buffer, src_format->format, - src_buffer, src_size, &len); - if (buf == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %s to 24 bit is not implemented", - sample_format_to_string(src_format->format)); - return NULL; - } - - if (src_format->channels != dest_format->channels) { - buf = pcm_convert_channels_24(&state->channels_buffer, - dest_format->channels, - src_format->channels, - buf, len, &len); - if (buf == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %u to %u channels " - "is not implemented", - src_format->channels, - dest_format->channels); - return NULL; - } - } - - if (src_format->sample_rate != dest_format->sample_rate) { - buf = pcm_resample_24(&state->resample, - dest_format->channels, - src_format->sample_rate, buf, len, - dest_format->sample_rate, &len, - error_r); - if (buf == NULL) - return NULL; - } - - *dest_size_r = len; - return buf; -} - -static const int32_t * -pcm_convert_32(struct pcm_convert_state *state, - const struct audio_format *src_format, - const void *src_buffer, size_t src_size, - const struct audio_format *dest_format, size_t *dest_size_r, - GError **error_r) -{ - const int32_t *buf; - size_t len; - - assert(dest_format->format == SAMPLE_FORMAT_S32); - - buf = pcm_convert_to_32(&state->format_buffer, src_format->format, - src_buffer, src_size, &len); - if (buf == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %s to 32 bit is not implemented", - sample_format_to_string(src_format->format)); - return NULL; - } - - if (src_format->channels != dest_format->channels) { - buf = pcm_convert_channels_32(&state->channels_buffer, - dest_format->channels, - src_format->channels, - buf, len, &len); - if (buf == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %u to %u channels " - "is not implemented", - src_format->channels, - dest_format->channels); - return NULL; - } - } - - if (src_format->sample_rate != dest_format->sample_rate) { - buf = pcm_resample_32(&state->resample, - dest_format->channels, - src_format->sample_rate, buf, len, - dest_format->sample_rate, &len, - error_r); - if (buf == NULL) - return buf; - } - - *dest_size_r = len; - return buf; + avresample_free(&state->avr); } -static const float * -pcm_convert_float(struct pcm_convert_state *state, - const struct audio_format *src_format, - const void *src_buffer, size_t src_size, - const struct audio_format *dest_format, size_t *dest_size_r, - GError **error_r) +AVFrame *pcm_convert(struct pcm_convert_state *state, + const struct audio_format *src_format, + const struct audio_format *dest_format, + const AVFrame *src) { - const float *buffer = src_buffer; - size_t size = src_size; - - assert(dest_format->format == SAMPLE_FORMAT_FLOAT); - - /* convert channels first, hoping the source format is - supported (float is not) */ + AVFrame *dst; + int ret; - if (dest_format->channels != src_format->channels) { - buffer = pcm_convert_channels(&state->channels_buffer, - src_format->format, - dest_format->channels, - src_format->channels, - buffer, size, &size, error_r); - if (buffer == NULL) - return NULL; - } - - /* convert to float now */ - - buffer = pcm_convert_to_float(&state->format_buffer, - src_format->format, - buffer, size, &size); - if (buffer == NULL) { - g_set_error(error_r, pcm_convert_quark(), 0, - "Conversion from %s to float is not implemented", - sample_format_to_string(src_format->format)); - return NULL; - } - - /* resample with float, because this is the best format for - libsamplerate */ - - if (src_format->sample_rate != dest_format->sample_rate) { - buffer = pcm_resample_float(&state->resample, - dest_format->channels, - src_format->sample_rate, - buffer, size, - dest_format->sample_rate, &size, - error_r); - if (buffer == NULL) - return NULL; - } - - *dest_size_r = size; - return buffer; -} - -const void * -pcm_convert(struct pcm_convert_state *state, - const struct audio_format *src_format, - const void *src, size_t src_size, - const struct audio_format *dest_format, - size_t *dest_size_r, - GError **error_r) -{ +#if 0 // FIXME struct audio_format float_format; if (src_format->format == SAMPLE_FORMAT_DSD) { size_t f_size; @@ -344,36 +82,63 @@ pcm_convert(struct pcm_convert_state *state, src = f; src_size = f_size; } - - switch (dest_format->format) { - case SAMPLE_FORMAT_S16: - return pcm_convert_16(state, - src_format, src, src_size, - dest_format, dest_size_r, - error_r); - - case SAMPLE_FORMAT_S24_P32: - return pcm_convert_24(state, - src_format, src, src_size, - dest_format, dest_size_r, - error_r); - - case SAMPLE_FORMAT_S32: - return pcm_convert_32(state, - src_format, src, src_size, - dest_format, dest_size_r, - error_r); - - case SAMPLE_FORMAT_FLOAT: - return pcm_convert_float(state, - src_format, src, src_size, - dest_format, dest_size_r, - error_r); - - default: - g_set_error(error_r, pcm_convert_quark(), 0, - "PCM conversion to %s is not implemented", - sample_format_to_string(dest_format->format)); - return NULL; - } +#endif + + if (!state->avr) { + char in_layout[128], out_layout[128]; + state->avr = avresample_alloc_context(); + if (!state->avr) + return NULL; + + state->dst_channel_layout = av_get_default_channel_layout(dest_format->channels); + state->dst_samplerate = dest_format->sample_rate; + state->dst_format = sample_fmt_native_to_libav(dest_format->format); + + av_opt_set_int(state->avr, "in_channel_layout", src->channel_layout, 0); + av_opt_set_int(state->avr, "out_channel_layout", state->dst_channel_layout, 0); + av_opt_set_int(state->avr, "in_sample_rate", src->sample_rate, 0); + av_opt_set_int(state->avr, "out_sample_rate", state->dst_samplerate, 0); + av_opt_set_int(state->avr, "in_sample_fmt", src->format, 0); + av_opt_set_int(state->avr, "out_sample_fmt", state->dst_format, 0); + + av_get_channel_layout_string(in_layout, sizeof(in_layout), -1, src->channel_layout); + av_get_channel_layout_string(out_layout, sizeof(out_layout), -1, state->dst_channel_layout); + g_debug("Opening resampling context %s:%d:%s -> %s:%d:%s\n", + av_get_sample_fmt_name(src->format), src->sample_rate, in_layout, + av_get_sample_fmt_name(state->dst_format), state->dst_samplerate, out_layout); + + ret = avresample_open(state->avr); + if (ret < 0) { + g_warning("Error initializing format conversion.\n"); + avresample_free(&state->avr); + return NULL; + } + } + + dst = av_frame_alloc(); + if (!dst) + return NULL; + dst->format = state->dst_format; + dst->channel_layout = state->dst_channel_layout; + dst->sample_rate = state->dst_samplerate; + dst->nb_samples = avresample_get_out_samples(state->avr, src->nb_samples); + + ret = av_frame_get_buffer(dst, 32); + if (ret < 0) { + g_warning("Error allocating a buffer for format conversion.\n"); + av_frame_free(&dst); + return NULL; + } + + ret = avresample_convert(state->avr, dst->extended_data, dst->linesize[0], + dst->nb_samples, src->extended_data, src->linesize[0], + src->nb_samples); + if (ret < 0) { + g_warning("Error during format conversion.\n"); + av_frame_free(&dst); + return NULL; + } + dst->nb_samples = ret; + + return dst; } diff --git a/src/pcm_convert.h b/src/pcm_convert.h index be11a6e4..b9b1af17 100644 --- a/src/pcm_convert.h +++ b/src/pcm_convert.h @@ -21,10 +21,13 @@ #define PCM_CONVERT_H #include "pcm_dsd.h" -#include "pcm_resample.h" #include "pcm_dither.h" #include "pcm_buffer.h" +#include +#include +#include + struct audio_format; /** @@ -35,15 +38,10 @@ struct audio_format; struct pcm_convert_state { struct pcm_dsd dsd; - struct pcm_resample_state resample; - - struct pcm_dither dither; - - /** the buffer for converting the sample format */ - struct pcm_buffer format_buffer; - - /** the buffer for converting the channel count */ - struct pcm_buffer channels_buffer; + AVAudioResampleContext *avr; + enum AVSampleFormat dst_format; + int dst_samplerate; + uint64_t dst_channel_layout; }; static inline GQuark @@ -83,12 +81,9 @@ pcm_convert_reset(struct pcm_convert_state *state); * ignore errors * @return the destination buffer, or NULL on error */ -const void * -pcm_convert(struct pcm_convert_state *state, - const struct audio_format *src_format, - const void *src, size_t src_size, - const struct audio_format *dest_format, - size_t *dest_size_r, - GError **error_r); +AVFrame *pcm_convert(struct pcm_convert_state *state, + const struct audio_format *src_format, + const struct audio_format *dest_format, + const AVFrame *src); #endif diff --git a/src/pcm_format.c b/src/pcm_format.c deleted file mode 100644 index d3ea3acb..00000000 --- a/src/pcm_format.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "pcm_format.h" -#include "pcm_dither.h" -#include "pcm_buffer.h" -#include "pcm_pack.h" -#include "pcm_utils.h" - -static void -pcm_convert_8_to_16(int16_t *out, const int8_t *in, const int8_t *in_end) -{ - while (in < in_end) { - *out++ = *in++ << 8; - } -} - -static void -pcm_convert_24_to_16(struct pcm_dither *dither, - int16_t *out, const int32_t *in, const int32_t *in_end) -{ - pcm_dither_24_to_16(dither, out, in, in_end); -} - -static void -pcm_convert_32_to_16(struct pcm_dither *dither, - int16_t *out, const int32_t *in, const int32_t *in_end) -{ - pcm_dither_32_to_16(dither, out, in, in_end); -} - -static void -pcm_convert_float_to_16(int16_t *out, const float *in, const float *in_end) -{ - const unsigned OUT_BITS = 16; - const float factor = 1 << (OUT_BITS - 1); - - while (in < in_end) { - int sample = *in++ * factor; - *out++ = pcm_clamp_16(sample); - } -} - -static int16_t * -pcm_allocate_8_to_16(struct pcm_buffer *buffer, - const int8_t *src, size_t src_size, size_t *dest_size_r) -{ - int16_t *dest; - *dest_size_r = src_size / sizeof(*src) * sizeof(*dest); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_8_to_16(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static int16_t * -pcm_allocate_24p32_to_16(struct pcm_buffer *buffer, struct pcm_dither *dither, - const int32_t *src, size_t src_size, - size_t *dest_size_r) -{ - int16_t *dest; - *dest_size_r = src_size / 2; - assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_24_to_16(dither, dest, src, - pcm_end_pointer(src, src_size)); - return dest; -} - -static int16_t * -pcm_allocate_32_to_16(struct pcm_buffer *buffer, struct pcm_dither *dither, - const int32_t *src, size_t src_size, - size_t *dest_size_r) -{ - int16_t *dest; - *dest_size_r = src_size / 2; - assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_32_to_16(dither, dest, src, - pcm_end_pointer(src, src_size)); - return dest; -} - -static int16_t * -pcm_allocate_float_to_16(struct pcm_buffer *buffer, - const float *src, size_t src_size, - size_t *dest_size_r) -{ - int16_t *dest; - *dest_size_r = src_size / 2; - assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_float_to_16(dest, src, - pcm_end_pointer(src, src_size)); - return dest; -} - -const int16_t * -pcm_convert_to_16(struct pcm_buffer *buffer, struct pcm_dither *dither, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r) -{ - assert(src_size % sample_format_size(src_format) == 0); - - switch (src_format) { - case SAMPLE_FORMAT_UNDEFINED: - case SAMPLE_FORMAT_DSD: - break; - - case SAMPLE_FORMAT_S8: - return pcm_allocate_8_to_16(buffer, - src, src_size, dest_size_r); - - case SAMPLE_FORMAT_S16: - *dest_size_r = src_size; - return src; - - case SAMPLE_FORMAT_S24_P32: - return pcm_allocate_24p32_to_16(buffer, dither, src, src_size, - dest_size_r); - - case SAMPLE_FORMAT_S32: - return pcm_allocate_32_to_16(buffer, dither, src, src_size, - dest_size_r); - - case SAMPLE_FORMAT_FLOAT: - return pcm_allocate_float_to_16(buffer, src, src_size, - dest_size_r); - } - - return NULL; -} - -static void -pcm_convert_8_to_24(int32_t *out, const int8_t *in, const int8_t *in_end) -{ - while (in < in_end) - *out++ = *in++ << 16; -} - -static void -pcm_convert_16_to_24(int32_t *out, const int16_t *in, const int16_t *in_end) -{ - while (in < in_end) - *out++ = *in++ << 8; -} - -static void -pcm_convert_32_to_24(int32_t *restrict out, - const int32_t *restrict in, - const int32_t *restrict in_end) -{ - while (in < in_end) - *out++ = *in++ >> 8; -} - -static void -pcm_convert_float_to_24(int32_t *out, const float *in, const float *in_end) -{ - const unsigned OUT_BITS = 24; - const float factor = 1 << (OUT_BITS - 1); - - while (in < in_end) { - int sample = *in++ * factor; - *out++ = pcm_clamp_24(sample); - } -} - -static int32_t * -pcm_allocate_8_to_24(struct pcm_buffer *buffer, - const int8_t *src, size_t src_size, size_t *dest_size_r) -{ - int32_t *dest; - *dest_size_r = src_size / sizeof(*src) * sizeof(*dest); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_8_to_24(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static int32_t * -pcm_allocate_16_to_24(struct pcm_buffer *buffer, - const int16_t *src, size_t src_size, size_t *dest_size_r) -{ - int32_t *dest; - *dest_size_r = src_size * 2; - assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_16_to_24(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static int32_t * -pcm_allocate_32_to_24(struct pcm_buffer *buffer, - const int32_t *src, size_t src_size, size_t *dest_size_r) -{ - *dest_size_r = src_size; - int32_t *dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_32_to_24(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static int32_t * -pcm_allocate_float_to_24(struct pcm_buffer *buffer, - const float *src, size_t src_size, - size_t *dest_size_r) -{ - *dest_size_r = src_size; - int32_t *dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_float_to_24(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -const int32_t * -pcm_convert_to_24(struct pcm_buffer *buffer, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r) -{ - assert(src_size % sample_format_size(src_format) == 0); - - switch (src_format) { - case SAMPLE_FORMAT_UNDEFINED: - case SAMPLE_FORMAT_DSD: - break; - - case SAMPLE_FORMAT_S8: - return pcm_allocate_8_to_24(buffer, - src, src_size, dest_size_r); - - case SAMPLE_FORMAT_S16: - return pcm_allocate_16_to_24(buffer, - src, src_size, dest_size_r); - - case SAMPLE_FORMAT_S24_P32: - *dest_size_r = src_size; - return src; - - case SAMPLE_FORMAT_S32: - return pcm_allocate_32_to_24(buffer, src, src_size, - dest_size_r); - - case SAMPLE_FORMAT_FLOAT: - return pcm_allocate_float_to_24(buffer, src, src_size, - dest_size_r); - } - - return NULL; -} - -static void -pcm_convert_8_to_32(int32_t *out, const int8_t *in, const int8_t *in_end) -{ - while (in < in_end) - *out++ = *in++ << 24; -} - -static void -pcm_convert_16_to_32(int32_t *out, const int16_t *in, const int16_t *in_end) -{ - while (in < in_end) - *out++ = *in++ << 16; -} - -static void -pcm_convert_24_to_32(int32_t *restrict out, - const int32_t *restrict in, - const int32_t *restrict in_end) -{ - while (in < in_end) - *out++ = *in++ << 8; -} - -static int32_t * -pcm_allocate_8_to_32(struct pcm_buffer *buffer, - const int8_t *src, size_t src_size, size_t *dest_size_r) -{ - int32_t *dest; - *dest_size_r = src_size / sizeof(*src) * sizeof(*dest); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_8_to_32(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static int32_t * -pcm_allocate_16_to_32(struct pcm_buffer *buffer, - const int16_t *src, size_t src_size, size_t *dest_size_r) -{ - int32_t *dest; - *dest_size_r = src_size * 2; - assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_16_to_32(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static int32_t * -pcm_allocate_24p32_to_32(struct pcm_buffer *buffer, - const int32_t *src, size_t src_size, - size_t *dest_size_r) -{ - *dest_size_r = src_size; - int32_t *dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_24_to_32(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static int32_t * -pcm_allocate_float_to_32(struct pcm_buffer *buffer, - const float *src, size_t src_size, - size_t *dest_size_r) -{ - /* convert to S24_P32 first */ - int32_t *dest = pcm_allocate_float_to_24(buffer, src, src_size, - dest_size_r); - - /* convert to 32 bit in-place */ - pcm_convert_24_to_32(dest, dest, pcm_end_pointer(dest, *dest_size_r)); - return dest; -} - -const int32_t * -pcm_convert_to_32(struct pcm_buffer *buffer, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r) -{ - assert(src_size % sample_format_size(src_format) == 0); - - switch (src_format) { - case SAMPLE_FORMAT_UNDEFINED: - case SAMPLE_FORMAT_DSD: - break; - - case SAMPLE_FORMAT_S8: - return pcm_allocate_8_to_32(buffer, src, src_size, - dest_size_r); - - case SAMPLE_FORMAT_S16: - return pcm_allocate_16_to_32(buffer, src, src_size, - dest_size_r); - - case SAMPLE_FORMAT_S24_P32: - return pcm_allocate_24p32_to_32(buffer, src, src_size, - dest_size_r); - - case SAMPLE_FORMAT_S32: - *dest_size_r = src_size; - return src; - - case SAMPLE_FORMAT_FLOAT: - return pcm_allocate_float_to_32(buffer, src, src_size, - dest_size_r); - } - - return NULL; -} - -static void -pcm_convert_8_to_float(float *out, const int8_t *in, const int8_t *in_end) -{ - enum { in_bits = sizeof(*in) * 8 }; - static const float factor = 2.0f / (1 << in_bits); - while (in < in_end) - *out++ = (float)*in++ * factor; -} - -static void -pcm_convert_16_to_float(float *out, const int16_t *in, const int16_t *in_end) -{ - enum { in_bits = sizeof(*in) * 8 }; - static const float factor = 2.0f / (1 << in_bits); - while (in < in_end) - *out++ = (float)*in++ * factor; -} - -static void -pcm_convert_24_to_float(float *out, const int32_t *in, const int32_t *in_end) -{ - enum { in_bits = 24 }; - static const float factor = 2.0f / (1 << in_bits); - while (in < in_end) - *out++ = (float)*in++ * factor; -} - -static void -pcm_convert_32_to_float(float *out, const int32_t *in, const int32_t *in_end) -{ - enum { in_bits = sizeof(*in) * 8 }; - static const float factor = 0.5f / (1 << (in_bits - 2)); - while (in < in_end) - *out++ = (float)*in++ * factor; -} - -static float * -pcm_allocate_8_to_float(struct pcm_buffer *buffer, - const int8_t *src, size_t src_size, - size_t *dest_size_r) -{ - float *dest; - *dest_size_r = src_size / sizeof(*src) * sizeof(*dest); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_8_to_float(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static float * -pcm_allocate_16_to_float(struct pcm_buffer *buffer, - const int16_t *src, size_t src_size, - size_t *dest_size_r) -{ - float *dest; - *dest_size_r = src_size * 2; - assert(*dest_size_r == src_size / sizeof(*src) * sizeof(*dest)); - dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_16_to_float(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static float * -pcm_allocate_24p32_to_float(struct pcm_buffer *buffer, - const int32_t *src, size_t src_size, - size_t *dest_size_r) -{ - *dest_size_r = src_size; - float *dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_24_to_float(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -static float * -pcm_allocate_32_to_float(struct pcm_buffer *buffer, - const int32_t *src, size_t src_size, - size_t *dest_size_r) -{ - *dest_size_r = src_size; - float *dest = pcm_buffer_get(buffer, *dest_size_r); - pcm_convert_32_to_float(dest, src, pcm_end_pointer(src, src_size)); - return dest; -} - -const float * -pcm_convert_to_float(struct pcm_buffer *buffer, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r) -{ - switch (src_format) { - case SAMPLE_FORMAT_UNDEFINED: - case SAMPLE_FORMAT_DSD: - break; - - case SAMPLE_FORMAT_S8: - return pcm_allocate_8_to_float(buffer, - src, src_size, dest_size_r); - - case SAMPLE_FORMAT_S16: - return pcm_allocate_16_to_float(buffer, - src, src_size, dest_size_r); - - case SAMPLE_FORMAT_S24_P32: - return pcm_allocate_24p32_to_float(buffer, - src, src_size, dest_size_r); - - case SAMPLE_FORMAT_S32: - return pcm_allocate_32_to_float(buffer, - src, src_size, dest_size_r); - - case SAMPLE_FORMAT_FLOAT: - *dest_size_r = src_size; - return src; - } - - return NULL; -} diff --git a/src/pcm_format.h b/src/pcm_format.h deleted file mode 100644 index 48bcd066..00000000 --- a/src/pcm_format.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef PCM_FORMAT_H -#define PCM_FORMAT_H - -#include "audio_format.h" - -#include -#include - -struct pcm_buffer; -struct pcm_dither; - -/** - * Converts PCM samples to 16 bit. If the source format is 24 bit, - * then dithering is applied. - * - * @param buffer a pcm_buffer object - * @param dither a pcm_dither object for 24-to-16 conversion - * @param bits the number of in the source buffer - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int16_t * -pcm_convert_to_16(struct pcm_buffer *buffer, struct pcm_dither *dither, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r); - -/** - * Converts PCM samples to 24 bit (32 bit alignment). - * - * @param buffer a pcm_buffer object - * @param bits the number of in the source buffer - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int32_t * -pcm_convert_to_24(struct pcm_buffer *buffer, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r); - -/** - * Converts PCM samples to 32 bit. - * - * @param buffer a pcm_buffer object - * @param bits the number of in the source buffer - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int32_t * -pcm_convert_to_32(struct pcm_buffer *buffer, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r); - -/** - * Converts PCM samples to 32 bit floating point. - * - * @param buffer a pcm_buffer object - * @param bits the number of in the source buffer - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const float * -pcm_convert_to_float(struct pcm_buffer *buffer, - enum sample_format src_format, const void *src, - size_t src_size, size_t *dest_size_r); - -#endif diff --git a/src/pcm_resample.c b/src/pcm_resample.c deleted file mode 100644 index bb75db6c..00000000 --- a/src/pcm_resample.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "pcm_resample_internal.h" - -#if CONFIG_LIBSAMPLERATE -#include "conf.h" -#endif - -#include - -#if CONFIG_LIBSAMPLERATE -static bool lsr_enabled; -#endif - -#if CONFIG_LIBSAMPLERATE -static bool -pcm_resample_lsr_enabled(void) -{ - return lsr_enabled; -} -#endif - -bool -pcm_resample_global_init(GError **error_r) -{ -#if CONFIG_LIBSAMPLERATE - const char *converter = - config_get_string(CONF_SAMPLERATE_CONVERTER, ""); - - lsr_enabled = strcmp(converter, "internal") != 0; - if (lsr_enabled) - return pcm_resample_lsr_global_init(converter, error_r); - else - return true; -#else - (void)error_r; - return true; -#endif -} - -void pcm_resample_init(struct pcm_resample_state *state) -{ -#if CONFIG_LIBSAMPLERATE - if (pcm_resample_lsr_enabled()) - pcm_resample_lsr_init(state); - else -#endif - pcm_resample_fallback_init(state); -} - -void pcm_resample_deinit(struct pcm_resample_state *state) -{ -#if CONFIG_LIBSAMPLERATE - if (pcm_resample_lsr_enabled()) - pcm_resample_lsr_deinit(state); - else -#endif - pcm_resample_fallback_deinit(state); -} - -void -pcm_resample_reset(struct pcm_resample_state *state) -{ -#if CONFIG_LIBSAMPLERATE - pcm_resample_lsr_reset(state); -#else - (void)state; -#endif -} - -const float * -pcm_resample_float(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const float *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r) -{ -#if CONFIG_LIBSAMPLERATE - if (pcm_resample_lsr_enabled()) - return pcm_resample_lsr_float(state, channels, - src_rate, src_buffer, src_size, - dest_rate, dest_size_r, - error_r); -#else - (void)error_r; -#endif - - /* sizeof(float)==sizeof(int32_t); the fallback resampler does - not do any math on the sample values, so this hack is - possible: */ - return (const float *) - pcm_resample_fallback_32(state, channels, - src_rate, (const int32_t *)src_buffer, - src_size, - dest_rate, dest_size_r); -} - -const int16_t * -pcm_resample_16(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, const int16_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r) -{ -#if CONFIG_LIBSAMPLERATE - if (pcm_resample_lsr_enabled()) - return pcm_resample_lsr_16(state, channels, - src_rate, src_buffer, src_size, - dest_rate, dest_size_r, - error_r); -#else - (void)error_r; -#endif - - return pcm_resample_fallback_16(state, channels, - src_rate, src_buffer, src_size, - dest_rate, dest_size_r); -} - -const int32_t * -pcm_resample_32(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, const int32_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r) -{ -#if CONFIG_LIBSAMPLERATE - if (pcm_resample_lsr_enabled()) - return pcm_resample_lsr_32(state, channels, - src_rate, src_buffer, src_size, - dest_rate, dest_size_r, - error_r); -#else - (void)error_r; -#endif - - return pcm_resample_fallback_32(state, channels, - src_rate, src_buffer, src_size, - dest_rate, dest_size_r); -} diff --git a/src/pcm_resample.h b/src/pcm_resample.h deleted file mode 100644 index 8e73659d..00000000 --- a/src/pcm_resample.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPD_PCM_RESAMPLE_H -#define MPD_PCM_RESAMPLE_H - -#include "check.h" -#include "pcm_buffer.h" - -#include -#include -#include - -#if CONFIG_LIBSAMPLERATE -#include -#endif - -/** - * This object is statically allocated (within another struct), and - * holds buffer allocations and the state for the resampler. - */ -struct pcm_resample_state { -#if CONFIG_LIBSAMPLERATE - SRC_STATE *state; - SRC_DATA data; - - struct pcm_buffer in, out; - - struct { - unsigned src_rate; - unsigned dest_rate; - unsigned channels; - } prev; - - int error; -#endif - - struct pcm_buffer buffer; -}; - -bool -pcm_resample_global_init(GError **error_r); - -/** - * Initializes a pcm_resample_state object. - */ -void pcm_resample_init(struct pcm_resample_state *state); - -/** - * Deinitializes a pcm_resample_state object and frees allocated - * memory. - */ -void pcm_resample_deinit(struct pcm_resample_state *state); - -/** - * @see pcm_convert_reset() - */ -void -pcm_resample_reset(struct pcm_resample_state *state); - -/** - * Resamples 32 bit float data. - * - * @param state an initialized pcm_resample_state object - * @param channels the number of channels - * @param src_rate the source sample rate - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_rate the requested destination sample rate - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const float * -pcm_resample_float(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const float *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r); - -/** - * Resamples 16 bit PCM data. - * - * @param state an initialized pcm_resample_state object - * @param channels the number of channels - * @param src_rate the source sample rate - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_rate the requested destination sample rate - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int16_t * -pcm_resample_16(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int16_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r); - -/** - * Resamples 32 bit PCM data. - * - * @param state an initialized pcm_resample_state object - * @param channels the number of channels - * @param src_rate the source sample rate - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_rate the requested destination sample rate - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -const int32_t * -pcm_resample_32(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int32_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r); - -/** - * Resamples 24 bit PCM data. - * - * @param state an initialized pcm_resample_state object - * @param channels the number of channels - * @param src_rate the source sample rate - * @param src the source PCM buffer - * @param src_size the size of #src in bytes - * @param dest_rate the requested destination sample rate - * @param dest_size_r returns the number of bytes of the destination buffer - * @return the destination buffer - */ -static inline const int32_t * -pcm_resample_24(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int32_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r) -{ - /* reuse the 32 bit code - the resampler code doesn't care if - the upper 8 bits are actually used */ - return pcm_resample_32(state, channels, - src_rate, src_buffer, src_size, - dest_rate, dest_size_r, error_r); -} - -#endif diff --git a/src/pcm_resample_fallback.c b/src/pcm_resample_fallback.c deleted file mode 100644 index 1d1dfdf5..00000000 --- a/src/pcm_resample_fallback.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "pcm_resample_internal.h" - -#include - -void -pcm_resample_fallback_init(struct pcm_resample_state *state) -{ - pcm_buffer_init(&state->buffer); -} - -void -pcm_resample_fallback_deinit(struct pcm_resample_state *state) -{ - pcm_buffer_deinit(&state->buffer); -} - -/* resampling code blatantly ripped from ESD */ -const int16_t * -pcm_resample_fallback_16(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int16_t *src_buffer, size_t src_size, - unsigned dest_rate, - size_t *dest_size_r) -{ - unsigned src_pos, dest_pos = 0; - unsigned src_frames = src_size / channels / sizeof(*src_buffer); - unsigned dest_frames = - (src_frames * dest_rate + src_rate - 1) / src_rate; - unsigned dest_samples = dest_frames * channels; - size_t dest_size = dest_samples * sizeof(*src_buffer); - int16_t *dest_buffer = pcm_buffer_get(&state->buffer, dest_size); - - assert((src_size % (sizeof(*src_buffer) * channels)) == 0); - - 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; - } - - *dest_size_r = dest_size; - return dest_buffer; -} - -const int32_t * -pcm_resample_fallback_32(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int32_t *src_buffer, size_t src_size, - unsigned dest_rate, - size_t *dest_size_r) -{ - unsigned src_pos, dest_pos = 0; - unsigned src_frames = src_size / channels / sizeof(*src_buffer); - unsigned dest_frames = - (src_frames * dest_rate + src_rate - 1) / src_rate; - unsigned dest_samples = dest_frames * channels; - size_t dest_size = dest_samples * sizeof(*src_buffer); - int32_t *dest_buffer = pcm_buffer_get(&state->buffer, dest_size); - - assert((src_size % (sizeof(*src_buffer) * channels)) == 0); - - 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; - } - - *dest_size_r = dest_size; - return dest_buffer; -} diff --git a/src/pcm_resample_internal.h b/src/pcm_resample_internal.h deleted file mode 100644 index 528ea2d6..00000000 --- a/src/pcm_resample_internal.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/** \file - * - * Internal declarations for the pcm_resample library. The "internal" - * resampler is called "fallback" in the MPD source, so the file name - * of this header is somewhat unrelated to it. - */ - -#ifndef MPD_PCM_RESAMPLE_INTERNAL_H -#define MPD_PCM_RESAMPLE_INTERNAL_H - -#include "check.h" -#include "pcm_resample.h" - -#if CONFIG_LIBSAMPLERATE - -bool -pcm_resample_lsr_global_init(const char *converter, GError **error_r); - -void -pcm_resample_lsr_init(struct pcm_resample_state *state); - -void -pcm_resample_lsr_deinit(struct pcm_resample_state *state); - -void -pcm_resample_lsr_reset(struct pcm_resample_state *state); - -const float * -pcm_resample_lsr_float(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const float *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r); - -const int16_t * -pcm_resample_lsr_16(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int16_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r); - -const int32_t * -pcm_resample_lsr_32(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int32_t *src_buffer, - G_GNUC_UNUSED size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r); - -#endif - -void -pcm_resample_fallback_init(struct pcm_resample_state *state); - -void -pcm_resample_fallback_deinit(struct pcm_resample_state *state); - -const int16_t * -pcm_resample_fallback_16(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int16_t *src_buffer, size_t src_size, - unsigned dest_rate, - size_t *dest_size_r); - -const int32_t * -pcm_resample_fallback_32(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int32_t *src_buffer, - G_GNUC_UNUSED size_t src_size, - unsigned dest_rate, - size_t *dest_size_r); - -#endif diff --git a/src/pcm_resample_libsamplerate.c b/src/pcm_resample_libsamplerate.c deleted file mode 100644 index f957e515..00000000 --- a/src/pcm_resample_libsamplerate.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (C) 2003-2011 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "pcm_resample_internal.h" -#include "conf.h" - -#include - -#include -#include -#include - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "pcm" - -static int lsr_converter = SRC_SINC_FASTEST; - -static inline GQuark -libsamplerate_quark(void) -{ - return g_quark_from_static_string("libsamplerate"); -} - -static bool -lsr_parse_converter(const char *s) -{ - assert(s != NULL); - - if (*s == 0) - return true; - - char *endptr; - long l = strtol(s, &endptr, 10); - if (*endptr == 0 && src_get_name(l) != NULL) { - lsr_converter = l; - return true; - } - - size_t length = strlen(s); - for (int i = 0;; ++i) { - const char *name = src_get_name(i); - if (name == NULL) - break; - - if (g_ascii_strncasecmp(s, name, length) == 0) { - lsr_converter = i; - return true; - } - } - - return false; -} - -bool -pcm_resample_lsr_global_init(const char *converter, GError **error_r) -{ - if (!lsr_parse_converter(converter)) { - g_set_error(error_r, libsamplerate_quark(), 0, - "unknown samplerate converter '%s'", converter); - return false; - } - - g_debug("libsamplerate converter '%s'", - src_get_name(lsr_converter)); - - return true; -} - -void -pcm_resample_lsr_init(struct pcm_resample_state *state) -{ - memset(state, 0, sizeof(*state)); - - pcm_buffer_init(&state->in); - pcm_buffer_init(&state->out); - pcm_buffer_init(&state->buffer); -} - -void -pcm_resample_lsr_deinit(struct pcm_resample_state *state) -{ - if (state->state != NULL) - state->state = src_delete(state->state); - - pcm_buffer_deinit(&state->in); - pcm_buffer_deinit(&state->out); - pcm_buffer_deinit(&state->buffer); -} - -void -pcm_resample_lsr_reset(struct pcm_resample_state *state) -{ - if (state->state != NULL) - src_reset(state->state); -} - -static bool -pcm_resample_set(struct pcm_resample_state *state, - unsigned channels, unsigned src_rate, unsigned dest_rate, - GError **error_r) -{ - int error; - SRC_DATA *data = &state->data; - - /* (re)set the state/ratio if the in or out format changed */ - if (channels == state->prev.channels && - src_rate == state->prev.src_rate && - dest_rate == state->prev.dest_rate) - return true; - - state->error = 0; - state->prev.channels = channels; - state->prev.src_rate = src_rate; - state->prev.dest_rate = dest_rate; - - if (state->state) - state->state = src_delete(state->state); - - state->state = src_new(lsr_converter, channels, &error); - if (!state->state) { - g_set_error(error_r, libsamplerate_quark(), state->error, - "libsamplerate initialization has failed: %s", - src_strerror(error)); - return false; - } - - data->src_ratio = (double)dest_rate / (double)src_rate; - g_debug("setting samplerate conversion ratio to %.2lf", - data->src_ratio); - src_set_ratio(state->state, data->src_ratio); - - return true; -} - -static bool -lsr_process(struct pcm_resample_state *state, GError **error_r) -{ - if (state->error == 0) - state->error = src_process(state->state, &state->data); - if (state->error) { - g_set_error(error_r, libsamplerate_quark(), state->error, - "libsamplerate has failed: %s", - src_strerror(state->error)); - return false; - } - - return true; -} - -static float * -deconst_float_buffer(const float *in) -{ - union { - const float *in; - float *out; - } u = { .in = in }; - return u.out; -} - -const float * -pcm_resample_lsr_float(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const float *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r) -{ - assert((src_size % (sizeof(*src_buffer) * channels)) == 0); - - if (!pcm_resample_set(state, channels, src_rate, dest_rate, error_r)) - return NULL; - - SRC_DATA *data = &state->data; - data->input_frames = src_size / sizeof(*src_buffer) / channels; - data->data_in = deconst_float_buffer(src_buffer); - - data->output_frames = (src_size * dest_rate + src_rate - 1) / src_rate; - size_t data_out_size = data->output_frames * sizeof(float) * channels; - data->data_out = pcm_buffer_get(&state->out, data_out_size); - - if (!lsr_process(state, error_r)) - return NULL; - - *dest_size_r = data->output_frames_gen * - sizeof(*data->data_out) * channels; - return data->data_out; -} - -const int16_t * -pcm_resample_lsr_16(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int16_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r) -{ - bool success; - SRC_DATA *data = &state->data; - size_t data_in_size; - size_t data_out_size; - int16_t *dest_buffer; - - assert((src_size % (sizeof(*src_buffer) * channels)) == 0); - - success = pcm_resample_set(state, channels, src_rate, dest_rate, - error_r); - if (!success) - return NULL; - - data->input_frames = src_size / sizeof(*src_buffer) / channels; - data_in_size = data->input_frames * sizeof(float) * channels; - data->data_in = pcm_buffer_get(&state->in, data_in_size); - - data->output_frames = (src_size * dest_rate + src_rate - 1) / src_rate; - data_out_size = data->output_frames * sizeof(float) * channels; - data->data_out = pcm_buffer_get(&state->out, data_out_size); - - src_short_to_float_array(src_buffer, data->data_in, - data->input_frames * channels); - - if (!lsr_process(state, error_r)) - return NULL; - - *dest_size_r = data->output_frames_gen * - sizeof(*dest_buffer) * channels; - dest_buffer = pcm_buffer_get(&state->buffer, *dest_size_r); - src_float_to_short_array(data->data_out, dest_buffer, - data->output_frames_gen * channels); - - return dest_buffer; -} - -#ifdef HAVE_LIBSAMPLERATE_NOINT - -/* libsamplerate introduced these functions in v0.1.3 */ - -static void -src_int_to_float_array(const int *in, float *out, int len) -{ - while (len-- > 0) - *out++ = *in++ / (float)(1 << (24 - 1)); -} - -static void -src_float_to_int_array (const float *in, int *out, int len) -{ - while (len-- > 0) - *out++ = *in++ * (float)(1 << (24 - 1)); -} - -#endif - -const int32_t * -pcm_resample_lsr_32(struct pcm_resample_state *state, - unsigned channels, - unsigned src_rate, - const int32_t *src_buffer, size_t src_size, - unsigned dest_rate, size_t *dest_size_r, - GError **error_r) -{ - bool success; - SRC_DATA *data = &state->data; - size_t data_in_size; - size_t data_out_size; - int32_t *dest_buffer; - - assert((src_size % (sizeof(*src_buffer) * channels)) == 0); - - success = pcm_resample_set(state, channels, src_rate, dest_rate, - error_r); - if (!success) - return NULL; - - data->input_frames = src_size / sizeof(*src_buffer) / channels; - data_in_size = data->input_frames * sizeof(float) * channels; - data->data_in = pcm_buffer_get(&state->in, data_in_size); - - data->output_frames = (src_size * dest_rate + src_rate - 1) / src_rate; - data_out_size = data->output_frames * sizeof(float) * channels; - data->data_out = pcm_buffer_get(&state->out, data_out_size); - - src_int_to_float_array(src_buffer, data->data_in, - data->input_frames * channels); - - if (!lsr_process(state, error_r)) - return NULL; - - *dest_size_r = data->output_frames_gen * - sizeof(*dest_buffer) * channels; - dest_buffer = pcm_buffer_get(&state->buffer, *dest_size_r); - src_float_to_int_array(data->data_out, dest_buffer, - data->output_frames_gen * channels); - - return dest_buffer; -} -- cgit v1.2.3