From 7c52a1c04bccac68f4220c8bf3d3a59c16ed58db Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 24 Jan 2014 16:31:52 +0100 Subject: Filter*: move to filter/ --- Makefile.am | 44 ++-- src/FilterConfig.cxx | 108 --------- src/FilterConfig.hxx | 43 ---- src/FilterInternal.hxx | 74 ------- src/FilterPlugin.cxx | 58 ----- src/FilterPlugin.hxx | 67 ------ src/FilterRegistry.cxx | 43 ---- src/FilterRegistry.hxx | 43 ---- src/filter/AutoConvertFilterPlugin.cxx | 131 ----------- src/filter/AutoConvertFilterPlugin.hxx | 34 --- src/filter/ChainFilterPlugin.cxx | 181 --------------- src/filter/ChainFilterPlugin.hxx | 48 ---- src/filter/ConvertFilterPlugin.cxx | 149 ------------- src/filter/ConvertFilterPlugin.hxx | 37 ---- src/filter/FilterConfig.cxx | 108 +++++++++ src/filter/FilterConfig.hxx | 43 ++++ src/filter/FilterInternal.hxx | 74 +++++++ src/filter/FilterPlugin.cxx | 58 +++++ src/filter/FilterPlugin.hxx | 67 ++++++ src/filter/FilterRegistry.cxx | 43 ++++ src/filter/FilterRegistry.hxx | 43 ++++ src/filter/NormalizeFilterPlugin.cxx | 82 ------- src/filter/NullFilterPlugin.cxx | 61 ----- src/filter/ReplayGainFilterPlugin.cxx | 210 ------------------ src/filter/ReplayGainFilterPlugin.hxx | 52 ----- src/filter/RouteFilterPlugin.cxx | 296 ------------------------- src/filter/VolumeFilterPlugin.cxx | 106 --------- src/filter/VolumeFilterPlugin.hxx | 31 --- src/filter/plugins/AutoConvertFilterPlugin.cxx | 131 +++++++++++ src/filter/plugins/AutoConvertFilterPlugin.hxx | 34 +++ src/filter/plugins/ChainFilterPlugin.cxx | 181 +++++++++++++++ src/filter/plugins/ChainFilterPlugin.hxx | 48 ++++ src/filter/plugins/ConvertFilterPlugin.cxx | 149 +++++++++++++ src/filter/plugins/ConvertFilterPlugin.hxx | 37 ++++ src/filter/plugins/NormalizeFilterPlugin.cxx | 82 +++++++ src/filter/plugins/NullFilterPlugin.cxx | 61 +++++ src/filter/plugins/ReplayGainFilterPlugin.cxx | 210 ++++++++++++++++++ src/filter/plugins/ReplayGainFilterPlugin.hxx | 52 +++++ src/filter/plugins/RouteFilterPlugin.cxx | 296 +++++++++++++++++++++++++ src/filter/plugins/VolumeFilterPlugin.cxx | 106 +++++++++ src/filter/plugins/VolumeFilterPlugin.hxx | 31 +++ src/mixer/SoftwareMixerPlugin.cxx | 8 +- src/output/OutputControl.cxx | 2 +- src/output/OutputFinish.cxx | 2 +- src/output/OutputInit.cxx | 12 +- src/output/OutputThread.cxx | 6 +- test/read_mixer.cxx | 2 +- test/run_filter.cxx | 6 +- test/run_output.cxx | 2 +- 49 files changed, 1896 insertions(+), 1896 deletions(-) delete mode 100644 src/FilterConfig.cxx delete mode 100644 src/FilterConfig.hxx delete mode 100644 src/FilterInternal.hxx delete mode 100644 src/FilterPlugin.cxx delete mode 100644 src/FilterPlugin.hxx delete mode 100644 src/FilterRegistry.cxx delete mode 100644 src/FilterRegistry.hxx delete mode 100644 src/filter/AutoConvertFilterPlugin.cxx delete mode 100644 src/filter/AutoConvertFilterPlugin.hxx delete mode 100644 src/filter/ChainFilterPlugin.cxx delete mode 100644 src/filter/ChainFilterPlugin.hxx delete mode 100644 src/filter/ConvertFilterPlugin.cxx delete mode 100644 src/filter/ConvertFilterPlugin.hxx create mode 100644 src/filter/FilterConfig.cxx create mode 100644 src/filter/FilterConfig.hxx create mode 100644 src/filter/FilterInternal.hxx create mode 100644 src/filter/FilterPlugin.cxx create mode 100644 src/filter/FilterPlugin.hxx create mode 100644 src/filter/FilterRegistry.cxx create mode 100644 src/filter/FilterRegistry.hxx delete mode 100644 src/filter/NormalizeFilterPlugin.cxx delete mode 100644 src/filter/NullFilterPlugin.cxx delete mode 100644 src/filter/ReplayGainFilterPlugin.cxx delete mode 100644 src/filter/ReplayGainFilterPlugin.hxx delete mode 100644 src/filter/RouteFilterPlugin.cxx delete mode 100644 src/filter/VolumeFilterPlugin.cxx delete mode 100644 src/filter/VolumeFilterPlugin.hxx create mode 100644 src/filter/plugins/AutoConvertFilterPlugin.cxx create mode 100644 src/filter/plugins/AutoConvertFilterPlugin.hxx create mode 100644 src/filter/plugins/ChainFilterPlugin.cxx create mode 100644 src/filter/plugins/ChainFilterPlugin.hxx create mode 100644 src/filter/plugins/ConvertFilterPlugin.cxx create mode 100644 src/filter/plugins/ConvertFilterPlugin.hxx create mode 100644 src/filter/plugins/NormalizeFilterPlugin.cxx create mode 100644 src/filter/plugins/NullFilterPlugin.cxx create mode 100644 src/filter/plugins/ReplayGainFilterPlugin.cxx create mode 100644 src/filter/plugins/ReplayGainFilterPlugin.hxx create mode 100644 src/filter/plugins/RouteFilterPlugin.cxx create mode 100644 src/filter/plugins/VolumeFilterPlugin.cxx create mode 100644 src/filter/plugins/VolumeFilterPlugin.hxx diff --git a/Makefile.am b/Makefile.am index fe069ac79..e909bc111 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,10 +118,10 @@ src_mpd_SOURCES = \ src/db/Visitor.hxx \ src/db/Selection.cxx src/db/Selection.hxx \ src/ExcludeList.cxx src/ExcludeList.hxx \ - src/FilterConfig.cxx src/FilterConfig.hxx \ - src/FilterPlugin.cxx src/FilterPlugin.hxx \ - src/FilterInternal.hxx \ - src/FilterRegistry.cxx src/FilterRegistry.hxx \ + src/filter/FilterConfig.cxx src/filter/FilterConfig.hxx \ + src/filter/FilterPlugin.cxx src/filter/FilterPlugin.hxx \ + src/filter/FilterInternal.hxx \ + src/filter/FilterRegistry.cxx src/filter/FilterRegistry.hxx \ src/db/update/UpdateDomain.cxx src/db/update/UpdateDomain.hxx \ src/db/update/UpdateGlue.cxx src/db/update/UpdateGlue.hxx \ src/db/update/UpdateQueue.cxx src/db/update/UpdateQueue.hxx \ @@ -1112,19 +1112,19 @@ endif # libfilter_plugins_a_SOURCES = \ - src/filter/NullFilterPlugin.cxx \ - src/filter/ChainFilterPlugin.cxx \ - src/filter/ChainFilterPlugin.hxx \ - src/filter/AutoConvertFilterPlugin.cxx \ - src/filter/AutoConvertFilterPlugin.hxx \ - src/filter/ConvertFilterPlugin.cxx \ - src/filter/ConvertFilterPlugin.hxx \ - src/filter/RouteFilterPlugin.cxx \ - src/filter/NormalizeFilterPlugin.cxx \ - src/filter/ReplayGainFilterPlugin.cxx \ - src/filter/ReplayGainFilterPlugin.hxx \ - src/filter/VolumeFilterPlugin.cxx \ - src/filter/VolumeFilterPlugin.hxx + src/filter/plugins/NullFilterPlugin.cxx \ + src/filter/plugins/ChainFilterPlugin.cxx \ + src/filter/plugins/ChainFilterPlugin.hxx \ + src/filter/plugins/AutoConvertFilterPlugin.cxx \ + src/filter/plugins/AutoConvertFilterPlugin.hxx \ + src/filter/plugins/ConvertFilterPlugin.cxx \ + src/filter/plugins/ConvertFilterPlugin.hxx \ + src/filter/plugins/RouteFilterPlugin.cxx \ + src/filter/plugins/NormalizeFilterPlugin.cxx \ + src/filter/plugins/ReplayGainFilterPlugin.cxx \ + src/filter/plugins/ReplayGainFilterPlugin.hxx \ + src/filter/plugins/VolumeFilterPlugin.cxx \ + src/filter/plugins/VolumeFilterPlugin.hxx FILTER_LIBS = \ libfilter_plugins.a \ @@ -1414,7 +1414,7 @@ test_run_filter_SOURCES = test/run_filter.cxx \ test/FakeReplayGainConfig.cxx \ test/stdbin.h \ src/Log.cxx src/LogBackend.cxx \ - src/FilterPlugin.cxx src/FilterRegistry.cxx \ + src/filter/FilterPlugin.cxx src/filter/FilterRegistry.cxx \ src/CheckAudioFormat.cxx \ src/AudioFormat.cxx \ src/AudioParser.cxx \ @@ -1542,8 +1542,8 @@ test_run_output_SOURCES = test/run_output.cxx \ src/output/OutputPlugin.cxx \ src/MixerControl.cxx \ src/MixerType.cxx \ - src/FilterPlugin.cxx \ - src/FilterConfig.cxx \ + src/filter/FilterPlugin.cxx \ + src/filter/FilterConfig.cxx \ src/AudioCompress/compress.c \ src/ReplayGainInfo.cxx @@ -1560,9 +1560,9 @@ test_read_mixer_LDADD = \ test_read_mixer_SOURCES = test/read_mixer.cxx \ src/Log.cxx src/LogBackend.cxx \ src/MixerControl.cxx \ - src/FilterPlugin.cxx \ + src/filter/FilterPlugin.cxx \ src/AudioFormat.cxx \ - src/filter/VolumeFilterPlugin.cxx + src/filter/plugins/VolumeFilterPlugin.cxx if ENABLE_BZIP2_TEST TESTS += test/test_archive_bzip2.sh diff --git a/src/FilterConfig.cxx b/src/FilterConfig.cxx deleted file mode 100644 index a3a8f7ddc..000000000 --- a/src/FilterConfig.cxx +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "FilterConfig.hxx" -#include "filter/ChainFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "config/ConfigData.hxx" -#include "config/ConfigOption.hxx" -#include "config/ConfigGlobal.hxx" -#include "config/ConfigError.hxx" -#include "util/Error.hxx" - -#include - -#include - -/** - * Find the "filter" configuration block for the specified name. - * - * @param filter_template_name the name of the filter template - * @param error space to return an error description - * @return the configuration block, or nullptr if none was configured - */ -static const struct config_param * -filter_plugin_config(const char *filter_template_name, Error &error) -{ - const struct config_param *param = nullptr; - - while ((param = config_get_next_param(CONF_AUDIO_FILTER, param)) != nullptr) { - const char *name = param->GetBlockValue("name"); - if (name == nullptr) { - error.Format(config_domain, - "filter configuration without 'name' name in line %d", - param->line); - return nullptr; - } - - if (strcmp(name, filter_template_name) == 0) - return param; - } - - error.Format(config_domain, - "filter template not found: %s", - filter_template_name); - return nullptr; -} - -static bool -filter_chain_append_new(Filter &chain, const char *template_name, Error &error) -{ - const struct config_param *cfg = - filter_plugin_config(template_name, error); - if (cfg == nullptr) - // The error has already been set, just stop. - return false; - - // Instantiate one of those filter plugins with the template name as a hint - Filter *f = filter_configured_new(*cfg, error); - if (f == nullptr) - // The error has already been set, just stop. - return false; - - const char *plugin_name = cfg->GetBlockValue("plugin", - "unknown"); - filter_chain_append(chain, plugin_name, f); - - return true; -} - -bool -filter_chain_parse(Filter &chain, const char *spec, Error &error) -{ - const char *const end = spec + strlen(spec); - - while (true) { - const char *comma = std::find(spec, end, ','); - if (comma > spec) { - const std::string name(spec, comma); - if (!filter_chain_append_new(chain, name.c_str(), - error)) - return false; - } - - if (comma == end) - break; - - spec = comma + 1; - } - - return true; -} diff --git a/src/FilterConfig.hxx b/src/FilterConfig.hxx deleted file mode 100644 index 1018eed51..000000000 --- a/src/FilterConfig.hxx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 - * 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 - * - * Utility functions for filter configuration - */ - -#ifndef MPD_FILTER_CONFIG_HXX -#define MPD_FILTER_CONFIG_HXX - -class Filter; -class Error; - -/** - * Builds a filter chain from a configuration string on the form - * "name1, name2, name3, ..." by looking up each name among the - * configured filter sections. - * @param chain the chain to append filters on - * @param spec the filter chain specification - * @param error_r space to return an error description - * @return true on success - */ -bool -filter_chain_parse(Filter &chain, const char *spec, Error &error); - -#endif diff --git a/src/FilterInternal.hxx b/src/FilterInternal.hxx deleted file mode 100644 index 131c3b3f5..000000000 --- a/src/FilterInternal.hxx +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 - * 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 - * - * Internal stuff for the filter core and filter plugins. - */ - -#ifndef MPD_FILTER_INTERNAL_HXX -#define MPD_FILTER_INTERNAL_HXX - -#include - -struct AudioFormat; -class Error; - -class Filter { -public: - virtual ~Filter() {} - - /** - * Opens the filter, preparing it for FilterPCM(). - * - * @param filter the filter object - * @param audio_format the audio format of incoming data; the - * plugin may modify the object to enforce another input - * format - * @param error location to store the error occurring, or nullptr - * to ignore errors. - * @return the format of outgoing data or - * AudioFormat::Undefined() on error - */ - virtual AudioFormat Open(AudioFormat &af, Error &error) = 0; - - /** - * Closes the filter. After that, you may call Open() again. - */ - virtual void Close() = 0; - - /** - * Filters a block of PCM data. - * - * @param filter the filter object - * @param src the input buffer - * @param src_size the size of #src_buffer in bytes - * @param dest_size_r the size of the returned buffer - * @param error location to store the error occurring, or nullptr - * to ignore errors. - * @return the destination buffer on success (will be - * invalidated by filter_close() or filter_filter()), nullptr on - * error - */ - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, - Error &error) = 0; -}; - -#endif diff --git a/src/FilterPlugin.cxx b/src/FilterPlugin.cxx deleted file mode 100644 index 98314f771..000000000 --- a/src/FilterPlugin.cxx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "FilterPlugin.hxx" -#include "FilterRegistry.hxx" -#include "config/ConfigData.hxx" -#include "config/ConfigError.hxx" -#include "util/Error.hxx" - -#include - -Filter * -filter_new(const struct filter_plugin *plugin, - const config_param ¶m, Error &error) -{ - assert(plugin != nullptr); - assert(!error.IsDefined()); - - return plugin->init(param, error); -} - -Filter * -filter_configured_new(const config_param ¶m, Error &error) -{ - assert(!error.IsDefined()); - - const char *plugin_name = param.GetBlockValue("plugin"); - if (plugin_name == nullptr) { - error.Set(config_domain, "No filter plugin specified"); - return nullptr; - } - - const filter_plugin *plugin = filter_plugin_by_name(plugin_name); - if (plugin == nullptr) { - error.Format(config_domain, - "No such filter plugin: %s", plugin_name); - return nullptr; - } - - return filter_new(plugin, param, error); -} diff --git a/src/FilterPlugin.hxx b/src/FilterPlugin.hxx deleted file mode 100644 index 443d29881..000000000 --- a/src/FilterPlugin.hxx +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 - * 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 - * - * This header declares the filter_plugin class. It describes a - * plugin API for objects which filter raw PCM data. - */ - -#ifndef MPD_FILTER_PLUGIN_HXX -#define MPD_FILTER_PLUGIN_HXX - -struct config_param; -class Filter; -class Error; - -struct filter_plugin { - const char *name; - - /** - * Allocates and configures a filter. - */ - Filter *(*init)(const config_param ¶m, Error &error); -}; - -/** - * Creates a new instance of the specified filter plugin. - * - * @param plugin the filter plugin - * @param param optional configuration section - * @param error location to store the error occurring, or nullptr to - * ignore errors. - * @return a new filter object, or nullptr on error - */ -Filter * -filter_new(const struct filter_plugin *plugin, - const config_param ¶m, Error &error); - -/** - * Creates a new filter, loads configuration and the plugin name from - * the specified configuration section. - * - * @param param the configuration section - * @param error location to store the error occurring, or nullptr to - * ignore errors. - * @return a new filter object, or nullptr on error - */ -Filter * -filter_configured_new(const config_param ¶m, Error &error); - -#endif diff --git a/src/FilterRegistry.cxx b/src/FilterRegistry.cxx deleted file mode 100644 index 286fb8db3..000000000 --- a/src/FilterRegistry.cxx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "FilterRegistry.hxx" -#include "FilterPlugin.hxx" - -#include - -const struct filter_plugin *const filter_plugins[] = { - &null_filter_plugin, - &route_filter_plugin, - &normalize_filter_plugin, - &volume_filter_plugin, - &replay_gain_filter_plugin, - nullptr, -}; - -const struct filter_plugin * -filter_plugin_by_name(const char *name) -{ - for (unsigned i = 0; filter_plugins[i] != nullptr; ++i) - if (strcmp(filter_plugins[i]->name, name) == 0) - return filter_plugins[i]; - - return nullptr; -} diff --git a/src/FilterRegistry.hxx b/src/FilterRegistry.hxx deleted file mode 100644 index 24618a87a..000000000 --- a/src/FilterRegistry.hxx +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 - * 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 - * - * This library manages all filter plugins which are enabled at - * compile time. - */ - -#ifndef MPD_FILTER_REGISTRY_HXX -#define MPD_FILTER_REGISTRY_HXX - -#include "Compiler.h" - -extern const struct filter_plugin null_filter_plugin; -extern const struct filter_plugin chain_filter_plugin; -extern const struct filter_plugin convert_filter_plugin; -extern const struct filter_plugin route_filter_plugin; -extern const struct filter_plugin normalize_filter_plugin; -extern const struct filter_plugin volume_filter_plugin; -extern const struct filter_plugin replay_gain_filter_plugin; - -gcc_pure -const struct filter_plugin * -filter_plugin_by_name(const char *name); - -#endif diff --git a/src/filter/AutoConvertFilterPlugin.cxx b/src/filter/AutoConvertFilterPlugin.cxx deleted file mode 100644 index b9bc12f31..000000000 --- a/src/filter/AutoConvertFilterPlugin.cxx +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "AutoConvertFilterPlugin.hxx" -#include "ConvertFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "AudioFormat.hxx" -#include "config/ConfigData.hxx" - -#include - -class AutoConvertFilter final : public Filter { - /** - * The underlying filter. - */ - Filter *filter; - - /** - * A convert_filter, just in case conversion is needed. nullptr - * if unused. - */ - Filter *convert; - -public: - AutoConvertFilter(Filter *_filter):filter(_filter) {} - ~AutoConvertFilter() { - delete filter; - } - - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close() override; - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, - Error &error) override; -}; - -AudioFormat -AutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error) -{ - assert(in_audio_format.IsValid()); - - /* open the "real" filter */ - - AudioFormat child_audio_format = in_audio_format; - AudioFormat out_audio_format = filter->Open(child_audio_format, error); - if (!out_audio_format.IsDefined()) - return out_audio_format; - - /* need to convert? */ - - if (in_audio_format != child_audio_format) { - /* yes - create a convert_filter */ - - const config_param empty; - convert = filter_new(&convert_filter_plugin, empty, error); - if (convert == nullptr) { - filter->Close(); - return AudioFormat::Undefined(); - } - - AudioFormat audio_format2 = in_audio_format; - AudioFormat audio_format3 = - convert->Open(audio_format2, error); - if (!audio_format3.IsDefined()) { - delete convert; - filter->Close(); - return AudioFormat::Undefined(); - } - - assert(audio_format2 == in_audio_format); - - if (!convert_filter_set(convert, child_audio_format, error)) { - delete convert; - filter->Close(); - return AudioFormat::Undefined(); - } - } else - /* no */ - convert = nullptr; - - return out_audio_format; -} - -void -AutoConvertFilter::Close() -{ - if (convert != nullptr) { - convert->Close(); - delete convert; - } - - filter->Close(); -} - -const void * -AutoConvertFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error) -{ - if (convert != nullptr) { - src = convert->FilterPCM(src, src_size, &src_size, error); - if (src == nullptr) - return nullptr; - } - - return filter->FilterPCM(src, src_size, dest_size_r, error); -} - -Filter * -autoconvert_filter_new(Filter *filter) -{ - return new AutoConvertFilter(filter); -} diff --git a/src/filter/AutoConvertFilterPlugin.hxx b/src/filter/AutoConvertFilterPlugin.hxx deleted file mode 100644 index c5dfdd2f6..000000000 --- a/src/filter/AutoConvertFilterPlugin.hxx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 - * 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. - */ - -#ifndef MPD_AUTOCONVERT_FILTER_PLUGIN_HXX -#define MPD_AUTOCONVERT_FILTER_PLUGIN_HXX - -class Filter; - -/** - * Creates a new "autoconvert" filter. When opened, it ensures that - * the input audio format isn't changed. If the underlying filter - * requests a different format, it automatically creates a - * convert_filter. - */ -Filter * -autoconvert_filter_new(Filter *filter); - -#endif diff --git a/src/filter/ChainFilterPlugin.cxx b/src/filter/ChainFilterPlugin.cxx deleted file mode 100644 index 528661163..000000000 --- a/src/filter/ChainFilterPlugin.cxx +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "ChainFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "AudioFormat.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" - -#include - -#include - -class ChainFilter final : public Filter { - struct Child { - const char *name; - Filter *filter; - - Child(const char *_name, Filter *_filter) - :name(_name), filter(_filter) {} - ~Child() { - delete filter; - } - - Child(const Child &) = delete; - Child &operator=(const Child &) = delete; - }; - - std::list children; - -public: - void Append(const char *name, Filter *filter) { - children.emplace_back(name, filter); - } - - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close(); - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error); - -private: - /** - * Close all filters in the chain until #until is reached. - * #until itself is not closed. - */ - void CloseUntil(const Filter *until); -}; - -static constexpr Domain chain_filter_domain("chain_filter"); - -static Filter * -chain_filter_init(gcc_unused const config_param ¶m, - gcc_unused Error &error) -{ - return new ChainFilter(); -} - -void -ChainFilter::CloseUntil(const Filter *until) -{ - for (auto &child : children) { - if (child.filter == until) - /* don't close this filter */ - return; - - /* close this filter */ - child.filter->Close(); - } - - /* this assertion fails if #until does not exist (anymore) */ - assert(false); - gcc_unreachable(); -} - -static AudioFormat -chain_open_child(const char *name, Filter *filter, - const AudioFormat &prev_audio_format, - Error &error) -{ - AudioFormat conv_audio_format = prev_audio_format; - const AudioFormat next_audio_format = - filter->Open(conv_audio_format, error); - if (!next_audio_format.IsDefined()) - return next_audio_format; - - if (conv_audio_format != prev_audio_format) { - struct audio_format_string s; - - filter->Close(); - - error.Format(chain_filter_domain, - "Audio format not supported by filter '%s': %s", - name, - audio_format_to_string(prev_audio_format, &s)); - return AudioFormat::Undefined(); - } - - return next_audio_format; -} - -AudioFormat -ChainFilter::Open(AudioFormat &in_audio_format, Error &error) -{ - AudioFormat audio_format = in_audio_format; - - for (auto &child : children) { - audio_format = chain_open_child(child.name, child.filter, - audio_format, error); - if (!audio_format.IsDefined()) { - /* rollback, close all children */ - CloseUntil(child.filter); - break; - } - } - - /* return the output format of the last filter */ - return audio_format; -} - -void -ChainFilter::Close() -{ - for (auto &child : children) - child.filter->Close(); -} - -const void * -ChainFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error) -{ - for (auto &child : children) { - /* feed the output of the previous filter as input - into the current one */ - src = child.filter->FilterPCM(src, src_size, &src_size, - error); - if (src == nullptr) - return nullptr; - } - - /* return the output of the last filter */ - *dest_size_r = src_size; - return src; -} - -const struct filter_plugin chain_filter_plugin = { - "chain", - chain_filter_init, -}; - -Filter * -filter_chain_new(void) -{ - return new ChainFilter(); -} - -void -filter_chain_append(Filter &_chain, const char *name, Filter *filter) -{ - ChainFilter &chain = (ChainFilter &)_chain; - - chain.Append(name, filter); -} diff --git a/src/filter/ChainFilterPlugin.hxx b/src/filter/ChainFilterPlugin.hxx deleted file mode 100644 index b36aa3322..000000000 --- a/src/filter/ChainFilterPlugin.hxx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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 - * 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 - -class Filter; - -/** - * Creates a new filter chain. - */ -Filter * -filter_chain_new(void); - -/** - * 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(Filter &chain, const char *name, Filter *filter); - -#endif diff --git a/src/filter/ConvertFilterPlugin.cxx b/src/filter/ConvertFilterPlugin.cxx deleted file mode 100644 index 2004fe303..000000000 --- a/src/filter/ConvertFilterPlugin.cxx +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "ConvertFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "pcm/PcmConvert.hxx" -#include "util/Manual.hxx" -#include "AudioFormat.hxx" -#include "poison.h" - -#include - -class ConvertFilter final : public Filter { - /** - * The input audio format; PCM data is passed to the filter() - * method in this format. - */ - AudioFormat in_audio_format; - - /** - * The output audio format; the consumer of this plugin - * expects PCM data in this format. - * - * If this is AudioFormat::Undefined(), then the #PcmConvert - * attribute is not open. This can mean that Set() has failed - * or that no conversion is necessary. - */ - AudioFormat out_audio_format; - - Manual state; - -public: - bool Set(const AudioFormat &_out_audio_format, Error &error); - - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close() override; - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, - Error &error) override; -}; - -static Filter * -convert_filter_init(gcc_unused const config_param ¶m, - gcc_unused Error &error) -{ - return new ConvertFilter(); -} - -bool -ConvertFilter::Set(const AudioFormat &_out_audio_format, Error &error) -{ - assert(in_audio_format.IsValid()); - assert(_out_audio_format.IsValid()); - - if (_out_audio_format == out_audio_format) - /* no change */ - return true; - - if (out_audio_format.IsValid()) { - out_audio_format.Clear(); - state->Close(); - } - - if (_out_audio_format == in_audio_format) - /* optimized special case: no-op */ - return true; - - if (!state->Open(in_audio_format, _out_audio_format, error)) - return false; - - out_audio_format = _out_audio_format; - return true; -} - -AudioFormat -ConvertFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) -{ - assert(audio_format.IsValid()); - - in_audio_format = audio_format; - out_audio_format.Clear(); - - state.Construct(); - - return in_audio_format; -} - -void -ConvertFilter::Close() -{ - assert(in_audio_format.IsValid()); - - if (out_audio_format.IsValid()) - state->Close(); - - state.Destruct(); - - poison_undefined(&in_audio_format, sizeof(in_audio_format)); - poison_undefined(&out_audio_format, sizeof(out_audio_format)); -} - -const void * -ConvertFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error) -{ - assert(in_audio_format.IsValid()); - - if (!out_audio_format.IsValid()) { - /* optimized special case: no-op */ - *dest_size_r = src_size; - return src; - } - - return state->Convert(src, src_size, dest_size_r, - error); -} - -const struct filter_plugin convert_filter_plugin = { - "convert", - convert_filter_init, -}; - -bool -convert_filter_set(Filter *_filter, AudioFormat out_audio_format, - Error &error) -{ - ConvertFilter *filter = (ConvertFilter *)_filter; - - return filter->Set(out_audio_format, error); -} diff --git a/src/filter/ConvertFilterPlugin.hxx b/src/filter/ConvertFilterPlugin.hxx deleted file mode 100644 index bb4673651..000000000 --- a/src/filter/ConvertFilterPlugin.hxx +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 - * 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. - */ - -#ifndef MPD_CONVERT_FILTER_PLUGIN_HXX -#define MPD_CONVERT_FILTER_PLUGIN_HXX - -class Filter; -class Error; -struct AudioFormat; - -/** - * Sets the output audio format for the specified filter. You must - * call this after the filter has been opened. Since this audio - * format switch is a violation of the filter API, this filter must be - * the last in a chain. - */ -bool -convert_filter_set(Filter *filter, AudioFormat out_audio_format, - Error &error); - -#endif diff --git a/src/filter/FilterConfig.cxx b/src/filter/FilterConfig.cxx new file mode 100644 index 000000000..5f2c3a95b --- /dev/null +++ b/src/filter/FilterConfig.cxx @@ -0,0 +1,108 @@ +/* + * 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 + * 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 "config.h" +#include "FilterConfig.hxx" +#include "plugins/ChainFilterPlugin.hxx" +#include "FilterPlugin.hxx" +#include "config/ConfigData.hxx" +#include "config/ConfigOption.hxx" +#include "config/ConfigGlobal.hxx" +#include "config/ConfigError.hxx" +#include "util/Error.hxx" + +#include + +#include + +/** + * Find the "filter" configuration block for the specified name. + * + * @param filter_template_name the name of the filter template + * @param error space to return an error description + * @return the configuration block, or nullptr if none was configured + */ +static const struct config_param * +filter_plugin_config(const char *filter_template_name, Error &error) +{ + const struct config_param *param = nullptr; + + while ((param = config_get_next_param(CONF_AUDIO_FILTER, param)) != nullptr) { + const char *name = param->GetBlockValue("name"); + if (name == nullptr) { + error.Format(config_domain, + "filter configuration without 'name' name in line %d", + param->line); + return nullptr; + } + + if (strcmp(name, filter_template_name) == 0) + return param; + } + + error.Format(config_domain, + "filter template not found: %s", + filter_template_name); + return nullptr; +} + +static bool +filter_chain_append_new(Filter &chain, const char *template_name, Error &error) +{ + const struct config_param *cfg = + filter_plugin_config(template_name, error); + if (cfg == nullptr) + // The error has already been set, just stop. + return false; + + // Instantiate one of those filter plugins with the template name as a hint + Filter *f = filter_configured_new(*cfg, error); + if (f == nullptr) + // The error has already been set, just stop. + return false; + + const char *plugin_name = cfg->GetBlockValue("plugin", + "unknown"); + filter_chain_append(chain, plugin_name, f); + + return true; +} + +bool +filter_chain_parse(Filter &chain, const char *spec, Error &error) +{ + const char *const end = spec + strlen(spec); + + while (true) { + const char *comma = std::find(spec, end, ','); + if (comma > spec) { + const std::string name(spec, comma); + if (!filter_chain_append_new(chain, name.c_str(), + error)) + return false; + } + + if (comma == end) + break; + + spec = comma + 1; + } + + return true; +} diff --git a/src/filter/FilterConfig.hxx b/src/filter/FilterConfig.hxx new file mode 100644 index 000000000..1018eed51 --- /dev/null +++ b/src/filter/FilterConfig.hxx @@ -0,0 +1,43 @@ +/* + * 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 + * 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 + * + * Utility functions for filter configuration + */ + +#ifndef MPD_FILTER_CONFIG_HXX +#define MPD_FILTER_CONFIG_HXX + +class Filter; +class Error; + +/** + * Builds a filter chain from a configuration string on the form + * "name1, name2, name3, ..." by looking up each name among the + * configured filter sections. + * @param chain the chain to append filters on + * @param spec the filter chain specification + * @param error_r space to return an error description + * @return true on success + */ +bool +filter_chain_parse(Filter &chain, const char *spec, Error &error); + +#endif diff --git a/src/filter/FilterInternal.hxx b/src/filter/FilterInternal.hxx new file mode 100644 index 000000000..131c3b3f5 --- /dev/null +++ b/src/filter/FilterInternal.hxx @@ -0,0 +1,74 @@ +/* + * 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 + * 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 + * + * Internal stuff for the filter core and filter plugins. + */ + +#ifndef MPD_FILTER_INTERNAL_HXX +#define MPD_FILTER_INTERNAL_HXX + +#include + +struct AudioFormat; +class Error; + +class Filter { +public: + virtual ~Filter() {} + + /** + * Opens the filter, preparing it for FilterPCM(). + * + * @param filter the filter object + * @param audio_format the audio format of incoming data; the + * plugin may modify the object to enforce another input + * format + * @param error location to store the error occurring, or nullptr + * to ignore errors. + * @return the format of outgoing data or + * AudioFormat::Undefined() on error + */ + virtual AudioFormat Open(AudioFormat &af, Error &error) = 0; + + /** + * Closes the filter. After that, you may call Open() again. + */ + virtual void Close() = 0; + + /** + * Filters a block of PCM data. + * + * @param filter the filter object + * @param src the input buffer + * @param src_size the size of #src_buffer in bytes + * @param dest_size_r the size of the returned buffer + * @param error location to store the error occurring, or nullptr + * to ignore errors. + * @return the destination buffer on success (will be + * invalidated by filter_close() or filter_filter()), nullptr on + * error + */ + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, + Error &error) = 0; +}; + +#endif diff --git a/src/filter/FilterPlugin.cxx b/src/filter/FilterPlugin.cxx new file mode 100644 index 000000000..98314f771 --- /dev/null +++ b/src/filter/FilterPlugin.cxx @@ -0,0 +1,58 @@ +/* + * 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 + * 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 "config.h" +#include "FilterPlugin.hxx" +#include "FilterRegistry.hxx" +#include "config/ConfigData.hxx" +#include "config/ConfigError.hxx" +#include "util/Error.hxx" + +#include + +Filter * +filter_new(const struct filter_plugin *plugin, + const config_param ¶m, Error &error) +{ + assert(plugin != nullptr); + assert(!error.IsDefined()); + + return plugin->init(param, error); +} + +Filter * +filter_configured_new(const config_param ¶m, Error &error) +{ + assert(!error.IsDefined()); + + const char *plugin_name = param.GetBlockValue("plugin"); + if (plugin_name == nullptr) { + error.Set(config_domain, "No filter plugin specified"); + return nullptr; + } + + const filter_plugin *plugin = filter_plugin_by_name(plugin_name); + if (plugin == nullptr) { + error.Format(config_domain, + "No such filter plugin: %s", plugin_name); + return nullptr; + } + + return filter_new(plugin, param, error); +} diff --git a/src/filter/FilterPlugin.hxx b/src/filter/FilterPlugin.hxx new file mode 100644 index 000000000..443d29881 --- /dev/null +++ b/src/filter/FilterPlugin.hxx @@ -0,0 +1,67 @@ +/* + * 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 + * 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 + * + * This header declares the filter_plugin class. It describes a + * plugin API for objects which filter raw PCM data. + */ + +#ifndef MPD_FILTER_PLUGIN_HXX +#define MPD_FILTER_PLUGIN_HXX + +struct config_param; +class Filter; +class Error; + +struct filter_plugin { + const char *name; + + /** + * Allocates and configures a filter. + */ + Filter *(*init)(const config_param ¶m, Error &error); +}; + +/** + * Creates a new instance of the specified filter plugin. + * + * @param plugin the filter plugin + * @param param optional configuration section + * @param error location to store the error occurring, or nullptr to + * ignore errors. + * @return a new filter object, or nullptr on error + */ +Filter * +filter_new(const struct filter_plugin *plugin, + const config_param ¶m, Error &error); + +/** + * Creates a new filter, loads configuration and the plugin name from + * the specified configuration section. + * + * @param param the configuration section + * @param error location to store the error occurring, or nullptr to + * ignore errors. + * @return a new filter object, or nullptr on error + */ +Filter * +filter_configured_new(const config_param ¶m, Error &error); + +#endif diff --git a/src/filter/FilterRegistry.cxx b/src/filter/FilterRegistry.cxx new file mode 100644 index 000000000..286fb8db3 --- /dev/null +++ b/src/filter/FilterRegistry.cxx @@ -0,0 +1,43 @@ +/* + * 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 + * 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 "config.h" +#include "FilterRegistry.hxx" +#include "FilterPlugin.hxx" + +#include + +const struct filter_plugin *const filter_plugins[] = { + &null_filter_plugin, + &route_filter_plugin, + &normalize_filter_plugin, + &volume_filter_plugin, + &replay_gain_filter_plugin, + nullptr, +}; + +const struct filter_plugin * +filter_plugin_by_name(const char *name) +{ + for (unsigned i = 0; filter_plugins[i] != nullptr; ++i) + if (strcmp(filter_plugins[i]->name, name) == 0) + return filter_plugins[i]; + + return nullptr; +} diff --git a/src/filter/FilterRegistry.hxx b/src/filter/FilterRegistry.hxx new file mode 100644 index 000000000..24618a87a --- /dev/null +++ b/src/filter/FilterRegistry.hxx @@ -0,0 +1,43 @@ +/* + * 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 + * 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 + * + * This library manages all filter plugins which are enabled at + * compile time. + */ + +#ifndef MPD_FILTER_REGISTRY_HXX +#define MPD_FILTER_REGISTRY_HXX + +#include "Compiler.h" + +extern const struct filter_plugin null_filter_plugin; +extern const struct filter_plugin chain_filter_plugin; +extern const struct filter_plugin convert_filter_plugin; +extern const struct filter_plugin route_filter_plugin; +extern const struct filter_plugin normalize_filter_plugin; +extern const struct filter_plugin volume_filter_plugin; +extern const struct filter_plugin replay_gain_filter_plugin; + +gcc_pure +const struct filter_plugin * +filter_plugin_by_name(const char *name); + +#endif diff --git a/src/filter/NormalizeFilterPlugin.cxx b/src/filter/NormalizeFilterPlugin.cxx deleted file mode 100644 index fa3a18aec..000000000 --- a/src/filter/NormalizeFilterPlugin.cxx +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "pcm/PcmBuffer.hxx" -#include "AudioFormat.hxx" -#include "AudioCompress/compress.h" - -#include - -class NormalizeFilter final : public Filter { - struct Compressor *compressor; - - PcmBuffer buffer; - -public: - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close(); - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error); -}; - -static Filter * -normalize_filter_init(gcc_unused const config_param ¶m, - gcc_unused Error &error) -{ - return new NormalizeFilter(); -} - -AudioFormat -NormalizeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) -{ - audio_format.format = SampleFormat::S16; - - compressor = Compressor_new(0); - - return audio_format; -} - -void -NormalizeFilter::Close() -{ - buffer.Clear(); - Compressor_delete(compressor); -} - -const void * -NormalizeFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, gcc_unused Error &error) -{ - int16_t *dest = (int16_t *)buffer.Get(src_size); - memcpy(dest, src, src_size); - - Compressor_Process_int16(compressor, dest, src_size / 2); - - *dest_size_r = src_size; - return dest; -} - -const struct filter_plugin normalize_filter_plugin = { - "normalize", - normalize_filter_init, -}; diff --git a/src/filter/NullFilterPlugin.cxx b/src/filter/NullFilterPlugin.cxx deleted file mode 100644 index 971598920..000000000 --- a/src/filter/NullFilterPlugin.cxx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 - * 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 - * - * This filter plugin does nothing. That is not quite useful, except - * for testing the filter core, or as a template for new filter - * plugins. - */ - -#include "config.h" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "AudioFormat.hxx" -#include "Compiler.h" - -class NullFilter final : public Filter { -public: - virtual AudioFormat Open(AudioFormat &af, - gcc_unused Error &error) override { - return af; - } - - virtual void Close() override {} - - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, - gcc_unused Error &error) override { - *dest_size_r = src_size; - return src; - } -}; - -static Filter * -null_filter_init(gcc_unused const config_param ¶m, - gcc_unused Error &error) -{ - return new NullFilter(); -} - -const struct filter_plugin null_filter_plugin = { - "null", - null_filter_init, -}; diff --git a/src/filter/ReplayGainFilterPlugin.cxx b/src/filter/ReplayGainFilterPlugin.cxx deleted file mode 100644 index 0b96b1d6d..000000000 --- a/src/filter/ReplayGainFilterPlugin.cxx +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "ReplayGainFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "AudioFormat.hxx" -#include "ReplayGainInfo.hxx" -#include "ReplayGainConfig.hxx" -#include "MixerControl.hxx" -#include "pcm/Volume.hxx" -#include "pcm/PcmBuffer.hxx" -#include "util/ConstBuffer.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" -#include "Log.hxx" - -#include -#include - -static constexpr Domain replay_gain_domain("replay_gain"); - -class ReplayGainFilter final : public Filter { - /** - * If set, then this hardware mixer is used for applying - * replay gain, instead of the software volume library. - */ - Mixer *mixer; - - /** - * The base volume level for scale=1.0, between 1 and 100 - * (including). - */ - unsigned base; - - ReplayGainMode mode; - - ReplayGainInfo info; - - /** - * About the current volume: it is between 0 and a value that - * may or may not exceed #PCM_VOLUME_1. - * - * If the default value of true is used for replaygain_limit, the - * application of the volume to the signal will never cause clipping. - * - * On the other hand, if the user has set replaygain_limit to false, - * the chance of clipping is explicitly preferred if that's required to - * maintain a consistent audio level. Whether clipping will actually - * occur depends on what value the user is using for replaygain_preamp. - */ - PcmVolume pv; - -public: - ReplayGainFilter() - :mixer(nullptr), mode(REPLAY_GAIN_OFF) { - info.Clear(); - } - - void SetMixer(Mixer *_mixer, unsigned _base) { - assert(_mixer == nullptr || (_base > 0 && _base <= 100)); - - mixer = _mixer; - base = _base; - - Update(); - } - - void SetInfo(const ReplayGainInfo *_info) { - if (_info != nullptr) { - info = *_info; - info.Complete(); - } else - info.Clear(); - - Update(); - } - - void SetMode(ReplayGainMode _mode) { - if (_mode == mode) - /* no change */ - return; - - FormatDebug(replay_gain_domain, - "replay gain mode has changed %d->%d\n", - mode, _mode); - - mode = _mode; - Update(); - } - - /** - * Recalculates the new volume after a property was changed. - */ - void Update(); - - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close(); - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error); -}; - -void -ReplayGainFilter::Update() -{ - unsigned volume = PCM_VOLUME_1; - if (mode != REPLAY_GAIN_OFF) { - const auto &tuple = info.tuples[mode]; - float scale = tuple.CalculateScale(replay_gain_preamp, - replay_gain_missing_preamp, - replay_gain_limit); - FormatDebug(replay_gain_domain, - "scale=%f\n", (double)scale); - - volume = pcm_float_to_volume(scale); - } - - pv.SetVolume(volume); - - if (mixer != nullptr) { - /* update the hardware mixer volume */ - - unsigned _volume = (volume * base) / PCM_VOLUME_1; - if (_volume > 100) - _volume = 100; - - Error error; - if (!mixer_set_volume(mixer, _volume, error)) - LogError(error, "Failed to update hardware mixer"); - } -} - -static Filter * -replay_gain_filter_init(gcc_unused const config_param ¶m, - gcc_unused Error &error) -{ - return new ReplayGainFilter(); -} - -AudioFormat -ReplayGainFilter::Open(AudioFormat &af, gcc_unused Error &error) -{ - if (!pv.Open(af.format, error)) - return AudioFormat::Undefined(); - - return af; -} - -void -ReplayGainFilter::Close() -{ - pv.Close(); -} - -const void * -ReplayGainFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, gcc_unused Error &error) -{ - const auto dest = pv.Apply({src, src_size}); - *dest_size_r = dest.size; - return dest.data; -} - -const struct filter_plugin replay_gain_filter_plugin = { - "replay_gain", - replay_gain_filter_init, -}; - -void -replay_gain_filter_set_mixer(Filter *_filter, Mixer *mixer, - unsigned base) -{ - ReplayGainFilter *filter = (ReplayGainFilter *)_filter; - - filter->SetMixer(mixer, base); -} - -void -replay_gain_filter_set_info(Filter *_filter, const ReplayGainInfo *info) -{ - ReplayGainFilter *filter = (ReplayGainFilter *)_filter; - - filter->SetInfo(info); -} - -void -replay_gain_filter_set_mode(Filter *_filter, ReplayGainMode mode) -{ - ReplayGainFilter *filter = (ReplayGainFilter *)_filter; - - filter->SetMode(mode); -} diff --git a/src/filter/ReplayGainFilterPlugin.hxx b/src/filter/ReplayGainFilterPlugin.hxx deleted file mode 100644 index 346541b97..000000000 --- a/src/filter/ReplayGainFilterPlugin.hxx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 - * 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. - */ - -#ifndef MPD_REPLAY_GAIN_FILTER_PLUGIN_HXX -#define MPD_REPLAY_GAIN_FILTER_PLUGIN_HXX - -#include "ReplayGainInfo.hxx" - -class Filter; -class Mixer; - -/** - * Enables or disables the hardware mixer for applying replay gain. - * - * @param mixer the hardware mixer, or nullptr to fall back to software - * volume - * @param base the base volume level for scale=1.0, between 1 and 100 - * (including). - */ -void -replay_gain_filter_set_mixer(Filter *_filter, Mixer *mixer, - unsigned base); - -/** - * Sets a new #replay_gain_info at the beginning of a new song. - * - * @param info the new #replay_gain_info value, or nullptr if no replay - * gain data is available for the current song - */ -void -replay_gain_filter_set_info(Filter *filter, const ReplayGainInfo *info); - -void -replay_gain_filter_set_mode(Filter *filter, ReplayGainMode mode); - -#endif diff --git a/src/filter/RouteFilterPlugin.cxx b/src/filter/RouteFilterPlugin.cxx deleted file mode 100644 index 50073778a..000000000 --- a/src/filter/RouteFilterPlugin.cxx +++ /dev/null @@ -1,296 +0,0 @@ -/* - * 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 - * 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 - * - * This filter copies audio data between channels. Useful for - * upmixing mono/stereo audio to surround speaker configurations. - * - * Its configuration consists of a "filter" section with a single - * "routes" entry, formatted as: \\ - * routes "0>1, 1>0, 2>2, 3>3, 3>4" \\ - * where each pair of numbers signifies a set of channels. - * Each source>dest pair leads to the data from channel #source - * being copied to channel #dest in the output. - * - * Example: \\ - * routes "0>0, 1>1, 0>2, 1>3"\\ - * upmixes stereo audio to a 4-speaker system, copying the front-left - * (0) to front left (0) and rear left (2), copying front-right (1) to - * front-right (1) and rear-right (3). - * - * If multiple sources are copied to the same destination channel, only - * one of them takes effect. - */ - -#include "config.h" -#include "config/ConfigError.hxx" -#include "config/ConfigData.hxx" -#include "AudioFormat.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "pcm/PcmBuffer.hxx" -#include "util/StringUtil.hxx" -#include "util/Error.hxx" - -#include - -#include -#include -#include -#include - -class RouteFilter final : public Filter { - /** - * The minimum number of channels we need for output - * to be able to perform all the copies the user has specified - */ - unsigned min_output_channels; - - /** - * The minimum number of input channels we need to - * copy all the data the user has requested. If fewer - * than this many are supplied by the input, undefined - * copy operations are given zeroed sources in stead. - */ - unsigned min_input_channels; - - /** - * The set of copy operations to perform on each sample - * The index is an output channel to use, the value is - * a corresponding input channel from which to take the - * data. A -1 means "no source" - */ - int8_t sources[MAX_CHANNELS]; - - /** - * The actual input format of our signal, once opened - */ - AudioFormat input_format; - - /** - * The decided upon output format, once opened - */ - AudioFormat output_format; - - /** - * The size, in bytes, of each multichannel frame in the - * input buffer - */ - size_t input_frame_size; - - /** - * The size, in bytes, of each multichannel frame in the - * output buffer - */ - size_t output_frame_size; - - /** - * The output buffer used last time around, can be reused if the size doesn't differ. - */ - PcmBuffer output_buffer; - -public: - /** - * Parse the "routes" section, a string on the form - * a>b, c>d, e>f, ... - * where a... are non-unique, non-negative integers - * and input channel a gets copied to output channel b, etc. - * @param param the configuration block to read - * @param filter a route_filter whose min_channels and sources[] to set - * @return true on success, false on error - */ - bool Configure(const config_param ¶m, Error &error); - - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close(); - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error); -}; - -bool -RouteFilter::Configure(const config_param ¶m, Error &error) { - - /* TODO: - * With a more clever way of marking "don't copy to output N", - * This could easily be merged into a single loop with some - * dynamic realloc() instead of one count run and one malloc(). - */ - - std::fill_n(sources, MAX_CHANNELS, -1); - - min_input_channels = 0; - min_output_channels = 0; - - // A cowardly default, just passthrough stereo - const char *routes = param.GetBlockValue("routes", "0>0, 1>1"); - while (true) { - routes = strchug_fast(routes); - - char *endptr; - const unsigned source = strtoul(routes, &endptr, 10); - endptr = strchug_fast(endptr); - if (endptr == routes || *endptr != '>') { - error.Set(config_domain, - "Malformed 'routes' specification"); - return false; - } - - if (source >= MAX_CHANNELS) { - error.Format(config_domain, - "Invalid source channel number: %u", - source); - return false; - } - - if (source >= min_input_channels) - min_input_channels = source + 1; - - routes = strchug_fast(endptr + 1); - - unsigned dest = strtoul(routes, &endptr, 10); - endptr = strchug_fast(endptr); - if (endptr == routes) { - error.Set(config_domain, - "Malformed 'routes' specification"); - return false; - } - - if (dest >= MAX_CHANNELS) { - error.Format(config_domain, - "Invalid destination channel number: %u", - dest); - return false; - } - - if (dest >= min_output_channels) - min_output_channels = dest + 1; - - sources[dest] = source; - - routes = endptr; - - if (*routes == 0) - break; - - if (*routes != ',') { - error.Set(config_domain, - "Malformed 'routes' specification"); - return false; - } - - ++routes; - } - - return true; -} - -static Filter * -route_filter_init(const config_param ¶m, Error &error) -{ - RouteFilter *filter = new RouteFilter(); - if (!filter->Configure(param, error)) { - delete filter; - return nullptr; - } - - return filter; -} - -AudioFormat -RouteFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) -{ - // Copy the input format for later reference - input_format = audio_format; - input_frame_size = input_format.GetFrameSize(); - - // Decide on an output format which has enough channels, - // and is otherwise identical - output_format = audio_format; - output_format.channels = min_output_channels; - - // Precalculate this simple value, to speed up allocation later - output_frame_size = output_format.GetFrameSize(); - - return output_format; -} - -void -RouteFilter::Close() -{ - output_buffer.Clear(); -} - -const void * -RouteFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, gcc_unused Error &error) -{ - size_t number_of_frames = src_size / input_frame_size; - - const size_t bytes_per_frame_per_channel = input_format.GetSampleSize(); - - // A moving pointer that always refers to channel 0 in the input, at the currently handled frame - const uint8_t *base_source = (const uint8_t *)src; - - // Grow our reusable buffer, if needed, and set the moving pointer - *dest_size_r = number_of_frames * output_frame_size; - void *const result = output_buffer.Get(*dest_size_r); - - // A moving pointer that always refers to the currently filled channel of the currently handled frame, in the output - uint8_t *chan_destination = (uint8_t *)result; - - // Perform our copy operations, with N input channels and M output channels - for (unsigned int s=0; s= input_format.channels) { - // No source for this destination output, - // give it zeroes as input - memset(chan_destination, - 0x00, - bytes_per_frame_per_channel); - } else { - // Get the data from channel sources[c] - // and copy it to the output - const uint8_t *data = base_source + - (sources[c] * bytes_per_frame_per_channel); - memcpy(chan_destination, - data, - bytes_per_frame_per_channel); - } - // Move on to the next output channel - chan_destination += bytes_per_frame_per_channel; - } - - - // Go on to the next N input samples - base_source += input_frame_size; - } - - // Here it is, ladies and gentlemen! Rerouted data! - return result; -} - -const struct filter_plugin route_filter_plugin = { - "route", - route_filter_init, -}; diff --git a/src/filter/VolumeFilterPlugin.cxx b/src/filter/VolumeFilterPlugin.cxx deleted file mode 100644 index 8d3de3eb9..000000000 --- a/src/filter/VolumeFilterPlugin.cxx +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 - * 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 "config.h" -#include "VolumeFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "pcm/Volume.hxx" -#include "AudioFormat.hxx" -#include "util/ConstBuffer.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" - -#include -#include - -class VolumeFilter final : public Filter { - PcmVolume pv; - -public: - unsigned GetVolume() const { - return pv.GetVolume(); - } - - void SetVolume(unsigned _volume) { - pv.SetVolume(_volume); - } - - virtual AudioFormat Open(AudioFormat &af, Error &error) override; - virtual void Close(); - virtual const void *FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error); -}; - -static constexpr Domain volume_domain("pcm_volume"); - -static Filter * -volume_filter_init(gcc_unused const config_param ¶m, - gcc_unused Error &error) -{ - return new VolumeFilter(); -} - -AudioFormat -VolumeFilter::Open(AudioFormat &audio_format, Error &error) -{ - if (!pv.Open(audio_format.format, error)) - return AudioFormat::Undefined(); - - return audio_format; -} - -void -VolumeFilter::Close() -{ - pv.Close(); -} - -const void * -VolumeFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, gcc_unused Error &error) -{ - const auto dest = pv.Apply({src, src_size}); - *dest_size_r = dest.size; - return dest.data; -} - -const struct filter_plugin volume_filter_plugin = { - "volume", - volume_filter_init, -}; - -unsigned -volume_filter_get(const Filter *_filter) -{ - const VolumeFilter *filter = - (const VolumeFilter *)_filter; - - return filter->GetVolume(); -} - -void -volume_filter_set(Filter *_filter, unsigned volume) -{ - VolumeFilter *filter = (VolumeFilter *)_filter; - - filter->SetVolume(volume); -} - diff --git a/src/filter/VolumeFilterPlugin.hxx b/src/filter/VolumeFilterPlugin.hxx deleted file mode 100644 index b5317dc6f..000000000 --- a/src/filter/VolumeFilterPlugin.hxx +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 - * 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. - */ - -#ifndef MPD_VOLUME_FILTER_PLUGIN_HXX -#define MPD_VOLUME_FILTER_PLUGIN_HXX - -class Filter; - -unsigned -volume_filter_get(const Filter *filter); - -void -volume_filter_set(Filter *filter, unsigned volume); - -#endif diff --git a/src/filter/plugins/AutoConvertFilterPlugin.cxx b/src/filter/plugins/AutoConvertFilterPlugin.cxx new file mode 100644 index 000000000..cdeeefdc6 --- /dev/null +++ b/src/filter/plugins/AutoConvertFilterPlugin.cxx @@ -0,0 +1,131 @@ +/* + * 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 + * 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 "config.h" +#include "AutoConvertFilterPlugin.hxx" +#include "ConvertFilterPlugin.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "AudioFormat.hxx" +#include "config/ConfigData.hxx" + +#include + +class AutoConvertFilter final : public Filter { + /** + * The underlying filter. + */ + Filter *filter; + + /** + * A convert_filter, just in case conversion is needed. nullptr + * if unused. + */ + Filter *convert; + +public: + AutoConvertFilter(Filter *_filter):filter(_filter) {} + ~AutoConvertFilter() { + delete filter; + } + + virtual AudioFormat Open(AudioFormat &af, Error &error) override; + virtual void Close() override; + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, + Error &error) override; +}; + +AudioFormat +AutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error) +{ + assert(in_audio_format.IsValid()); + + /* open the "real" filter */ + + AudioFormat child_audio_format = in_audio_format; + AudioFormat out_audio_format = filter->Open(child_audio_format, error); + if (!out_audio_format.IsDefined()) + return out_audio_format; + + /* need to convert? */ + + if (in_audio_format != child_audio_format) { + /* yes - create a convert_filter */ + + const config_param empty; + convert = filter_new(&convert_filter_plugin, empty, error); + if (convert == nullptr) { + filter->Close(); + return AudioFormat::Undefined(); + } + + AudioFormat audio_format2 = in_audio_format; + AudioFormat audio_format3 = + convert->Open(audio_format2, error); + if (!audio_format3.IsDefined()) { + delete convert; + filter->Close(); + return AudioFormat::Undefined(); + } + + assert(audio_format2 == in_audio_format); + + if (!convert_filter_set(convert, child_audio_format, error)) { + delete convert; + filter->Close(); + return AudioFormat::Undefined(); + } + } else + /* no */ + convert = nullptr; + + return out_audio_format; +} + +void +AutoConvertFilter::Close() +{ + if (convert != nullptr) { + convert->Close(); + delete convert; + } + + filter->Close(); +} + +const void * +AutoConvertFilter::FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error) +{ + if (convert != nullptr) { + src = convert->FilterPCM(src, src_size, &src_size, error); + if (src == nullptr) + return nullptr; + } + + return filter->FilterPCM(src, src_size, dest_size_r, error); +} + +Filter * +autoconvert_filter_new(Filter *filter) +{ + return new AutoConvertFilter(filter); +} diff --git a/src/filter/plugins/AutoConvertFilterPlugin.hxx b/src/filter/plugins/AutoConvertFilterPlugin.hxx new file mode 100644 index 000000000..c5dfdd2f6 --- /dev/null +++ b/src/filter/plugins/AutoConvertFilterPlugin.hxx @@ -0,0 +1,34 @@ +/* + * 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 + * 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. + */ + +#ifndef MPD_AUTOCONVERT_FILTER_PLUGIN_HXX +#define MPD_AUTOCONVERT_FILTER_PLUGIN_HXX + +class Filter; + +/** + * Creates a new "autoconvert" filter. When opened, it ensures that + * the input audio format isn't changed. If the underlying filter + * requests a different format, it automatically creates a + * convert_filter. + */ +Filter * +autoconvert_filter_new(Filter *filter); + +#endif diff --git a/src/filter/plugins/ChainFilterPlugin.cxx b/src/filter/plugins/ChainFilterPlugin.cxx new file mode 100644 index 000000000..7dc6db667 --- /dev/null +++ b/src/filter/plugins/ChainFilterPlugin.cxx @@ -0,0 +1,181 @@ +/* + * 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 + * 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 "config.h" +#include "ChainFilterPlugin.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "AudioFormat.hxx" +#include "util/Error.hxx" +#include "util/Domain.hxx" + +#include + +#include + +class ChainFilter final : public Filter { + struct Child { + const char *name; + Filter *filter; + + Child(const char *_name, Filter *_filter) + :name(_name), filter(_filter) {} + ~Child() { + delete filter; + } + + Child(const Child &) = delete; + Child &operator=(const Child &) = delete; + }; + + std::list children; + +public: + void Append(const char *name, Filter *filter) { + children.emplace_back(name, filter); + } + + virtual AudioFormat Open(AudioFormat &af, Error &error) override; + virtual void Close(); + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error); + +private: + /** + * Close all filters in the chain until #until is reached. + * #until itself is not closed. + */ + void CloseUntil(const Filter *until); +}; + +static constexpr Domain chain_filter_domain("chain_filter"); + +static Filter * +chain_filter_init(gcc_unused const config_param ¶m, + gcc_unused Error &error) +{ + return new ChainFilter(); +} + +void +ChainFilter::CloseUntil(const Filter *until) +{ + for (auto &child : children) { + if (child.filter == until) + /* don't close this filter */ + return; + + /* close this filter */ + child.filter->Close(); + } + + /* this assertion fails if #until does not exist (anymore) */ + assert(false); + gcc_unreachable(); +} + +static AudioFormat +chain_open_child(const char *name, Filter *filter, + const AudioFormat &prev_audio_format, + Error &error) +{ + AudioFormat conv_audio_format = prev_audio_format; + const AudioFormat next_audio_format = + filter->Open(conv_audio_format, error); + if (!next_audio_format.IsDefined()) + return next_audio_format; + + if (conv_audio_format != prev_audio_format) { + struct audio_format_string s; + + filter->Close(); + + error.Format(chain_filter_domain, + "Audio format not supported by filter '%s': %s", + name, + audio_format_to_string(prev_audio_format, &s)); + return AudioFormat::Undefined(); + } + + return next_audio_format; +} + +AudioFormat +ChainFilter::Open(AudioFormat &in_audio_format, Error &error) +{ + AudioFormat audio_format = in_audio_format; + + for (auto &child : children) { + audio_format = chain_open_child(child.name, child.filter, + audio_format, error); + if (!audio_format.IsDefined()) { + /* rollback, close all children */ + CloseUntil(child.filter); + break; + } + } + + /* return the output format of the last filter */ + return audio_format; +} + +void +ChainFilter::Close() +{ + for (auto &child : children) + child.filter->Close(); +} + +const void * +ChainFilter::FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error) +{ + for (auto &child : children) { + /* feed the output of the previous filter as input + into the current one */ + src = child.filter->FilterPCM(src, src_size, &src_size, + error); + if (src == nullptr) + return nullptr; + } + + /* return the output of the last filter */ + *dest_size_r = src_size; + return src; +} + +const struct filter_plugin chain_filter_plugin = { + "chain", + chain_filter_init, +}; + +Filter * +filter_chain_new(void) +{ + return new ChainFilter(); +} + +void +filter_chain_append(Filter &_chain, const char *name, Filter *filter) +{ + ChainFilter &chain = (ChainFilter &)_chain; + + chain.Append(name, filter); +} diff --git a/src/filter/plugins/ChainFilterPlugin.hxx b/src/filter/plugins/ChainFilterPlugin.hxx new file mode 100644 index 000000000..b36aa3322 --- /dev/null +++ b/src/filter/plugins/ChainFilterPlugin.hxx @@ -0,0 +1,48 @@ +/* + * 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 + * 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 + +class Filter; + +/** + * Creates a new filter chain. + */ +Filter * +filter_chain_new(void); + +/** + * 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(Filter &chain, const char *name, Filter *filter); + +#endif diff --git a/src/filter/plugins/ConvertFilterPlugin.cxx b/src/filter/plugins/ConvertFilterPlugin.cxx new file mode 100644 index 000000000..27e6774f8 --- /dev/null +++ b/src/filter/plugins/ConvertFilterPlugin.cxx @@ -0,0 +1,149 @@ +/* + * 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 + * 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 "config.h" +#include "ConvertFilterPlugin.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "pcm/PcmConvert.hxx" +#include "util/Manual.hxx" +#include "AudioFormat.hxx" +#include "poison.h" + +#include + +class ConvertFilter final : public Filter { + /** + * The input audio format; PCM data is passed to the filter() + * method in this format. + */ + AudioFormat in_audio_format; + + /** + * The output audio format; the consumer of this plugin + * expects PCM data in this format. + * + * If this is AudioFormat::Undefined(), then the #PcmConvert + * attribute is not open. This can mean that Set() has failed + * or that no conversion is necessary. + */ + AudioFormat out_audio_format; + + Manual state; + +public: + bool Set(const AudioFormat &_out_audio_format, Error &error); + + virtual AudioFormat Open(AudioFormat &af, Error &error) override; + virtual void Close() override; + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, + Error &error) override; +}; + +static Filter * +convert_filter_init(gcc_unused const config_param ¶m, + gcc_unused Error &error) +{ + return new ConvertFilter(); +} + +bool +ConvertFilter::Set(const AudioFormat &_out_audio_format, Error &error) +{ + assert(in_audio_format.IsValid()); + assert(_out_audio_format.IsValid()); + + if (_out_audio_format == out_audio_format) + /* no change */ + return true; + + if (out_audio_format.IsValid()) { + out_audio_format.Clear(); + state->Close(); + } + + if (_out_audio_format == in_audio_format) + /* optimized special case: no-op */ + return true; + + if (!state->Open(in_audio_format, _out_audio_format, error)) + return false; + + out_audio_format = _out_audio_format; + return true; +} + +AudioFormat +ConvertFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) +{ + assert(audio_format.IsValid()); + + in_audio_format = audio_format; + out_audio_format.Clear(); + + state.Construct(); + + return in_audio_format; +} + +void +ConvertFilter::Close() +{ + assert(in_audio_format.IsValid()); + + if (out_audio_format.IsValid()) + state->Close(); + + state.Destruct(); + + poison_undefined(&in_audio_format, sizeof(in_audio_format)); + poison_undefined(&out_audio_format, sizeof(out_audio_format)); +} + +const void * +ConvertFilter::FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error) +{ + assert(in_audio_format.IsValid()); + + if (!out_audio_format.IsValid()) { + /* optimized special case: no-op */ + *dest_size_r = src_size; + return src; + } + + return state->Convert(src, src_size, dest_size_r, + error); +} + +const struct filter_plugin convert_filter_plugin = { + "convert", + convert_filter_init, +}; + +bool +convert_filter_set(Filter *_filter, AudioFormat out_audio_format, + Error &error) +{ + ConvertFilter *filter = (ConvertFilter *)_filter; + + return filter->Set(out_audio_format, error); +} diff --git a/src/filter/plugins/ConvertFilterPlugin.hxx b/src/filter/plugins/ConvertFilterPlugin.hxx new file mode 100644 index 000000000..bb4673651 --- /dev/null +++ b/src/filter/plugins/ConvertFilterPlugin.hxx @@ -0,0 +1,37 @@ +/* + * 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 + * 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. + */ + +#ifndef MPD_CONVERT_FILTER_PLUGIN_HXX +#define MPD_CONVERT_FILTER_PLUGIN_HXX + +class Filter; +class Error; +struct AudioFormat; + +/** + * Sets the output audio format for the specified filter. You must + * call this after the filter has been opened. Since this audio + * format switch is a violation of the filter API, this filter must be + * the last in a chain. + */ +bool +convert_filter_set(Filter *filter, AudioFormat out_audio_format, + Error &error); + +#endif diff --git a/src/filter/plugins/NormalizeFilterPlugin.cxx b/src/filter/plugins/NormalizeFilterPlugin.cxx new file mode 100644 index 000000000..58eb0c6a2 --- /dev/null +++ b/src/filter/plugins/NormalizeFilterPlugin.cxx @@ -0,0 +1,82 @@ +/* + * 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 + * 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 "config.h" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "pcm/PcmBuffer.hxx" +#include "AudioFormat.hxx" +#include "AudioCompress/compress.h" + +#include + +class NormalizeFilter final : public Filter { + struct Compressor *compressor; + + PcmBuffer buffer; + +public: + virtual AudioFormat Open(AudioFormat &af, Error &error) override; + virtual void Close(); + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error); +}; + +static Filter * +normalize_filter_init(gcc_unused const config_param ¶m, + gcc_unused Error &error) +{ + return new NormalizeFilter(); +} + +AudioFormat +NormalizeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) +{ + audio_format.format = SampleFormat::S16; + + compressor = Compressor_new(0); + + return audio_format; +} + +void +NormalizeFilter::Close() +{ + buffer.Clear(); + Compressor_delete(compressor); +} + +const void * +NormalizeFilter::FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, gcc_unused Error &error) +{ + int16_t *dest = (int16_t *)buffer.Get(src_size); + memcpy(dest, src, src_size); + + Compressor_Process_int16(compressor, dest, src_size / 2); + + *dest_size_r = src_size; + return dest; +} + +const struct filter_plugin normalize_filter_plugin = { + "normalize", + normalize_filter_init, +}; diff --git a/src/filter/plugins/NullFilterPlugin.cxx b/src/filter/plugins/NullFilterPlugin.cxx new file mode 100644 index 000000000..f79aa19f7 --- /dev/null +++ b/src/filter/plugins/NullFilterPlugin.cxx @@ -0,0 +1,61 @@ +/* + * 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 + * 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 + * + * This filter plugin does nothing. That is not quite useful, except + * for testing the filter core, or as a template for new filter + * plugins. + */ + +#include "config.h" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "AudioFormat.hxx" +#include "Compiler.h" + +class NullFilter final : public Filter { +public: + virtual AudioFormat Open(AudioFormat &af, + gcc_unused Error &error) override { + return af; + } + + virtual void Close() override {} + + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, + gcc_unused Error &error) override { + *dest_size_r = src_size; + return src; + } +}; + +static Filter * +null_filter_init(gcc_unused const config_param ¶m, + gcc_unused Error &error) +{ + return new NullFilter(); +} + +const struct filter_plugin null_filter_plugin = { + "null", + null_filter_init, +}; diff --git a/src/filter/plugins/ReplayGainFilterPlugin.cxx b/src/filter/plugins/ReplayGainFilterPlugin.cxx new file mode 100644 index 000000000..d89e79480 --- /dev/null +++ b/src/filter/plugins/ReplayGainFilterPlugin.cxx @@ -0,0 +1,210 @@ +/* + * 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 + * 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 "config.h" +#include "ReplayGainFilterPlugin.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "AudioFormat.hxx" +#include "ReplayGainInfo.hxx" +#include "ReplayGainConfig.hxx" +#include "MixerControl.hxx" +#include "pcm/Volume.hxx" +#include "pcm/PcmBuffer.hxx" +#include "util/ConstBuffer.hxx" +#include "util/Error.hxx" +#include "util/Domain.hxx" +#include "Log.hxx" + +#include +#include + +static constexpr Domain replay_gain_domain("replay_gain"); + +class ReplayGainFilter final : public Filter { + /** + * If set, then this hardware mixer is used for applying + * replay gain, instead of the software volume library. + */ + Mixer *mixer; + + /** + * The base volume level for scale=1.0, between 1 and 100 + * (including). + */ + unsigned base; + + ReplayGainMode mode; + + ReplayGainInfo info; + + /** + * About the current volume: it is between 0 and a value that + * may or may not exceed #PCM_VOLUME_1. + * + * If the default value of true is used for replaygain_limit, the + * application of the volume to the signal will never cause clipping. + * + * On the other hand, if the user has set replaygain_limit to false, + * the chance of clipping is explicitly preferred if that's required to + * maintain a consistent audio level. Whether clipping will actually + * occur depends on what value the user is using for replaygain_preamp. + */ + PcmVolume pv; + +public: + ReplayGainFilter() + :mixer(nullptr), mode(REPLAY_GAIN_OFF) { + info.Clear(); + } + + void SetMixer(Mixer *_mixer, unsigned _base) { + assert(_mixer == nullptr || (_base > 0 && _base <= 100)); + + mixer = _mixer; + base = _base; + + Update(); + } + + void SetInfo(const ReplayGainInfo *_info) { + if (_info != nullptr) { + info = *_info; + info.Complete(); + } else + info.Clear(); + + Update(); + } + + void SetMode(ReplayGainMode _mode) { + if (_mode == mode) + /* no change */ + return; + + FormatDebug(replay_gain_domain, + "replay gain mode has changed %d->%d\n", + mode, _mode); + + mode = _mode; + Update(); + } + + /** + * Recalculates the new volume after a property was changed. + */ + void Update(); + + virtual AudioFormat Open(AudioFormat &af, Error &error) override; + virtual void Close(); + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error); +}; + +void +ReplayGainFilter::Update() +{ + unsigned volume = PCM_VOLUME_1; + if (mode != REPLAY_GAIN_OFF) { + const auto &tuple = info.tuples[mode]; + float scale = tuple.CalculateScale(replay_gain_preamp, + replay_gain_missing_preamp, + replay_gain_limit); + FormatDebug(replay_gain_domain, + "scale=%f\n", (double)scale); + + volume = pcm_float_to_volume(scale); + } + + pv.SetVolume(volume); + + if (mixer != nullptr) { + /* update the hardware mixer volume */ + + unsigned _volume = (volume * base) / PCM_VOLUME_1; + if (_volume > 100) + _volume = 100; + + Error error; + if (!mixer_set_volume(mixer, _volume, error)) + LogError(error, "Failed to update hardware mixer"); + } +} + +static Filter * +replay_gain_filter_init(gcc_unused const config_param ¶m, + gcc_unused Error &error) +{ + return new ReplayGainFilter(); +} + +AudioFormat +ReplayGainFilter::Open(AudioFormat &af, gcc_unused Error &error) +{ + if (!pv.Open(af.format, error)) + return AudioFormat::Undefined(); + + return af; +} + +void +ReplayGainFilter::Close() +{ + pv.Close(); +} + +const void * +ReplayGainFilter::FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, gcc_unused Error &error) +{ + const auto dest = pv.Apply({src, src_size}); + *dest_size_r = dest.size; + return dest.data; +} + +const struct filter_plugin replay_gain_filter_plugin = { + "replay_gain", + replay_gain_filter_init, +}; + +void +replay_gain_filter_set_mixer(Filter *_filter, Mixer *mixer, + unsigned base) +{ + ReplayGainFilter *filter = (ReplayGainFilter *)_filter; + + filter->SetMixer(mixer, base); +} + +void +replay_gain_filter_set_info(Filter *_filter, const ReplayGainInfo *info) +{ + ReplayGainFilter *filter = (ReplayGainFilter *)_filter; + + filter->SetInfo(info); +} + +void +replay_gain_filter_set_mode(Filter *_filter, ReplayGainMode mode) +{ + ReplayGainFilter *filter = (ReplayGainFilter *)_filter; + + filter->SetMode(mode); +} diff --git a/src/filter/plugins/ReplayGainFilterPlugin.hxx b/src/filter/plugins/ReplayGainFilterPlugin.hxx new file mode 100644 index 000000000..346541b97 --- /dev/null +++ b/src/filter/plugins/ReplayGainFilterPlugin.hxx @@ -0,0 +1,52 @@ +/* + * 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 + * 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. + */ + +#ifndef MPD_REPLAY_GAIN_FILTER_PLUGIN_HXX +#define MPD_REPLAY_GAIN_FILTER_PLUGIN_HXX + +#include "ReplayGainInfo.hxx" + +class Filter; +class Mixer; + +/** + * Enables or disables the hardware mixer for applying replay gain. + * + * @param mixer the hardware mixer, or nullptr to fall back to software + * volume + * @param base the base volume level for scale=1.0, between 1 and 100 + * (including). + */ +void +replay_gain_filter_set_mixer(Filter *_filter, Mixer *mixer, + unsigned base); + +/** + * Sets a new #replay_gain_info at the beginning of a new song. + * + * @param info the new #replay_gain_info value, or nullptr if no replay + * gain data is available for the current song + */ +void +replay_gain_filter_set_info(Filter *filter, const ReplayGainInfo *info); + +void +replay_gain_filter_set_mode(Filter *filter, ReplayGainMode mode); + +#endif diff --git a/src/filter/plugins/RouteFilterPlugin.cxx b/src/filter/plugins/RouteFilterPlugin.cxx new file mode 100644 index 000000000..38c4ec43b --- /dev/null +++ b/src/filter/plugins/RouteFilterPlugin.cxx @@ -0,0 +1,296 @@ +/* + * 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 + * 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 + * + * This filter copies audio data between channels. Useful for + * upmixing mono/stereo audio to surround speaker configurations. + * + * Its configuration consists of a "filter" section with a single + * "routes" entry, formatted as: \\ + * routes "0>1, 1>0, 2>2, 3>3, 3>4" \\ + * where each pair of numbers signifies a set of channels. + * Each source>dest pair leads to the data from channel #source + * being copied to channel #dest in the output. + * + * Example: \\ + * routes "0>0, 1>1, 0>2, 1>3"\\ + * upmixes stereo audio to a 4-speaker system, copying the front-left + * (0) to front left (0) and rear left (2), copying front-right (1) to + * front-right (1) and rear-right (3). + * + * If multiple sources are copied to the same destination channel, only + * one of them takes effect. + */ + +#include "config.h" +#include "config/ConfigError.hxx" +#include "config/ConfigData.hxx" +#include "AudioFormat.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "pcm/PcmBuffer.hxx" +#include "util/StringUtil.hxx" +#include "util/Error.hxx" + +#include + +#include +#include +#include +#include + +class RouteFilter final : public Filter { + /** + * The minimum number of channels we need for output + * to be able to perform all the copies the user has specified + */ + unsigned min_output_channels; + + /** + * The minimum number of input channels we need to + * copy all the data the user has requested. If fewer + * than this many are supplied by the input, undefined + * copy operations are given zeroed sources in stead. + */ + unsigned min_input_channels; + + /** + * The set of copy operations to perform on each sample + * The index is an output channel to use, the value is + * a corresponding input channel from which to take the + * data. A -1 means "no source" + */ + int8_t sources[MAX_CHANNELS]; + + /** + * The actual input format of our signal, once opened + */ + AudioFormat input_format; + + /** + * The decided upon output format, once opened + */ + AudioFormat output_format; + + /** + * The size, in bytes, of each multichannel frame in the + * input buffer + */ + size_t input_frame_size; + + /** + * The size, in bytes, of each multichannel frame in the + * output buffer + */ + size_t output_frame_size; + + /** + * The output buffer used last time around, can be reused if the size doesn't differ. + */ + PcmBuffer output_buffer; + +public: + /** + * Parse the "routes" section, a string on the form + * a>b, c>d, e>f, ... + * where a... are non-unique, non-negative integers + * and input channel a gets copied to output channel b, etc. + * @param param the configuration block to read + * @param filter a route_filter whose min_channels and sources[] to set + * @return true on success, false on error + */ + bool Configure(const config_param ¶m, Error &error); + + virtual AudioFormat Open(AudioFormat &af, Error &error) override; + virtual void Close(); + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error); +}; + +bool +RouteFilter::Configure(const config_param ¶m, Error &error) { + + /* TODO: + * With a more clever way of marking "don't copy to output N", + * This could easily be merged into a single loop with some + * dynamic realloc() instead of one count run and one malloc(). + */ + + std::fill_n(sources, MAX_CHANNELS, -1); + + min_input_channels = 0; + min_output_channels = 0; + + // A cowardly default, just passthrough stereo + const char *routes = param.GetBlockValue("routes", "0>0, 1>1"); + while (true) { + routes = strchug_fast(routes); + + char *endptr; + const unsigned source = strtoul(routes, &endptr, 10); + endptr = strchug_fast(endptr); + if (endptr == routes || *endptr != '>') { + error.Set(config_domain, + "Malformed 'routes' specification"); + return false; + } + + if (source >= MAX_CHANNELS) { + error.Format(config_domain, + "Invalid source channel number: %u", + source); + return false; + } + + if (source >= min_input_channels) + min_input_channels = source + 1; + + routes = strchug_fast(endptr + 1); + + unsigned dest = strtoul(routes, &endptr, 10); + endptr = strchug_fast(endptr); + if (endptr == routes) { + error.Set(config_domain, + "Malformed 'routes' specification"); + return false; + } + + if (dest >= MAX_CHANNELS) { + error.Format(config_domain, + "Invalid destination channel number: %u", + dest); + return false; + } + + if (dest >= min_output_channels) + min_output_channels = dest + 1; + + sources[dest] = source; + + routes = endptr; + + if (*routes == 0) + break; + + if (*routes != ',') { + error.Set(config_domain, + "Malformed 'routes' specification"); + return false; + } + + ++routes; + } + + return true; +} + +static Filter * +route_filter_init(const config_param ¶m, Error &error) +{ + RouteFilter *filter = new RouteFilter(); + if (!filter->Configure(param, error)) { + delete filter; + return nullptr; + } + + return filter; +} + +AudioFormat +RouteFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) +{ + // Copy the input format for later reference + input_format = audio_format; + input_frame_size = input_format.GetFrameSize(); + + // Decide on an output format which has enough channels, + // and is otherwise identical + output_format = audio_format; + output_format.channels = min_output_channels; + + // Precalculate this simple value, to speed up allocation later + output_frame_size = output_format.GetFrameSize(); + + return output_format; +} + +void +RouteFilter::Close() +{ + output_buffer.Clear(); +} + +const void * +RouteFilter::FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, gcc_unused Error &error) +{ + size_t number_of_frames = src_size / input_frame_size; + + const size_t bytes_per_frame_per_channel = input_format.GetSampleSize(); + + // A moving pointer that always refers to channel 0 in the input, at the currently handled frame + const uint8_t *base_source = (const uint8_t *)src; + + // Grow our reusable buffer, if needed, and set the moving pointer + *dest_size_r = number_of_frames * output_frame_size; + void *const result = output_buffer.Get(*dest_size_r); + + // A moving pointer that always refers to the currently filled channel of the currently handled frame, in the output + uint8_t *chan_destination = (uint8_t *)result; + + // Perform our copy operations, with N input channels and M output channels + for (unsigned int s=0; s= input_format.channels) { + // No source for this destination output, + // give it zeroes as input + memset(chan_destination, + 0x00, + bytes_per_frame_per_channel); + } else { + // Get the data from channel sources[c] + // and copy it to the output + const uint8_t *data = base_source + + (sources[c] * bytes_per_frame_per_channel); + memcpy(chan_destination, + data, + bytes_per_frame_per_channel); + } + // Move on to the next output channel + chan_destination += bytes_per_frame_per_channel; + } + + + // Go on to the next N input samples + base_source += input_frame_size; + } + + // Here it is, ladies and gentlemen! Rerouted data! + return result; +} + +const struct filter_plugin route_filter_plugin = { + "route", + route_filter_init, +}; diff --git a/src/filter/plugins/VolumeFilterPlugin.cxx b/src/filter/plugins/VolumeFilterPlugin.cxx new file mode 100644 index 000000000..c9b7aa89e --- /dev/null +++ b/src/filter/plugins/VolumeFilterPlugin.cxx @@ -0,0 +1,106 @@ +/* + * 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 + * 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 "config.h" +#include "VolumeFilterPlugin.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" +#include "pcm/Volume.hxx" +#include "AudioFormat.hxx" +#include "util/ConstBuffer.hxx" +#include "util/Error.hxx" +#include "util/Domain.hxx" + +#include +#include + +class VolumeFilter final : public Filter { + PcmVolume pv; + +public: + unsigned GetVolume() const { + return pv.GetVolume(); + } + + void SetVolume(unsigned _volume) { + pv.SetVolume(_volume); + } + + virtual AudioFormat Open(AudioFormat &af, Error &error) override; + virtual void Close(); + virtual const void *FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, Error &error); +}; + +static constexpr Domain volume_domain("pcm_volume"); + +static Filter * +volume_filter_init(gcc_unused const config_param ¶m, + gcc_unused Error &error) +{ + return new VolumeFilter(); +} + +AudioFormat +VolumeFilter::Open(AudioFormat &audio_format, Error &error) +{ + if (!pv.Open(audio_format.format, error)) + return AudioFormat::Undefined(); + + return audio_format; +} + +void +VolumeFilter::Close() +{ + pv.Close(); +} + +const void * +VolumeFilter::FilterPCM(const void *src, size_t src_size, + size_t *dest_size_r, gcc_unused Error &error) +{ + const auto dest = pv.Apply({src, src_size}); + *dest_size_r = dest.size; + return dest.data; +} + +const struct filter_plugin volume_filter_plugin = { + "volume", + volume_filter_init, +}; + +unsigned +volume_filter_get(const Filter *_filter) +{ + const VolumeFilter *filter = + (const VolumeFilter *)_filter; + + return filter->GetVolume(); +} + +void +volume_filter_set(Filter *_filter, unsigned volume) +{ + VolumeFilter *filter = (VolumeFilter *)_filter; + + filter->SetVolume(volume); +} + diff --git a/src/filter/plugins/VolumeFilterPlugin.hxx b/src/filter/plugins/VolumeFilterPlugin.hxx new file mode 100644 index 000000000..b5317dc6f --- /dev/null +++ b/src/filter/plugins/VolumeFilterPlugin.hxx @@ -0,0 +1,31 @@ +/* + * 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 + * 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. + */ + +#ifndef MPD_VOLUME_FILTER_PLUGIN_HXX +#define MPD_VOLUME_FILTER_PLUGIN_HXX + +class Filter; + +unsigned +volume_filter_get(const Filter *filter); + +void +volume_filter_set(Filter *filter, unsigned volume); + +#endif diff --git a/src/mixer/SoftwareMixerPlugin.cxx b/src/mixer/SoftwareMixerPlugin.cxx index ad23baa2c..a0de727af 100644 --- a/src/mixer/SoftwareMixerPlugin.cxx +++ b/src/mixer/SoftwareMixerPlugin.cxx @@ -20,10 +20,10 @@ #include "config.h" #include "SoftwareMixerPlugin.hxx" #include "MixerInternal.hxx" -#include "FilterPlugin.hxx" -#include "FilterRegistry.hxx" -#include "FilterInternal.hxx" -#include "filter/VolumeFilterPlugin.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterRegistry.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/plugins/VolumeFilterPlugin.hxx" #include "pcm/Volume.hxx" #include "config/ConfigData.hxx" #include "util/Error.hxx" diff --git a/src/output/OutputControl.cxx b/src/output/OutputControl.cxx index b938754fd..234980a52 100644 --- a/src/output/OutputControl.cxx +++ b/src/output/OutputControl.cxx @@ -26,7 +26,7 @@ #include "OutputError.hxx" #include "MixerControl.hxx" #include "notify.hxx" -#include "filter/ReplayGainFilterPlugin.hxx" +#include "filter/plugins/ReplayGainFilterPlugin.hxx" #include "util/Error.hxx" #include "Log.hxx" diff --git a/src/output/OutputFinish.cxx b/src/output/OutputFinish.cxx index 43f0dd1ec..109662fb0 100644 --- a/src/output/OutputFinish.cxx +++ b/src/output/OutputFinish.cxx @@ -21,7 +21,7 @@ #include "OutputInternal.hxx" #include "OutputPlugin.hxx" #include "MixerControl.hxx" -#include "FilterInternal.hxx" +#include "filter/FilterInternal.hxx" #include diff --git a/src/output/OutputInit.cxx b/src/output/OutputInit.cxx index 920a04997..7815dc921 100644 --- a/src/output/OutputInit.cxx +++ b/src/output/OutputInit.cxx @@ -22,17 +22,17 @@ #include "OutputList.hxx" #include "OutputError.hxx" #include "OutputAPI.hxx" -#include "FilterConfig.hxx" +#include "filter/FilterConfig.hxx" #include "AudioParser.hxx" #include "MixerList.hxx" #include "MixerType.hxx" #include "MixerControl.hxx" #include "mixer/SoftwareMixerPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterRegistry.hxx" -#include "filter/AutoConvertFilterPlugin.hxx" -#include "filter/ReplayGainFilterPlugin.hxx" -#include "filter/ChainFilterPlugin.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterRegistry.hxx" +#include "filter/plugins/AutoConvertFilterPlugin.hxx" +#include "filter/plugins/ReplayGainFilterPlugin.hxx" +#include "filter/plugins/ChainFilterPlugin.hxx" #include "config/ConfigError.hxx" #include "config/ConfigGlobal.hxx" #include "util/Error.hxx" diff --git a/src/output/OutputThread.cxx b/src/output/OutputThread.cxx index f7e28b5f4..52dfc63ef 100644 --- a/src/output/OutputThread.cxx +++ b/src/output/OutputThread.cxx @@ -24,9 +24,9 @@ #include "OutputError.hxx" #include "pcm/PcmMix.hxx" #include "notify.hxx" -#include "FilterInternal.hxx" -#include "filter/ConvertFilterPlugin.hxx" -#include "filter/ReplayGainFilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/plugins/ConvertFilterPlugin.hxx" +#include "filter/plugins/ReplayGainFilterPlugin.hxx" #include "PlayerControl.hxx" #include "MusicPipe.hxx" #include "MusicChunk.hxx" diff --git a/test/read_mixer.cxx b/test/read_mixer.cxx index 60c60c86a..d080f46ca 100644 --- a/test/read_mixer.cxx +++ b/test/read_mixer.cxx @@ -20,7 +20,7 @@ #include "config.h" #include "MixerControl.hxx" #include "MixerList.hxx" -#include "FilterRegistry.hxx" +#include "filter/FilterRegistry.hxx" #include "pcm/Volume.hxx" #include "GlobalEvents.hxx" #include "Main.hxx" diff --git a/test/run_filter.cxx b/test/run_filter.cxx index 16808ebb2..3ce116280 100644 --- a/test/run_filter.cxx +++ b/test/run_filter.cxx @@ -23,8 +23,8 @@ #include "fs/Path.hxx" #include "AudioParser.hxx" #include "AudioFormat.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" #include "pcm/Volume.hxx" #include "MixerControl.hxx" #include "stdbin.h" @@ -153,7 +153,7 @@ int main(int argc, char **argv) dest = filter->FilterPCM(buffer, (size_t)nbytes, &length, error); if (dest == NULL) { - LogError(error, "Filter failed"); + LogError(error, "filter/Filter failed"); filter->Close(); delete filter; return EXIT_FAILURE; diff --git a/test/run_output.cxx b/test/run_output.cxx index de2152337..522db5e1e 100644 --- a/test/run_output.cxx +++ b/test/run_output.cxx @@ -32,7 +32,7 @@ #include "fs/Path.hxx" #include "AudioParser.hxx" #include "pcm/PcmConvert.hxx" -#include "FilterRegistry.hxx" +#include "filter/FilterRegistry.hxx" #include "PlayerControl.hxx" #include "stdbin.h" #include "util/Error.hxx" -- cgit v1.2.3