From f6ec43b9ec2a1f64ed09479b60e85bd7d4fdb962 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 2 Jan 2018 18:22:53 +0100 Subject: [PATCH] pcm/Resampler: add virtual method Flush() Wired to Filter::Flush(). Closes #153 --- NEWS | 2 ++ src/filter/plugins/ConvertFilterPlugin.cxx | 4 ++++ src/pcm/GlueResampler.cxx | 6 ++++++ src/pcm/GlueResampler.hxx | 2 ++ src/pcm/PcmConvert.cxx | 19 +++++++++++++++++++ src/pcm/PcmConvert.hxx | 6 ++++++ src/pcm/Resampler.hxx | 8 ++++++++ src/pcm/SoxrResampler.cxx | 21 +++++++++++++++++++++ src/pcm/SoxrResampler.hxx | 1 + 9 files changed, 69 insertions(+) diff --git a/NEWS b/NEWS index 342f8029f..0e432c07f 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ ver 0.21 (not yet released) * decoder - gme: try loading m3u sidecar files - pcm: support audio/L24 (RFC 3190) +* resampler + - soxr: flush resampler at end of song * output - alsa: non-blocking mode - alsa: change "dop" and "allowed_formats" settings at runtime diff --git a/src/filter/plugins/ConvertFilterPlugin.cxx b/src/filter/plugins/ConvertFilterPlugin.cxx index 5e640aaa0..8600ea03d 100644 --- a/src/filter/plugins/ConvertFilterPlugin.cxx +++ b/src/filter/plugins/ConvertFilterPlugin.cxx @@ -55,6 +55,10 @@ public: } ConstBuffer FilterPCM(ConstBuffer src) override; + + ConstBuffer Flush() override { + return state.Flush(); + } }; class PreparedConvertFilter final : public PreparedFilter { diff --git a/src/pcm/GlueResampler.cxx b/src/pcm/GlueResampler.cxx index 36ee4648b..78118feff 100644 --- a/src/pcm/GlueResampler.cxx +++ b/src/pcm/GlueResampler.cxx @@ -81,3 +81,9 @@ GluePcmResampler::Resample(ConstBuffer src) return resampler->Resample(src); } + +ConstBuffer +GluePcmResampler::Flush() +{ + return resampler->Flush(); +} diff --git a/src/pcm/GlueResampler.hxx b/src/pcm/GlueResampler.hxx index 6c81d1886..4c5c918a4 100644 --- a/src/pcm/GlueResampler.hxx +++ b/src/pcm/GlueResampler.hxx @@ -61,6 +61,8 @@ public: void Reset() noexcept; ConstBuffer Resample(ConstBuffer src); + + ConstBuffer Flush(); }; #endif diff --git a/src/pcm/PcmConvert.cxx b/src/pcm/PcmConvert.cxx index a63e92a7c..548c5a9d1 100644 --- a/src/pcm/PcmConvert.cxx +++ b/src/pcm/PcmConvert.cxx @@ -152,3 +152,22 @@ PcmConvert::Convert(ConstBuffer buffer) return buffer; } + +ConstBuffer +PcmConvert::Flush() +{ + if (enable_resampler) { + auto buffer = resampler.Flush(); + if (!buffer.IsNull()) { + if (enable_format) + buffer = format_converter.Convert(buffer); + + if (enable_channels) + buffer = channels_converter.Convert(buffer); + + return buffer; + } + } + + return nullptr; +} diff --git a/src/pcm/PcmConvert.hxx b/src/pcm/PcmConvert.hxx index 264179635..60a85b1d8 100644 --- a/src/pcm/PcmConvert.hxx +++ b/src/pcm/PcmConvert.hxx @@ -81,6 +81,12 @@ public: * @return the destination buffer */ ConstBuffer Convert(ConstBuffer src); + + /** + * Flush pending data and return it. This should be called + * repepatedly until it returns nullptr. + */ + ConstBuffer Flush(); }; void diff --git a/src/pcm/Resampler.hxx b/src/pcm/Resampler.hxx index 485450acc..7f2c5ae4c 100644 --- a/src/pcm/Resampler.hxx +++ b/src/pcm/Resampler.hxx @@ -70,6 +70,14 @@ public: * filter_close() or filter_filter()) */ virtual ConstBuffer Resample(ConstBuffer src) = 0; + + /** + * Flush pending data and return it. This should be called + * repepatedly until it returns nullptr. + */ + virtual ConstBuffer Flush() { + return nullptr; + } }; #endif diff --git a/src/pcm/SoxrResampler.cxx b/src/pcm/SoxrResampler.cxx index 0c887cbdd..6dc80f416 100644 --- a/src/pcm/SoxrResampler.cxx +++ b/src/pcm/SoxrResampler.cxx @@ -160,3 +160,24 @@ SoxrPcmResampler::Resample(ConstBuffer src) return { output_buffer, o_done * frame_size }; } + +ConstBuffer +SoxrPcmResampler::Flush() +{ + const size_t frame_size = channels * sizeof(float); + const size_t o_frames = 1024; + + float *output_buffer = (float *)buffer.Get(o_frames * frame_size); + + size_t o_done; + soxr_error_t e = soxr_process(soxr, nullptr, 0, nullptr, + output_buffer, o_frames, &o_done); + if (e != nullptr) + throw FormatRuntimeError("soxr error: %s", e); + + if (o_done == 0) + /* flush complete */ + output_buffer = nullptr; + + return { output_buffer, o_done * frame_size }; +} diff --git a/src/pcm/SoxrResampler.hxx b/src/pcm/SoxrResampler.hxx index ee4b98869..8df36c959 100644 --- a/src/pcm/SoxrResampler.hxx +++ b/src/pcm/SoxrResampler.hxx @@ -42,6 +42,7 @@ public: AudioFormat Open(AudioFormat &af, unsigned new_sample_rate) override; void Close() noexcept override; ConstBuffer Resample(ConstBuffer src) override; + ConstBuffer Flush() override; }; void