diff --git a/src/filter/LoadChain.cxx b/src/filter/LoadChain.cxx index 67c94e85c..519eb461b 100644 --- a/src/filter/LoadChain.cxx +++ b/src/filter/LoadChain.cxx @@ -21,27 +21,29 @@ #include "Factory.hxx" #include "Prepared.hxx" #include "plugins/AutoConvertFilterPlugin.hxx" -#include "plugins/ChainFilterPlugin.hxx" +#include "plugins/TwoFilters.hxx" #include "util/IterableSplitString.hxx" #include static void -filter_chain_append_new(PreparedFilter &chain, FilterFactory &factory, +filter_chain_append_new(std::unique_ptr &chain, + FilterFactory &factory, std::string_view template_name) { /* using the AutoConvert filter just in case the specified filter plugin does not support the exact input format */ - filter_chain_append(chain, template_name, - /* unfortunately, MakeFilter() wants a - null-terminated string, so we need to - copy it here */ - autoconvert_filter_new(factory.MakeFilter(std::string(template_name).c_str()))); + chain = ChainFilters(std::move(chain), + /* unfortunately, MakeFilter() wants a + null-terminated string, so we need to + copy it here */ + autoconvert_filter_new(factory.MakeFilter(std::string(template_name).c_str())), + template_name); } void -filter_chain_parse(PreparedFilter &chain, +filter_chain_parse(std::unique_ptr &chain, FilterFactory &factory, const char *spec) { diff --git a/src/filter/LoadChain.hxx b/src/filter/LoadChain.hxx index c0196e22d..c36c63f4c 100644 --- a/src/filter/LoadChain.hxx +++ b/src/filter/LoadChain.hxx @@ -20,6 +20,8 @@ #ifndef MPD_FILTER_LOAD_CHAIN_HXX #define MPD_FILTER_LOAD_CHAIN_HXX +#include + class FilterFactory; class PreparedFilter; @@ -35,7 +37,7 @@ class PreparedFilter; * @param spec the filter chain specification */ void -filter_chain_parse(PreparedFilter &chain, +filter_chain_parse(std::unique_ptr &chain, FilterFactory &factory, const char *spec); diff --git a/src/filter/plugins/ChainFilterPlugin.cxx b/src/filter/plugins/ChainFilterPlugin.cxx deleted file mode 100644 index 488e43896..000000000 --- a/src/filter/plugins/ChainFilterPlugin.cxx +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright 2003-2021 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "ChainFilterPlugin.hxx" -#include "filter/Filter.hxx" -#include "filter/Prepared.hxx" -#include "pcm/AudioFormat.hxx" -#include "util/ConstBuffer.hxx" -#include "util/StringBuffer.hxx" -#include "util/RuntimeError.hxx" - -#include -#include -#include -#include - -class ChainFilter final : public Filter { - struct Child { - std::unique_ptr filter; - - explicit Child(std::unique_ptr &&_filter) noexcept - :filter(std::move(_filter)) {} - }; - - std::list children; - - /** - * The child which will be flushed in the next Flush() call. - */ - std::list::iterator flushing = children.end(); - -public: - explicit ChainFilter(AudioFormat _audio_format) - :Filter(_audio_format) {} - - void Append(std::unique_ptr filter) noexcept { - assert(out_audio_format.IsValid()); - out_audio_format = filter->GetOutAudioFormat(); - assert(out_audio_format.IsValid()); - - children.emplace_back(std::move(filter)); - - RewindFlush(); - } - - /* virtual methods from class Filter */ - void Reset() noexcept override; - ConstBuffer FilterPCM(ConstBuffer src) override; - ConstBuffer Flush() override; - -private: - void RewindFlush() { - flushing = children.begin(); - } - -}; - -class PreparedChainFilter final : public PreparedFilter { - struct Child { - const std::string name; - std::unique_ptr filter; - - Child(std::string_view _name, - std::unique_ptr _filter) - :name(_name), filter(std::move(_filter)) {} - - Child(const Child &) = delete; - Child &operator=(const Child &) = delete; - - std::unique_ptr Open(const AudioFormat &prev_audio_format); - }; - - std::list children; - -public: - void Append(std::string_view name, - std::unique_ptr filter) noexcept { - children.emplace_back(name, std::move(filter)); - } - - /* virtual methods from class PreparedFilter */ - std::unique_ptr Open(AudioFormat &af) override; -}; - -std::unique_ptr -PreparedChainFilter::Child::Open(const AudioFormat &prev_audio_format) -{ - AudioFormat conv_audio_format = prev_audio_format; - auto new_filter = filter->Open(conv_audio_format); - - if (conv_audio_format != prev_audio_format) - throw FormatRuntimeError("Audio format not supported by filter '%s': %s", - name.c_str(), - ToString(prev_audio_format).c_str()); - - return new_filter; -} - -std::unique_ptr -PreparedChainFilter::Open(AudioFormat &in_audio_format) -{ - auto chain = std::make_unique(in_audio_format); - - for (auto &child : children) { - AudioFormat audio_format = chain->GetOutAudioFormat(); - chain->Append(child.Open(audio_format)); - } - - return chain; -} - -void -ChainFilter::Reset() noexcept -{ - RewindFlush(); - - for (auto &child : children) - child.filter->Reset(); -} - -template -static ConstBuffer -ApplyFilterChain(I begin, I end, ConstBuffer src) -{ - for (auto i = begin; i != end; ++i) - /* feed the output of the previous filter as input - into the current one */ - src = i->filter->FilterPCM(src); - - return src; -} - -ConstBuffer -ChainFilter::FilterPCM(ConstBuffer src) -{ - RewindFlush(); - - /* return the output of the last filter */ - return ApplyFilterChain(children.begin(), children.end(), src); -} - -ConstBuffer -ChainFilter::Flush() -{ - for (auto end = children.end(); flushing != end; ++flushing) { - auto data = flushing->filter->Flush(); - if (!data.IsNull()) - return ApplyFilterChain(std::next(flushing), end, - data); - } - - return nullptr; -} - -std::unique_ptr -filter_chain_new() noexcept -{ - return std::make_unique(); -} - -void -filter_chain_append(PreparedFilter &_chain, std::string_view name, - std::unique_ptr filter) noexcept -{ - auto &chain = (PreparedChainFilter &)_chain; - - chain.Append(name, std::move(filter)); -} diff --git a/src/filter/plugins/ChainFilterPlugin.hxx b/src/filter/plugins/ChainFilterPlugin.hxx deleted file mode 100644 index 75ff342de..000000000 --- a/src/filter/plugins/ChainFilterPlugin.hxx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2003-2021 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/** \file - * - * A filter chain is a container for several filters. They are - * chained together, i.e. called in a row, one filter passing its - * output to the next one. - */ - -#ifndef MPD_FILTER_CHAIN_HXX -#define MPD_FILTER_CHAIN_HXX - -#include -#include - -class PreparedFilter; - -/** - * Creates a new filter chain. - */ -std::unique_ptr -filter_chain_new() noexcept; - -/** - * Appends a new filter at the end of the filter chain. You must call - * this function before the first filter_open() call. - * - * @param chain the filter chain created with filter_chain_new() - * @param filter the filter to be appended to #chain - */ -void -filter_chain_append(PreparedFilter &chain, std::string_view name, - std::unique_ptr filter) noexcept; - -#endif diff --git a/src/filter/plugins/meson.build b/src/filter/plugins/meson.build index 187dcfcc2..aa5dd8038 100644 --- a/src/filter/plugins/meson.build +++ b/src/filter/plugins/meson.build @@ -15,7 +15,6 @@ filter_plugins = static_library( '../../AudioCompress/compress.c', 'NullFilterPlugin.cxx', 'TwoFilters.cxx', - 'ChainFilterPlugin.cxx', 'AutoConvertFilterPlugin.cxx', 'ConvertFilterPlugin.cxx', 'RouteFilterPlugin.cxx', diff --git a/src/output/Filtered.hxx b/src/output/Filtered.hxx index 29e40f006..4482fddb0 100644 --- a/src/output/Filtered.hxx +++ b/src/output/Filtered.hxx @@ -90,8 +90,8 @@ public: AudioFormat out_audio_format; /** - * The filter object of this audio output. This is an - * instance of chain_filter_plugin. + * The filter object of this audio output. This is a chain of + * #PreparedTwoFilter instances. */ std::unique_ptr prepared_filter; diff --git a/src/output/Init.cxx b/src/output/Init.cxx index c07e9d6e9..c561c5705 100644 --- a/src/output/Init.cxx +++ b/src/output/Init.cxx @@ -32,7 +32,7 @@ #include "filter/plugins/AutoConvertFilterPlugin.hxx" #include "filter/plugins/ConvertFilterPlugin.hxx" #include "filter/plugins/ReplayGainFilterPlugin.hxx" -#include "filter/plugins/ChainFilterPlugin.hxx" +#include "filter/plugins/TwoFilters.hxx" #include "filter/plugins/VolumeFilterPlugin.hxx" #include "filter/plugins/NormalizeFilterPlugin.hxx" #include "util/RuntimeError.hxx" @@ -109,7 +109,7 @@ audio_output_load_mixer(EventLoop &event_loop, FilteredAudioOutput &ao, const ConfigBlock &block, const MixerType mixer_type, const MixerPlugin *plugin, - PreparedFilter &filter_chain, + std::unique_ptr &filter_chain, MixerListener &listener) { Mixer *mixer; @@ -137,8 +137,9 @@ audio_output_load_mixer(EventLoop &event_loop, FilteredAudioOutput &ao, ConfigBlock()); assert(mixer != nullptr); - filter_chain_append(filter_chain, "software_mixer", - ao.volume_filter.Set(volume_filter_prepare())); + filter_chain = ChainFilters(std::move(filter_chain), + ao.volume_filter.Set(volume_filter_prepare()), + "software_mixer"); return mixer; } @@ -169,21 +170,17 @@ FilteredAudioOutput::Configure(const ConfigBlock &block, log_name = StringFormat<256>("\"%s\" (%s)", name, plugin_name); - /* set up the filter chain */ - - prepared_filter = filter_chain_new(); - assert(prepared_filter != nullptr); - /* create the normalization filter (if configured) */ if (defaults.normalize) { - filter_chain_append(*prepared_filter, "normalize", - autoconvert_filter_new(normalize_filter_prepare())); + prepared_filter = ChainFilters(std::move(prepared_filter), + autoconvert_filter_new(normalize_filter_prepare()), + "normalize"); } try { if (filter_factory != nullptr) - filter_chain_parse(*prepared_filter, *filter_factory, + filter_chain_parse(prepared_filter, *filter_factory, block.GetBlockValue(AUDIO_FILTERS, "")); } catch (...) { /* It's not really fatal - Part of the filter chain @@ -236,7 +233,7 @@ FilteredAudioOutput::Setup(EventLoop &event_loop, mixer = audio_output_load_mixer(event_loop, *this, block, mixer_type, mixer_plugin, - *prepared_filter, + prepared_filter, mixer_listener); } catch (...) { FmtError(output_domain, @@ -260,8 +257,9 @@ FilteredAudioOutput::Setup(EventLoop &event_loop, /* the "convert" filter must be the last one in the chain */ - filter_chain_append(*prepared_filter, "convert", - convert_filter.Set(convert_filter_prepare())); + prepared_filter = ChainFilters(std::move(prepared_filter), + convert_filter.Set(convert_filter_prepare()), + "convert"); } std::unique_ptr