pcm/Convert: migrate from class Error to C++ exceptions
This commit is contained in:
parent
860064c812
commit
ae1eb9ccde
@ -520,10 +520,7 @@ try {
|
||||
archive_plugin_init_all();
|
||||
#endif
|
||||
|
||||
if (!pcm_convert_global_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pcm_convert_global_init();
|
||||
|
||||
decoder_plugin_init_all();
|
||||
|
||||
|
@ -73,11 +73,12 @@ decoder_initialized(Decoder &decoder,
|
||||
|
||||
decoder.convert = new PcmConvert();
|
||||
|
||||
Error error;
|
||||
if (!decoder.convert->Open(dc.in_audio_format,
|
||||
dc.out_audio_format,
|
||||
error))
|
||||
decoder.error = std::make_exception_ptr(std::move(error));
|
||||
try {
|
||||
decoder.convert->Open(dc.in_audio_format,
|
||||
dc.out_audio_format);
|
||||
} catch (...) {
|
||||
decoder.error = std::current_exception();
|
||||
}
|
||||
}
|
||||
|
||||
const ScopeLock protect(dc.mutex);
|
||||
@ -484,19 +485,17 @@ decoder_data(Decoder &decoder,
|
||||
if (decoder.convert != nullptr) {
|
||||
assert(dc.in_audio_format != dc.out_audio_format);
|
||||
|
||||
Error error;
|
||||
auto result = decoder.convert->Convert({data, length},
|
||||
error);
|
||||
if (data == nullptr) {
|
||||
try {
|
||||
auto result = decoder.convert->Convert({data, length});
|
||||
data = result.data;
|
||||
length = result.size;
|
||||
} catch (const std::runtime_error &e) {
|
||||
/* the PCM conversion has failed - stop
|
||||
playback, since we have no better way to
|
||||
bail out */
|
||||
LogError(error);
|
||||
LogError(e);
|
||||
return DecoderCommand::STOP;
|
||||
}
|
||||
|
||||
data = result.data;
|
||||
length = result.size;
|
||||
} else {
|
||||
assert(dc.in_audio_format == dc.out_audio_format);
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "pcm/PcmConvert.hxx"
|
||||
#include "util/Manual.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "poison.h"
|
||||
|
||||
@ -88,9 +87,7 @@ ConvertFilter::Set(const AudioFormat &_out_audio_format)
|
||||
/* optimized special case: no-op */
|
||||
return;
|
||||
|
||||
Error error;
|
||||
if (!state.Open(in_audio_format, _out_audio_format, error))
|
||||
throw std::runtime_error(error.GetMessage());
|
||||
state.Open(in_audio_format, _out_audio_format);
|
||||
|
||||
out_audio_format = _out_audio_format;
|
||||
}
|
||||
@ -125,12 +122,7 @@ ConvertFilter::FilterPCM(ConstBuffer<void> src)
|
||||
/* optimized special case: no-op */
|
||||
return src;
|
||||
|
||||
Error error;
|
||||
auto result = state.Convert(src, error);
|
||||
if (result.IsNull())
|
||||
throw std::runtime_error(error.GetMessage());
|
||||
|
||||
return result;
|
||||
return state.Convert(src);
|
||||
}
|
||||
|
||||
const struct filter_plugin convert_filter_plugin = {
|
||||
|
@ -76,9 +76,7 @@ public:
|
||||
mixer(_mixer), base(_base), mode(REPLAY_GAIN_OFF) {
|
||||
info.Clear();
|
||||
|
||||
Error error;
|
||||
if (!pv.Open(out_audio_format.format, error))
|
||||
throw std::runtime_error(error.GetMessage());
|
||||
pv.Open(out_audio_format.format);
|
||||
}
|
||||
|
||||
void SetInfo(const ReplayGainInfo *_info) {
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "pcm/Volume.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@ -35,9 +34,7 @@ class VolumeFilter final : public Filter {
|
||||
public:
|
||||
explicit VolumeFilter(const AudioFormat &audio_format)
|
||||
:Filter(audio_format) {
|
||||
Error error;
|
||||
if (!pv.Open(out_audio_format.format, error))
|
||||
throw std::runtime_error(error.GetMessage());
|
||||
pv.Open(out_audio_format.format);
|
||||
}
|
||||
|
||||
unsigned GetVolume() const {
|
||||
|
@ -22,14 +22,13 @@
|
||||
#include "PcmChannels.hxx"
|
||||
#include "Domain.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
bool
|
||||
void
|
||||
PcmChannelsConverter::Open(SampleFormat _format,
|
||||
unsigned _src_channels, unsigned _dest_channels,
|
||||
gcc_unused Error &error)
|
||||
unsigned _src_channels, unsigned _dest_channels)
|
||||
{
|
||||
assert(_format != SampleFormat::UNDEFINED);
|
||||
|
||||
@ -41,16 +40,13 @@ PcmChannelsConverter::Open(SampleFormat _format,
|
||||
break;
|
||||
|
||||
default:
|
||||
error.Format(pcm_domain,
|
||||
"PCM channel conversion for %s is not implemented",
|
||||
sample_format_to_string(_format));
|
||||
return false;
|
||||
throw FormatRuntimeError("PCM channel conversion for %s is not implemented",
|
||||
sample_format_to_string(_format));
|
||||
}
|
||||
|
||||
format = _format;
|
||||
src_channels = _src_channels;
|
||||
dest_channels = _dest_channels;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -62,7 +58,7 @@ PcmChannelsConverter::Close()
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
PcmChannelsConverter::Convert(ConstBuffer<void> src, gcc_unused Error &error)
|
||||
PcmChannelsConverter::Convert(ConstBuffer<void> src)
|
||||
{
|
||||
switch (format) {
|
||||
case SampleFormat::UNDEFINED:
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
class Error;
|
||||
template<typename T> struct ConstBuffer;
|
||||
|
||||
/**
|
||||
@ -53,15 +52,14 @@ public:
|
||||
/**
|
||||
* Opens the object, prepare for Convert().
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param format the sample format
|
||||
* @param src_channels the number of source channels
|
||||
* @param dest_channels the number of destination channels
|
||||
* @param error location to store the error
|
||||
* @return true on success
|
||||
*/
|
||||
bool Open(SampleFormat format,
|
||||
unsigned src_channels, unsigned dest_channels,
|
||||
Error &error);
|
||||
void Open(SampleFormat format,
|
||||
unsigned src_channels, unsigned dest_channels);
|
||||
|
||||
/**
|
||||
* Closes the object. After that, you may call Open() again.
|
||||
@ -71,13 +69,13 @@ public:
|
||||
/**
|
||||
* Convert a block of PCM data.
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param src the input buffer
|
||||
* @param error location to store the error
|
||||
* @return the destination buffer on success,
|
||||
* ConstBuffer::Null() on error
|
||||
* @return the destination buffer
|
||||
*/
|
||||
gcc_pure
|
||||
ConstBuffer<void> Convert(ConstBuffer<void> src, Error &error);
|
||||
ConstBuffer<void> Convert(ConstBuffer<void> src);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "config/ConfigError.hxx"
|
||||
#include "config/Block.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#ifdef ENABLE_LIBSAMPLERATE
|
||||
#include "LibsamplerateResampler.hxx"
|
||||
@ -112,7 +112,7 @@ MigrateResamplerConfig(const config_param *param, ConfigBlock &buffer)
|
||||
}
|
||||
|
||||
static const ConfigBlock *
|
||||
GetResamplerConfig(ConfigBlock &buffer, Error &error)
|
||||
GetResamplerConfig(ConfigBlock &buffer)
|
||||
{
|
||||
const auto *old_param =
|
||||
config_get_param(ConfigOption::SAMPLERATE_CONVERTER);
|
||||
@ -120,49 +120,39 @@ GetResamplerConfig(ConfigBlock &buffer, Error &error)
|
||||
if (block == nullptr)
|
||||
return MigrateResamplerConfig(old_param, buffer);
|
||||
|
||||
if (old_param != nullptr) {
|
||||
error.Format(config_domain,
|
||||
"Cannot use both 'resampler' (line %d) and 'samplerate_converter' (line %d)",
|
||||
block->line, old_param->line);
|
||||
return nullptr;
|
||||
}
|
||||
if (old_param != nullptr)
|
||||
throw FormatRuntimeError("Cannot use both 'resampler' (line %d) and 'samplerate_converter' (line %d)",
|
||||
block->line, old_param->line);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
bool
|
||||
pcm_resampler_global_init(Error &error)
|
||||
void
|
||||
pcm_resampler_global_init()
|
||||
{
|
||||
ConfigBlock buffer;
|
||||
const auto *block = GetResamplerConfig(buffer, error);
|
||||
if (block == nullptr)
|
||||
return false;
|
||||
const auto *block = GetResamplerConfig(buffer);
|
||||
|
||||
const char *plugin_name = block->GetBlockValue("plugin");
|
||||
if (plugin_name == nullptr) {
|
||||
error.Format(config_domain,
|
||||
"'plugin' missing in line %d", block->line);
|
||||
return false;
|
||||
}
|
||||
if (plugin_name == nullptr)
|
||||
throw FormatRuntimeError("'plugin' missing in line %d",
|
||||
block->line);
|
||||
|
||||
if (strcmp(plugin_name, "internal") == 0) {
|
||||
selected_resampler = SelectedResampler::FALLBACK;
|
||||
return true;
|
||||
#ifdef ENABLE_SOXR
|
||||
} else if (strcmp(plugin_name, "soxr") == 0) {
|
||||
selected_resampler = SelectedResampler::SOXR;
|
||||
return pcm_resample_soxr_global_init(*block, error);
|
||||
pcm_resample_soxr_global_init(*block);
|
||||
#endif
|
||||
#ifdef ENABLE_LIBSAMPLERATE
|
||||
} else if (strcmp(plugin_name, "libsamplerate") == 0) {
|
||||
selected_resampler = SelectedResampler::LIBSAMPLERATE;
|
||||
return pcm_resample_lsr_global_init(*block, error);
|
||||
pcm_resample_lsr_global_init(*block);
|
||||
#endif
|
||||
} else {
|
||||
error.Format(config_domain,
|
||||
"No such resampler plugin: %s",
|
||||
plugin_name);
|
||||
return false;
|
||||
throw FormatRuntimeError("No such resampler plugin: %s",
|
||||
plugin_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,10 @@
|
||||
|
||||
#include "check.h"
|
||||
|
||||
class Error;
|
||||
class PcmResampler;
|
||||
|
||||
bool
|
||||
pcm_resampler_global_init(Error &error);
|
||||
void
|
||||
pcm_resampler_global_init();
|
||||
|
||||
/**
|
||||
* Create a #PcmResampler instance from the implementation class
|
||||
|
@ -23,8 +23,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
AudioFormat
|
||||
FallbackPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
gcc_unused Error &error)
|
||||
FallbackPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate)
|
||||
{
|
||||
assert(af.IsValid());
|
||||
assert(audio_valid_sample_rate(new_sample_rate));
|
||||
@ -116,7 +115,7 @@ pcm_resample_fallback_void(PcmBuffer &buffer,
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
FallbackPcmResampler::Resample(ConstBuffer<void> src, gcc_unused Error &error)
|
||||
FallbackPcmResampler::Resample(ConstBuffer<void> src)
|
||||
{
|
||||
switch (format.format) {
|
||||
case SampleFormat::UNDEFINED:
|
||||
|
@ -36,11 +36,9 @@ class FallbackPcmResampler final : public PcmResampler {
|
||||
PcmBuffer buffer;
|
||||
|
||||
public:
|
||||
virtual AudioFormat Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
Error &error) override;
|
||||
virtual void Close() override;
|
||||
virtual ConstBuffer<void> Resample(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> Resample(ConstBuffer<void> src) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -20,15 +20,13 @@
|
||||
#include "config.h"
|
||||
#include "FormatConverter.hxx"
|
||||
#include "PcmFormat.hxx"
|
||||
#include "Domain.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
bool
|
||||
PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format,
|
||||
Error &error)
|
||||
void
|
||||
PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format)
|
||||
{
|
||||
assert(_src_format != SampleFormat::UNDEFINED);
|
||||
assert(_dest_format != SampleFormat::UNDEFINED);
|
||||
@ -40,11 +38,9 @@ PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format,
|
||||
|
||||
case SampleFormat::S8:
|
||||
case SampleFormat::DSD:
|
||||
error.Format(pcm_domain,
|
||||
"PCM conversion from %s to %s is not implemented",
|
||||
sample_format_to_string(_src_format),
|
||||
sample_format_to_string(_dest_format));
|
||||
return false;
|
||||
throw FormatRuntimeError("PCM conversion from %s to %s is not implemented",
|
||||
sample_format_to_string(_src_format),
|
||||
sample_format_to_string(_dest_format));
|
||||
|
||||
case SampleFormat::S16:
|
||||
case SampleFormat::S24_P32:
|
||||
@ -55,7 +51,6 @@ PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format,
|
||||
|
||||
src_format = _src_format;
|
||||
dest_format = _dest_format;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -68,7 +63,7 @@ PcmFormatConverter::Close()
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
PcmFormatConverter::Convert(ConstBuffer<void> src, gcc_unused Error &error)
|
||||
PcmFormatConverter::Convert(ConstBuffer<void> src)
|
||||
{
|
||||
switch (dest_format) {
|
||||
case SampleFormat::UNDEFINED:
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
class Error;
|
||||
template<typename T> struct ConstBuffer;
|
||||
|
||||
/**
|
||||
@ -56,13 +55,12 @@ public:
|
||||
/**
|
||||
* Opens the object, prepare for Convert().
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param src_format the sample format of incoming data
|
||||
* @param dest_format the sample format of outgoing data
|
||||
* @param error location to store the error
|
||||
* @return true on success
|
||||
*/
|
||||
bool Open(SampleFormat src_format, SampleFormat dest_format,
|
||||
Error &error);
|
||||
void Open(SampleFormat src_format, SampleFormat dest_format);
|
||||
|
||||
/**
|
||||
* Closes the object. After that, you may call Open() again.
|
||||
@ -72,13 +70,13 @@ public:
|
||||
/**
|
||||
* Convert a block of PCM data.
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param src the input buffer
|
||||
* @param error location to store the error
|
||||
* @return the destination buffer on success,
|
||||
* ConstBuffer::Null() on error
|
||||
* @return the destination buffer
|
||||
*/
|
||||
gcc_pure
|
||||
ConstBuffer<void> Convert(ConstBuffer<void> src, Error &error);
|
||||
ConstBuffer<void> Convert(ConstBuffer<void> src);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -32,33 +32,28 @@ GluePcmResampler::~GluePcmResampler()
|
||||
delete resampler;
|
||||
}
|
||||
|
||||
bool
|
||||
GluePcmResampler::Open(AudioFormat src_format, unsigned new_sample_rate,
|
||||
Error &error)
|
||||
void
|
||||
GluePcmResampler::Open(AudioFormat src_format, unsigned new_sample_rate)
|
||||
{
|
||||
assert(src_format.IsValid());
|
||||
assert(audio_valid_sample_rate(new_sample_rate));
|
||||
|
||||
AudioFormat requested_format = src_format;
|
||||
AudioFormat dest_format = resampler->Open(requested_format,
|
||||
new_sample_rate,
|
||||
error);
|
||||
if (!dest_format.IsValid())
|
||||
return false;
|
||||
new_sample_rate);
|
||||
assert(dest_format.IsValid());
|
||||
|
||||
assert(requested_format.channels == src_format.channels);
|
||||
assert(dest_format.channels == src_format.channels);
|
||||
assert(dest_format.sample_rate == new_sample_rate);
|
||||
|
||||
if (requested_format.format != src_format.format &&
|
||||
!format_converter.Open(src_format.format, requested_format.format,
|
||||
error))
|
||||
return false;
|
||||
if (requested_format.format != src_format.format)
|
||||
format_converter.Open(src_format.format,
|
||||
requested_format.format);
|
||||
|
||||
src_sample_format = src_format.format;
|
||||
requested_sample_format = requested_format.format;
|
||||
output_sample_format = dest_format.format;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -71,15 +66,12 @@ GluePcmResampler::Close()
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
GluePcmResampler::Resample(ConstBuffer<void> src, Error &error)
|
||||
GluePcmResampler::Resample(ConstBuffer<void> src)
|
||||
{
|
||||
assert(!src.IsNull());
|
||||
|
||||
if (requested_sample_format != src_sample_format) {
|
||||
src = format_converter.Convert(src, error);
|
||||
if (src.IsNull())
|
||||
return nullptr;
|
||||
}
|
||||
if (requested_sample_format != src_sample_format)
|
||||
src = format_converter.Convert(src);
|
||||
|
||||
return resampler->Resample(src, error);
|
||||
return resampler->Resample(src);
|
||||
}
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "AudioFormat.hxx"
|
||||
#include "FormatConverter.hxx"
|
||||
|
||||
class Error;
|
||||
class PcmResampler;
|
||||
template<typename T> struct ConstBuffer;
|
||||
|
||||
@ -49,15 +48,14 @@ public:
|
||||
GluePcmResampler();
|
||||
~GluePcmResampler();
|
||||
|
||||
bool Open(AudioFormat src_format, unsigned new_sample_rate,
|
||||
Error &error);
|
||||
void Open(AudioFormat src_format, unsigned new_sample_rate);
|
||||
void Close();
|
||||
|
||||
SampleFormat GetOutputSampleFormat() const {
|
||||
return output_sample_format;
|
||||
}
|
||||
|
||||
ConstBuffer<void> Resample(ConstBuffer<void> src, Error &error);
|
||||
ConstBuffer<void> Resample(ConstBuffer<void> src);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "LibsamplerateResampler.hxx"
|
||||
#include "config/Block.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
@ -63,26 +63,21 @@ lsr_parse_converter(const char *s)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
pcm_resample_lsr_global_init(const ConfigBlock &block, Error &error)
|
||||
void
|
||||
pcm_resample_lsr_global_init(const ConfigBlock &block)
|
||||
{
|
||||
const char *converter = block.GetBlockValue("type", "2");
|
||||
if (!lsr_parse_converter(converter)) {
|
||||
error.Format(libsamplerate_domain,
|
||||
"unknown samplerate converter '%s'", converter);
|
||||
return false;
|
||||
}
|
||||
if (!lsr_parse_converter(converter))
|
||||
throw FormatRuntimeError("unknown samplerate converter '%s'",
|
||||
converter);
|
||||
|
||||
FormatDebug(libsamplerate_domain,
|
||||
"libsamplerate converter '%s'",
|
||||
src_get_name(lsr_converter));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AudioFormat
|
||||
LibsampleratePcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
Error &error)
|
||||
LibsampleratePcmResampler::Open(AudioFormat &af, unsigned new_sample_rate)
|
||||
{
|
||||
assert(af.IsValid());
|
||||
assert(audio_valid_sample_rate(new_sample_rate));
|
||||
@ -96,12 +91,9 @@ LibsampleratePcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
|
||||
int src_error;
|
||||
state = src_new(lsr_converter, channels, &src_error);
|
||||
if (!state) {
|
||||
error.Format(libsamplerate_domain, src_error,
|
||||
"libsamplerate initialization has failed: %s",
|
||||
src_strerror(src_error));
|
||||
return AudioFormat::Undefined();
|
||||
}
|
||||
if (!state)
|
||||
throw FormatRuntimeError("libsamplerate initialization has failed: %s",
|
||||
src_strerror(src_error));
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
@ -122,22 +114,8 @@ LibsampleratePcmResampler::Close()
|
||||
state = src_delete(state);
|
||||
}
|
||||
|
||||
static bool
|
||||
src_process(SRC_STATE *state, SRC_DATA *data, Error &error)
|
||||
{
|
||||
int result = src_process(state, data);
|
||||
if (result != 0) {
|
||||
error.Format(libsamplerate_domain, result,
|
||||
"libsamplerate has failed: %s",
|
||||
src_strerror(result));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline ConstBuffer<float>
|
||||
LibsampleratePcmResampler::Resample2(ConstBuffer<float> src, Error &error)
|
||||
LibsampleratePcmResampler::Resample2(ConstBuffer<float> src)
|
||||
{
|
||||
assert(src.size % channels == 0);
|
||||
|
||||
@ -151,15 +129,17 @@ LibsampleratePcmResampler::Resample2(ConstBuffer<float> src, Error &error)
|
||||
data.input_frames = src_frames;
|
||||
data.output_frames = dest_frames;
|
||||
|
||||
if (!src_process(state, &data, error))
|
||||
return nullptr;
|
||||
int result = src_process(state, &data);
|
||||
if (result != 0)
|
||||
throw FormatRuntimeError("libsamplerate has failed: %s",
|
||||
src_strerror(result));
|
||||
|
||||
return ConstBuffer<float>(data.data_out,
|
||||
data.output_frames_gen * channels);
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
LibsampleratePcmResampler::Resample(ConstBuffer<void> src, Error &error)
|
||||
LibsampleratePcmResampler::Resample(ConstBuffer<void> src)
|
||||
{
|
||||
return Resample2(ConstBuffer<float>::FromVoid(src), error).ToVoid();
|
||||
return Resample2(ConstBuffer<float>::FromVoid(src)).ToVoid();
|
||||
}
|
||||
|
@ -42,17 +42,15 @@ class LibsampleratePcmResampler final : public PcmResampler {
|
||||
PcmBuffer buffer;
|
||||
|
||||
public:
|
||||
virtual AudioFormat Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
Error &error) override;
|
||||
virtual void Close() override;
|
||||
virtual ConstBuffer<void> Resample(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> Resample(ConstBuffer<void> src) override;
|
||||
|
||||
private:
|
||||
ConstBuffer<float> Resample2(ConstBuffer<float> src, Error &error);
|
||||
ConstBuffer<float> Resample2(ConstBuffer<float> src);
|
||||
};
|
||||
|
||||
bool
|
||||
pcm_resample_lsr_global_init(const ConfigBlock &block, Error &error);
|
||||
void
|
||||
pcm_resample_lsr_global_init(const ConfigBlock &block);
|
||||
|
||||
#endif
|
||||
|
@ -22,15 +22,14 @@
|
||||
#include "Domain.hxx"
|
||||
#include "ConfiguredResampler.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
bool
|
||||
pcm_convert_global_init(Error &error)
|
||||
void
|
||||
pcm_convert_global_init()
|
||||
{
|
||||
return pcm_resampler_global_init(error);
|
||||
pcm_resampler_global_init();
|
||||
}
|
||||
|
||||
PcmConvert::PcmConvert()
|
||||
@ -47,9 +46,8 @@ PcmConvert::~PcmConvert()
|
||||
assert(!dest_format.IsValid());
|
||||
}
|
||||
|
||||
bool
|
||||
PcmConvert::Open(const AudioFormat _src_format, const AudioFormat _dest_format,
|
||||
Error &error)
|
||||
void
|
||||
PcmConvert::Open(const AudioFormat _src_format, const AudioFormat _dest_format)
|
||||
{
|
||||
assert(!src_format.IsValid());
|
||||
assert(!dest_format.IsValid());
|
||||
@ -62,39 +60,42 @@ PcmConvert::Open(const AudioFormat _src_format, const AudioFormat _dest_format,
|
||||
|
||||
enable_resampler = format.sample_rate != _dest_format.sample_rate;
|
||||
if (enable_resampler) {
|
||||
if (!resampler.Open(format, _dest_format.sample_rate, error))
|
||||
return false;
|
||||
resampler.Open(format, _dest_format.sample_rate);
|
||||
|
||||
format.format = resampler.GetOutputSampleFormat();
|
||||
format.sample_rate = _dest_format.sample_rate;
|
||||
}
|
||||
|
||||
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 (enable_format) {
|
||||
try {
|
||||
format_converter.Open(format.format,
|
||||
_dest_format.format);
|
||||
} catch (...) {
|
||||
if (enable_resampler)
|
||||
resampler.Close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
if (enable_channels) {
|
||||
try {
|
||||
channels_converter.Open(format.format, format.channels,
|
||||
_dest_format.channels);
|
||||
} catch (...) {
|
||||
if (enable_format)
|
||||
format_converter.Close();
|
||||
if (enable_resampler)
|
||||
resampler.Close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
src_format = _src_format;
|
||||
dest_format = _dest_format;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
@ -118,39 +119,27 @@ PcmConvert::Close()
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
PcmConvert::Convert(ConstBuffer<void> buffer, Error &error)
|
||||
PcmConvert::Convert(ConstBuffer<void> buffer)
|
||||
{
|
||||
#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 (d.IsNull())
|
||||
throw std::runtime_error("DSD to PCM conversion failed");
|
||||
|
||||
buffer = d.ToVoid();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (enable_resampler) {
|
||||
buffer = resampler.Resample(buffer, error);
|
||||
if (buffer.IsNull())
|
||||
return nullptr;
|
||||
}
|
||||
if (enable_resampler)
|
||||
buffer = resampler.Resample(buffer);
|
||||
|
||||
if (enable_format) {
|
||||
buffer = format_converter.Convert(buffer, error);
|
||||
if (buffer.IsNull())
|
||||
return nullptr;
|
||||
}
|
||||
if (enable_format)
|
||||
buffer = format_converter.Convert(buffer);
|
||||
|
||||
if (enable_channels) {
|
||||
buffer = channels_converter.Convert(buffer, error);
|
||||
if (buffer.IsNull())
|
||||
return nullptr;
|
||||
}
|
||||
if (enable_channels)
|
||||
buffer = channels_converter.Convert(buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
#endif
|
||||
|
||||
template<typename T> struct ConstBuffer;
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* This object is statically allocated (within another struct), and
|
||||
@ -57,9 +56,10 @@ public:
|
||||
|
||||
/**
|
||||
* Prepare the object. Call Close() when done.
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*/
|
||||
bool Open(AudioFormat _src_format, AudioFormat _dest_format,
|
||||
Error &error);
|
||||
void Open(AudioFormat _src_format, AudioFormat _dest_format);
|
||||
|
||||
/**
|
||||
* Close the object after it was prepared with Open(). After
|
||||
@ -70,14 +70,15 @@ public:
|
||||
/**
|
||||
* Converts PCM data between two audio formats.
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param src the source PCM buffer
|
||||
* @param error location to store the error occurring
|
||||
* @return the destination buffer, or nullptr on error
|
||||
* @return the destination buffer
|
||||
*/
|
||||
ConstBuffer<void> Convert(ConstBuffer<void> src, Error &error);
|
||||
ConstBuffer<void> Convert(ConstBuffer<void> src);
|
||||
};
|
||||
|
||||
bool
|
||||
pcm_convert_global_init(Error &error);
|
||||
void
|
||||
pcm_convert_global_init();
|
||||
|
||||
#endif
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "Compiler.h"
|
||||
|
||||
struct AudioFormat;
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* This is an interface for plugins that convert PCM data to a
|
||||
@ -37,16 +36,17 @@ public:
|
||||
/**
|
||||
* Opens the resampler, preparing it for Resample().
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param af the audio format of incoming data; the plugin may
|
||||
* modify the object to enforce another input format (however,
|
||||
* it may not request a different input sample rate)
|
||||
* @param new_sample_rate the requested output sample rate
|
||||
* @param error location to store the error
|
||||
* @return the format of outgoing data or
|
||||
* AudioFormat::Undefined() on error
|
||||
* @return the format of outgoing data
|
||||
*/
|
||||
virtual AudioFormat Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
Error &error) = 0;
|
||||
virtual AudioFormat Open(AudioFormat &af,
|
||||
unsigned new_sample_rate) = 0;
|
||||
|
||||
/**
|
||||
* Closes the resampler. After that, you may call Open()
|
||||
@ -58,14 +58,11 @@ public:
|
||||
* Resamples a block of PCM data.
|
||||
*
|
||||
* @param src the input buffer
|
||||
* @param error location to store the error occurring
|
||||
* @return the destination buffer on success (will be
|
||||
* invalidated by filter_close() or filter_filter()), nullptr on
|
||||
* error
|
||||
* @return the destination buffer (will be invalidated by
|
||||
* filter_close() or filter_filter())
|
||||
*/
|
||||
gcc_pure
|
||||
virtual ConstBuffer<void> Resample(ConstBuffer<void> src,
|
||||
Error &error) = 0;
|
||||
virtual ConstBuffer<void> Resample(ConstBuffer<void> src) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "SoxrResampler.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "config/Block.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
@ -80,18 +80,16 @@ soxr_parse_quality(const char *quality)
|
||||
return SOXR_INVALID_RECIPE;
|
||||
}
|
||||
|
||||
bool
|
||||
pcm_resample_soxr_global_init(const ConfigBlock &block, Error &error)
|
||||
void
|
||||
pcm_resample_soxr_global_init(const ConfigBlock &block)
|
||||
{
|
||||
const char *quality_string = block.GetBlockValue("quality");
|
||||
unsigned long recipe = soxr_parse_quality(quality_string);
|
||||
if (recipe == SOXR_INVALID_RECIPE) {
|
||||
assert(quality_string != nullptr);
|
||||
|
||||
error.Format(soxr_domain,
|
||||
"unknown quality setting '%s' in line %d",
|
||||
quality_string, block.line);
|
||||
return false;
|
||||
throw FormatRuntimeError("unknown quality setting '%s' in line %d",
|
||||
quality_string, block.line);
|
||||
}
|
||||
|
||||
soxr_quality = soxr_quality_spec(recipe, 0);
|
||||
@ -102,13 +100,10 @@ pcm_resample_soxr_global_init(const ConfigBlock &block, Error &error)
|
||||
|
||||
const unsigned n_threads = block.GetBlockValue("threads", 1);
|
||||
soxr_runtime = soxr_runtime_spec(n_threads);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AudioFormat
|
||||
SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
Error &error)
|
||||
SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate)
|
||||
{
|
||||
assert(af.IsValid());
|
||||
assert(audio_valid_sample_rate(new_sample_rate));
|
||||
@ -117,11 +112,9 @@ SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
soxr = soxr_create(af.sample_rate, new_sample_rate,
|
||||
af.channels, &e,
|
||||
nullptr, &soxr_quality, &soxr_runtime);
|
||||
if (soxr == nullptr) {
|
||||
error.Format(soxr_domain,
|
||||
"soxr initialization has failed: %s", e);
|
||||
return AudioFormat::Undefined();
|
||||
}
|
||||
if (soxr == nullptr)
|
||||
throw FormatRuntimeError("soxr initialization has failed: %s",
|
||||
e);
|
||||
|
||||
FormatDebug(soxr_domain, "soxr engine '%s'", soxr_engine(soxr));
|
||||
|
||||
@ -147,7 +140,7 @@ SoxrPcmResampler::Close()
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
SoxrPcmResampler::Resample(ConstBuffer<void> src, Error &error)
|
||||
SoxrPcmResampler::Resample(ConstBuffer<void> src)
|
||||
{
|
||||
const size_t frame_size = channels * sizeof(float);
|
||||
assert(src.size % frame_size == 0);
|
||||
@ -162,10 +155,8 @@ SoxrPcmResampler::Resample(ConstBuffer<void> src, Error &error)
|
||||
size_t i_done, o_done;
|
||||
soxr_error_t e = soxr_process(soxr, src.data, n_frames, &i_done,
|
||||
output_buffer, o_frames, &o_done);
|
||||
if (e != nullptr) {
|
||||
error.Format(soxr_domain, "soxr error: %s", e);
|
||||
return nullptr;
|
||||
}
|
||||
if (e != nullptr)
|
||||
throw FormatRuntimeError("soxr error: %s", e);
|
||||
|
||||
return { output_buffer, o_done * frame_size };
|
||||
}
|
||||
|
@ -39,14 +39,12 @@ class SoxrPcmResampler final : public PcmResampler {
|
||||
PcmBuffer buffer;
|
||||
|
||||
public:
|
||||
virtual AudioFormat Open(AudioFormat &af, unsigned new_sample_rate,
|
||||
Error &error) override;
|
||||
virtual void Close() override;
|
||||
virtual ConstBuffer<void> Resample(ConstBuffer<void> src,
|
||||
Error &error) override;
|
||||
AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override;
|
||||
void Close() override;
|
||||
ConstBuffer<void> Resample(ConstBuffer<void> src) override;
|
||||
};
|
||||
|
||||
bool
|
||||
pcm_resample_soxr_global_init(const ConfigBlock &block, Error &error);
|
||||
void
|
||||
pcm_resample_soxr_global_init(const ConfigBlock &block);
|
||||
|
||||
#endif
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "Traits.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/WritableBuffer.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include "PcmDither.cxx" // including the .cxx file to get inlined templates
|
||||
|
||||
@ -97,17 +97,15 @@ pcm_volume_change_float(float *dest, const float *src, size_t n,
|
||||
dest[i] = src[i] * volume;
|
||||
}
|
||||
|
||||
bool
|
||||
PcmVolume::Open(SampleFormat _format, Error &error)
|
||||
void
|
||||
PcmVolume::Open(SampleFormat _format)
|
||||
{
|
||||
assert(format == SampleFormat::UNDEFINED);
|
||||
|
||||
switch (_format) {
|
||||
case SampleFormat::UNDEFINED:
|
||||
error.Format(pcm_domain,
|
||||
"Software volume for %s is not implemented",
|
||||
sample_format_to_string(_format));
|
||||
return false;
|
||||
throw FormatRuntimeError("Software volume for %s is not implemented",
|
||||
sample_format_to_string(_format));
|
||||
|
||||
case SampleFormat::S8:
|
||||
case SampleFormat::S16:
|
||||
@ -122,7 +120,6 @@ PcmVolume::Open(SampleFormat _format, Error &error)
|
||||
}
|
||||
|
||||
format = _format;
|
||||
return true;
|
||||
}
|
||||
|
||||
ConstBuffer<void>
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
class Error;
|
||||
template<typename T> struct ConstBuffer;
|
||||
|
||||
/**
|
||||
@ -93,11 +92,11 @@ public:
|
||||
/**
|
||||
* Opens the object, prepare for Apply().
|
||||
*
|
||||
* Throws std::runtime_error on error.
|
||||
*
|
||||
* @param format the sample format
|
||||
* @param error location to store the error
|
||||
* @return true on success
|
||||
*/
|
||||
bool Open(SampleFormat format, Error &error);
|
||||
void Open(SampleFormat format);
|
||||
|
||||
/**
|
||||
* Closes the object. After that, you may call Open() again.
|
||||
|
@ -38,8 +38,9 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
try {
|
||||
AudioFormat in_audio_format, out_audio_format;
|
||||
|
||||
if (argc != 3) {
|
||||
@ -68,10 +69,7 @@ int main(int argc, char **argv)
|
||||
const size_t in_frame_size = in_audio_format.GetFrameSize();
|
||||
|
||||
PcmConvert state;
|
||||
if (!state.Open(in_audio_format, out_audio_format_mask, error)) {
|
||||
LogError(error, "Failed to open PcmConvert");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
state.Open(in_audio_format, out_audio_format_mask);
|
||||
|
||||
StaticFifoBuffer<uint8_t, 4096> buffer;
|
||||
|
||||
@ -96,12 +94,7 @@ int main(int argc, char **argv)
|
||||
|
||||
buffer.Consume(src.size);
|
||||
|
||||
auto output = state.Convert({src.data, src.size}, error);
|
||||
if (output.IsNull()) {
|
||||
state.Close();
|
||||
LogError(error, "Failed to convert");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
auto output = state.Convert({src.data, src.size});
|
||||
|
||||
gcc_unused ssize_t ignored = write(1, output.data,
|
||||
output.size);
|
||||
@ -110,4 +103,7 @@ int main(int argc, char **argv)
|
||||
state.Close();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -36,8 +36,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
try {
|
||||
static char buffer[4096];
|
||||
ssize_t nbytes;
|
||||
|
||||
@ -56,10 +57,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
PcmVolume pv;
|
||||
if (!pv.Open(audio_format.format, error)) {
|
||||
fprintf(stderr, "%s\n", error.GetMessage());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pv.Open(audio_format.format);
|
||||
|
||||
while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) {
|
||||
auto dest = pv.Apply({buffer, size_t(nbytes)});
|
||||
@ -67,4 +65,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
pv.Close();
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "pcm/Volume.hxx"
|
||||
#include "pcm/Traits.hxx"
|
||||
#include "util/ConstBuffer.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "test_pcm_util.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
@ -37,7 +36,7 @@ TestVolume(G g=G())
|
||||
typedef typename Traits::value_type value_type;
|
||||
|
||||
PcmVolume pv;
|
||||
CPPUNIT_ASSERT(pv.Open(F, IgnoreError()));
|
||||
pv.Open(F);
|
||||
|
||||
constexpr size_t N = 509;
|
||||
static value_type zero[N];
|
||||
@ -96,7 +95,7 @@ void
|
||||
PcmVolumeTest::TestVolumeFloat()
|
||||
{
|
||||
PcmVolume pv;
|
||||
CPPUNIT_ASSERT(pv.Open(SampleFormat::FLOAT, IgnoreError()));
|
||||
pv.Open(SampleFormat::FLOAT);
|
||||
|
||||
constexpr size_t N = 509;
|
||||
static float zero[N];
|
||||
|
Loading…
Reference in New Issue
Block a user