diff options
Diffstat (limited to 'src/pcm/PcmConvert.cxx')
-rw-r--r-- | src/pcm/PcmConvert.cxx | 336 |
1 files changed, 94 insertions, 242 deletions
diff --git a/src/pcm/PcmConvert.cxx b/src/pcm/PcmConvert.cxx index 8eafe527c..438566759 100644 --- a/src/pcm/PcmConvert.cxx +++ b/src/pcm/PcmConvert.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,289 +19,141 @@ #include "config.h" #include "PcmConvert.hxx" -#include "PcmChannels.hxx" -#include "PcmFormat.hxx" +#include "Domain.hxx" +#include "ConfiguredResampler.hxx" #include "AudioFormat.hxx" +#include "util/ConstBuffer.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" +#include "util/ConstBuffer.hxx" #include <assert.h> #include <math.h> -const Domain pcm_convert_domain("pcm_convert"); - -PcmConvert::PcmConvert() +bool +pcm_convert_global_init(Error &error) { + return pcm_resampler_global_init(error); } -PcmConvert::~PcmConvert() +PcmConvert::PcmConvert() { +#ifndef NDEBUG + src_format.Clear(); + dest_format.Clear(); +#endif } -void -PcmConvert::Reset() +PcmConvert::~PcmConvert() { - dsd.Reset(); - resampler.Reset(); + assert(!src_format.IsValid()); + assert(!dest_format.IsValid()); } -inline const int16_t * -PcmConvert::Convert16(const AudioFormat src_format, - const void *src_buffer, size_t src_size, - const AudioFormat dest_format, size_t *dest_size_r, - Error &error) +bool +PcmConvert::Open(const AudioFormat _src_format, const AudioFormat _dest_format, + Error &error) { - const int16_t *buf; - size_t len; - - assert(dest_format.format == SampleFormat::S16); - - buf = pcm_convert_to_16(format_buffer, dither, - src_format.format, - src_buffer, src_size, - &len); - if (buf == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %s to 16 bit is not implemented", - sample_format_to_string(src_format.format)); - return nullptr; + assert(!src_format.IsValid()); + assert(!dest_format.IsValid()); + assert(_src_format.IsValid()); + assert(_dest_format.IsValid()); + + AudioFormat format = _src_format; + if (format.format == SampleFormat::DSD) + format.format = SampleFormat::FLOAT; + + enable_resampler = format.sample_rate != _dest_format.sample_rate; + if (enable_resampler) { + if (!resampler.Open(format, _dest_format.sample_rate, error)) + return false; + + format.format = resampler.GetOutputSampleFormat(); + format.sample_rate = _dest_format.sample_rate; } - if (src_format.channels != dest_format.channels) { - buf = pcm_convert_channels_16(channels_buffer, - dest_format.channels, - src_format.channels, - buf, len, &len); - if (buf == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %u to %u channels " - "is not implemented", - src_format.channels, - dest_format.channels); - return nullptr; - } + enable_format = format.format != _dest_format.format; + if (enable_format && + !format_converter.Open(format.format, _dest_format.format, + error)) { + if (enable_resampler) + resampler.Close(); + return false; } - if (src_format.sample_rate != dest_format.sample_rate) { - buf = resampler.Resample16(dest_format.channels, - src_format.sample_rate, buf, len, - dest_format.sample_rate, &len, - error); - if (buf == nullptr) - return nullptr; + format.format = _dest_format.format; + + enable_channels = format.channels != _dest_format.channels; + if (enable_channels && + !channels_converter.Open(format.format, format.channels, + _dest_format.channels, error)) { + if (enable_format) + format_converter.Close(); + if (enable_resampler) + resampler.Close(); + return false; } - *dest_size_r = len; - return buf; + src_format = _src_format; + dest_format = _dest_format; + + return true; } -inline const int32_t * -PcmConvert::Convert24(const AudioFormat src_format, - const void *src_buffer, size_t src_size, - const AudioFormat dest_format, size_t *dest_size_r, - Error &error) +void +PcmConvert::Close() { - const int32_t *buf; - size_t len; - - assert(dest_format.format == SampleFormat::S24_P32); - - buf = pcm_convert_to_24(format_buffer, - src_format.format, - src_buffer, src_size, &len); - if (buf == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %s to 24 bit is not implemented", - sample_format_to_string(src_format.format)); - return nullptr; - } - - if (src_format.channels != dest_format.channels) { - buf = pcm_convert_channels_24(channels_buffer, - dest_format.channels, - src_format.channels, - buf, len, &len); - if (buf == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %u to %u channels " - "is not implemented", - src_format.channels, - dest_format.channels); - return nullptr; - } - } - - if (src_format.sample_rate != dest_format.sample_rate) { - buf = resampler.Resample24(dest_format.channels, - src_format.sample_rate, buf, len, - dest_format.sample_rate, &len, - error); - if (buf == nullptr) - return nullptr; - } + if (enable_channels) + channels_converter.Close(); + if (enable_format) + format_converter.Close(); + if (enable_resampler) + resampler.Close(); + +#ifdef ENABLE_DSD + dsd.Reset(); +#endif - *dest_size_r = len; - return buf; +#ifndef NDEBUG + src_format.Clear(); + dest_format.Clear(); +#endif } -inline const int32_t * -PcmConvert::Convert32(const AudioFormat src_format, - const void *src_buffer, size_t src_size, - const AudioFormat dest_format, size_t *dest_size_r, - Error &error) +ConstBuffer<void> +PcmConvert::Convert(ConstBuffer<void> buffer, Error &error) { - const int32_t *buf; - size_t len; - - assert(dest_format.format == SampleFormat::S32); - - buf = pcm_convert_to_32(format_buffer, - src_format.format, - src_buffer, src_size, &len); - if (buf == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %s to 32 bit is not implemented", - sample_format_to_string(src_format.format)); - return nullptr; - } - - if (src_format.channels != dest_format.channels) { - buf = pcm_convert_channels_32(channels_buffer, - dest_format.channels, - src_format.channels, - buf, len, &len); - if (buf == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %u to %u channels " - "is not implemented", - src_format.channels, - dest_format.channels); +#ifdef ENABLE_DSD + if (src_format.format == SampleFormat::DSD) { + auto s = ConstBuffer<uint8_t>::FromVoid(buffer); + auto d = dsd.ToFloat(src_format.channels, s); + if (d.IsNull()) { + error.Set(pcm_domain, + "DSD to PCM conversion failed"); return nullptr; } - } - if (src_format.sample_rate != dest_format.sample_rate) { - buf = resampler.Resample32(dest_format.channels, - src_format.sample_rate, buf, len, - dest_format.sample_rate, &len, - error); - if (buf == nullptr) - return buf; + buffer = d.ToVoid(); } +#endif - *dest_size_r = len; - return buf; -} - -inline const float * -PcmConvert::ConvertFloat(const AudioFormat src_format, - const void *src_buffer, size_t src_size, - const AudioFormat dest_format, size_t *dest_size_r, - Error &error) -{ - const float *buffer = (const float *)src_buffer; - size_t size = src_size; - - assert(dest_format.format == SampleFormat::FLOAT); - - /* convert to float now */ - - buffer = pcm_convert_to_float(format_buffer, - src_format.format, - buffer, size, &size); - if (buffer == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %s to float is not implemented", - sample_format_to_string(src_format.format)); - return nullptr; - } - - /* convert channels */ - - if (src_format.channels != dest_format.channels) { - buffer = pcm_convert_channels_float(channels_buffer, - dest_format.channels, - src_format.channels, - buffer, size, &size); - if (buffer == nullptr) { - error.Format(pcm_convert_domain, - "Conversion from %u to %u channels " - "is not implemented", - src_format.channels, - dest_format.channels); + if (enable_resampler) { + buffer = resampler.Resample(buffer, error); + if (buffer.IsNull()) return nullptr; - } } - /* resample with float, because this is the best format for - libsamplerate */ - - if (src_format.sample_rate != dest_format.sample_rate) { - buffer = resampler.ResampleFloat(dest_format.channels, - src_format.sample_rate, - buffer, size, - dest_format.sample_rate, - &size, error); - if (buffer == nullptr) + if (enable_format) { + buffer = format_converter.Convert(buffer, error); + if (buffer.IsNull()) return nullptr; } - *dest_size_r = size; - return buffer; -} - -const void * -PcmConvert::Convert(AudioFormat src_format, - const void *src, size_t src_size, - const AudioFormat dest_format, - size_t *dest_size_r, - Error &error) -{ - AudioFormat float_format; - if (src_format.format == SampleFormat::DSD) { - size_t f_size; - const float *f = dsd.ToFloat(src_format.channels, - false, (const uint8_t *)src, - src_size, &f_size); - if (f == nullptr) { - error.Set(pcm_convert_domain, - "DSD to PCM conversion failed"); + if (enable_channels) { + buffer = channels_converter.Convert(buffer, error); + if (buffer.IsNull()) return nullptr; - } - - float_format = src_format; - float_format.format = SampleFormat::FLOAT; - - src_format = float_format; - src = f; - src_size = f_size; } - switch (dest_format.format) { - case SampleFormat::S16: - return Convert16(src_format, src, src_size, - dest_format, dest_size_r, - error); - - case SampleFormat::S24_P32: - return Convert24(src_format, src, src_size, - dest_format, dest_size_r, - error); - - case SampleFormat::S32: - return Convert32(src_format, src, src_size, - dest_format, dest_size_r, - error); - - case SampleFormat::FLOAT: - return ConvertFloat(src_format, src, src_size, - dest_format, dest_size_r, - error); - - default: - error.Format(pcm_convert_domain, - "PCM conversion to %s is not implemented", - sample_format_to_string(dest_format.format)); - return nullptr; - } + return buffer; } |