diff options
Diffstat (limited to 'src/pcm/PcmConvert.cxx')
-rw-r--r-- | src/pcm/PcmConvert.cxx | 334 |
1 files changed, 98 insertions, 236 deletions
diff --git a/src/pcm/PcmConvert.cxx b/src/pcm/PcmConvert.cxx index 8eafe527c..ad79e60fc 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,151 @@ #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"); +bool +pcm_convert_global_init(Error &error) +{ + return pcm_resampler_global_init(error); +} PcmConvert::PcmConvert() { +#ifndef NDEBUG + src_format.Clear(); + dest_format.Clear(); +#endif } PcmConvert::~PcmConvert() { + assert(!src_format.IsValid()); + assert(!dest_format.IsValid()); } -void -PcmConvert::Reset() +bool +PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format, + Error &error) { - dsd.Reset(); - resampler.Reset(); -} + assert(!src_format.IsValid()); + assert(!dest_format.IsValid()); + 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) -{ - const int16_t *buf; - size_t len; + src_format = _src_format; + dest_format = _dest_format; + + AudioFormat format = src_format; + if (format.format == SampleFormat::DSD) + format.format = SampleFormat::FLOAT; - assert(dest_format.format == SampleFormat::S16); + enable_resampler = format.sample_rate != dest_format.sample_rate; + if (enable_resampler) { + if (!resampler.Open(format, dest_format.sample_rate, error)) + return false; - 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; + 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; + 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 (enable_channels) + channels_converter.Close(); + if (enable_format) + format_converter.Close(); + if (enable_resampler) + resampler.Close(); - 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; - } + dsd.Reset(); - *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) +const void * +PcmConvert::Convert(const void *src, size_t src_size, + size_t *dest_size_r, + 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); + ConstBuffer<void> buffer(src, src_size); + AudioFormat format = src_format; + + if (format.format == SampleFormat::DSD) { + auto s = ConstBuffer<uint8_t>::FromVoid(buffer); + auto d = dsd.ToFloat(format.channels, + false, 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(); + format.format = SampleFormat::FLOAT; } - *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 */ + if (enable_resampler) { + buffer = resampler.Resample(buffer, error); + if (buffer.IsNull()) + return nullptr; - 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; + format.format = resampler.GetOutputSampleFormat(); + format.sample_rate = dest_format.sample_rate; } - /* 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_format) { + buffer = format_converter.Convert(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) - return nullptr; + format.format = dest_format.format; } - *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; + format.channels = dest_format.channels; } - 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; - } + *dest_size_r = buffer.size; + return buffer.data; } |