aboutsummaryrefslogtreecommitdiffstats
path: root/src/pcm/PcmConvert.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/pcm/PcmConvert.cxx')
-rw-r--r--src/pcm/PcmConvert.cxx334
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;
}