diff options
Diffstat (limited to 'src/filter')
-rw-r--r-- | src/filter/FilterConfig.cxx | 80 | ||||
-rw-r--r-- | src/filter/FilterConfig.hxx | 43 | ||||
-rw-r--r-- | src/filter/FilterInternal.hxx | 71 | ||||
-rw-r--r-- | src/filter/FilterPlugin.cxx | 58 | ||||
-rw-r--r-- | src/filter/FilterPlugin.hxx | 67 | ||||
-rw-r--r-- | src/filter/FilterRegistry.cxx | 43 | ||||
-rw-r--r-- | src/filter/FilterRegistry.hxx | 43 | ||||
-rw-r--r-- | src/filter/plugins/AutoConvertFilterPlugin.cxx (renamed from src/filter/AutoConvertFilterPlugin.cxx) | 33 | ||||
-rw-r--r-- | src/filter/plugins/AutoConvertFilterPlugin.hxx (renamed from src/filter/AutoConvertFilterPlugin.hxx) | 2 | ||||
-rw-r--r-- | src/filter/plugins/ChainFilterPlugin.cxx (renamed from src/filter/ChainFilterPlugin.cxx) | 24 | ||||
-rw-r--r-- | src/filter/plugins/ChainFilterPlugin.hxx (renamed from src/filter/ChainFilterPlugin.hxx) | 2 | ||||
-rw-r--r-- | src/filter/plugins/ConvertFilterPlugin.cxx (renamed from src/filter/ConvertFilterPlugin.cxx) | 88 | ||||
-rw-r--r-- | src/filter/plugins/ConvertFilterPlugin.hxx (renamed from src/filter/ConvertFilterPlugin.hxx) | 8 | ||||
-rw-r--r-- | src/filter/plugins/NormalizeFilterPlugin.cxx (renamed from src/filter/NormalizeFilterPlugin.cxx) | 29 | ||||
-rw-r--r-- | src/filter/plugins/NullFilterPlugin.cxx (renamed from src/filter/NullFilterPlugin.cxx) | 15 | ||||
-rw-r--r-- | src/filter/plugins/ReplayGainFilterPlugin.cxx (renamed from src/filter/ReplayGainFilterPlugin.cxx) | 76 | ||||
-rw-r--r-- | src/filter/plugins/ReplayGainFilterPlugin.hxx (renamed from src/filter/ReplayGainFilterPlugin.hxx) | 2 | ||||
-rw-r--r-- | src/filter/plugins/RouteFilterPlugin.cxx (renamed from src/filter/RouteFilterPlugin.cxx) | 41 | ||||
-rw-r--r-- | src/filter/plugins/VolumeFilterPlugin.cxx (renamed from src/filter/VolumeFilterPlugin.cxx) | 78 | ||||
-rw-r--r-- | src/filter/plugins/VolumeFilterPlugin.hxx (renamed from src/filter/VolumeFilterPlugin.hxx) | 2 |
20 files changed, 583 insertions, 222 deletions
diff --git a/src/filter/FilterConfig.cxx b/src/filter/FilterConfig.cxx new file mode 100644 index 000000000..d8c1fc6c2 --- /dev/null +++ b/src/filter/FilterConfig.cxx @@ -0,0 +1,80 @@ +/* + * 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 <algorithm> + +#include <string.h> + +static bool +filter_chain_append_new(Filter &chain, const char *template_name, Error &error) +{ + const struct config_param *cfg = + config_find_block(CONF_AUDIO_FILTER, "name", template_name); + if (cfg == nullptr) { + error.Format(config_domain, + "filter template not found: %s", + template_name); + 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..d2e619540 --- /dev/null +++ b/src/filter/FilterInternal.hxx @@ -0,0 +1,71 @@ +/* + * 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 <stddef.h> + +struct AudioFormat; +class Error; +template<typename T> struct ConstBuffer; + +class Filter { +public: + virtual ~Filter() {} + + /** + * Opens the filter, preparing it for FilterPCM(). + * + * @param filter the filter object + * @param af 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 error location to store the error occurring, or nullptr + * to ignore errors. + * @return the destination buffer on success (will be + * invalidated by Close() or FilterPCM()), nullptr on + * error + */ + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, 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 <assert.h> + +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 <string.h> + +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/AutoConvertFilterPlugin.cxx b/src/filter/plugins/AutoConvertFilterPlugin.cxx index 918a16e53..8586cb86e 100644 --- a/src/filter/AutoConvertFilterPlugin.cxx +++ b/src/filter/plugins/AutoConvertFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,11 +20,12 @@ #include "config.h" #include "AutoConvertFilterPlugin.hxx" #include "ConvertFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" #include "AudioFormat.hxx" -#include "ConfigData.hxx" +#include "config/ConfigData.hxx" +#include "util/ConstBuffer.hxx" #include <assert.h> @@ -48,9 +49,8 @@ public: 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; + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + Error &error) override; }; AudioFormat @@ -88,7 +88,11 @@ AutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error) assert(audio_format2 == in_audio_format); - convert_filter_set(convert, child_audio_format); + if (!convert_filter_set(convert, child_audio_format, error)) { + delete convert; + filter->Close(); + return AudioFormat::Undefined(); + } } else /* no */ convert = nullptr; @@ -107,17 +111,16 @@ AutoConvertFilter::Close() filter->Close(); } -const void * -AutoConvertFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error) +ConstBuffer<void> +AutoConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error) { if (convert != nullptr) { - src = convert->FilterPCM(src, src_size, &src_size, error); - if (src == nullptr) + src = convert->FilterPCM(src, error); + if (src.IsNull()) return nullptr; } - return filter->FilterPCM(src, src_size, dest_size_r, error); + return filter->FilterPCM(src, error); } Filter * diff --git a/src/filter/AutoConvertFilterPlugin.hxx b/src/filter/plugins/AutoConvertFilterPlugin.hxx index 7db72a345..c5dfdd2f6 100644 --- a/src/filter/AutoConvertFilterPlugin.hxx +++ b/src/filter/plugins/AutoConvertFilterPlugin.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/filter/ChainFilterPlugin.cxx b/src/filter/plugins/ChainFilterPlugin.cxx index cb52b86ca..7342beb14 100644 --- a/src/filter/ChainFilterPlugin.cxx +++ b/src/filter/plugins/ChainFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,12 +19,13 @@ #include "config.h" #include "ChainFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.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 "util/ConstBuffer.hxx" #include <list> @@ -54,8 +55,8 @@ 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); + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + Error &error); private: /** @@ -143,21 +144,18 @@ ChainFilter::Close() child.filter->Close(); } -const void * -ChainFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error) +ConstBuffer<void> +ChainFilter::FilterPCM(ConstBuffer<void> src, 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) + src = child.filter->FilterPCM(src, error); + if (src.IsNull()) return nullptr; } /* return the output of the last filter */ - *dest_size_r = src_size; return src; } diff --git a/src/filter/ChainFilterPlugin.hxx b/src/filter/plugins/ChainFilterPlugin.hxx index 884c7ca19..b36aa3322 100644 --- a/src/filter/ChainFilterPlugin.hxx +++ b/src/filter/plugins/ChainFilterPlugin.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/filter/ConvertFilterPlugin.cxx b/src/filter/plugins/ConvertFilterPlugin.cxx index 040f8426f..5c6a07ba1 100644 --- a/src/filter/ConvertFilterPlugin.cxx +++ b/src/filter/plugins/ConvertFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,16 +19,16 @@ #include "config.h" #include "ConvertFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" #include "pcm/PcmConvert.hxx" #include "util/Manual.hxx" +#include "util/ConstBuffer.hxx" #include "AudioFormat.hxx" #include "poison.h" #include <assert.h> -#include <string.h> class ConvertFilter final : public Filter { /** @@ -39,27 +39,23 @@ class ConvertFilter final : public Filter { /** * The output audio format; the consumer of this plugin - * expects PCM data in this format. This defaults to - * #in_audio_format, and can be set with convert_filter_set(). + * 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<PcmConvert> state; public: - void Set(const AudioFormat &_out_audio_format) { - assert(in_audio_format.IsValid()); - assert(out_audio_format.IsValid()); - assert(_out_audio_format.IsValid()); - - out_audio_format = _out_audio_format; - } + 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; + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + Error &error) override; }; static Filter * @@ -69,12 +65,40 @@ convert_filter_init(gcc_unused const config_param ¶m, 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 = out_audio_format = audio_format; + in_audio_format = audio_format; + out_audio_format.Clear(); + state.Construct(); return in_audio_format; @@ -83,26 +107,27 @@ ConvertFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) 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) +ConstBuffer<void> +ConvertFilter::FilterPCM(ConstBuffer<void> src, Error &error) { - if (in_audio_format == out_audio_format) { + 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(in_audio_format, - src, src_size, - out_audio_format, dest_size_r, - error); + return state->Convert(src, error); } const struct filter_plugin convert_filter_plugin = { @@ -110,10 +135,11 @@ const struct filter_plugin convert_filter_plugin = { convert_filter_init, }; -void -convert_filter_set(Filter *_filter, const AudioFormat out_audio_format) +bool +convert_filter_set(Filter *_filter, AudioFormat out_audio_format, + Error &error) { ConvertFilter *filter = (ConvertFilter *)_filter; - filter->Set(out_audio_format); + return filter->Set(out_audio_format, error); } diff --git a/src/filter/ConvertFilterPlugin.hxx b/src/filter/plugins/ConvertFilterPlugin.hxx index c814aaf49..bb4673651 100644 --- a/src/filter/ConvertFilterPlugin.hxx +++ b/src/filter/plugins/ConvertFilterPlugin.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,7 @@ #define MPD_CONVERT_FILTER_PLUGIN_HXX class Filter; +class Error; struct AudioFormat; /** @@ -29,7 +30,8 @@ struct AudioFormat; * format switch is a violation of the filter API, this filter must be * the last in a chain. */ -void -convert_filter_set(Filter *filter, AudioFormat out_audio_format); +bool +convert_filter_set(Filter *filter, AudioFormat out_audio_format, + Error &error); #endif diff --git a/src/filter/NormalizeFilterPlugin.cxx b/src/filter/plugins/NormalizeFilterPlugin.cxx index 6c4f6b0e5..a69df2b81 100644 --- a/src/filter/NormalizeFilterPlugin.cxx +++ b/src/filter/plugins/NormalizeFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -18,14 +18,14 @@ */ #include "config.h" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" #include "pcm/PcmBuffer.hxx" #include "AudioFormat.hxx" #include "AudioCompress/compress.h" +#include "util/ConstBuffer.hxx" -#include <assert.h> #include <string.h> class NormalizeFilter final : public Filter { @@ -36,8 +36,8 @@ class NormalizeFilter final : public Filter { 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); + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + Error &error) override; }; static Filter * @@ -64,17 +64,14 @@ NormalizeFilter::Close() Compressor_delete(compressor); } -const void * -NormalizeFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, gcc_unused Error &error) +ConstBuffer<void> +NormalizeFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error) { - int16_t *dest = (int16_t *)buffer.Get(src_size); - memcpy(dest, src, src_size); + int16_t *dest = (int16_t *)buffer.Get(src.size); + memcpy(dest, src.data, src.size); - Compressor_Process_int16(compressor, dest, src_size / 2); - - *dest_size_r = src_size; - return dest; + Compressor_Process_int16(compressor, dest, src.size / 2); + return { (const void *)dest, src.size }; } const struct filter_plugin normalize_filter_plugin = { diff --git a/src/filter/NullFilterPlugin.cxx b/src/filter/plugins/NullFilterPlugin.cxx index c762592f6..ebd8e4ec5 100644 --- a/src/filter/NullFilterPlugin.cxx +++ b/src/filter/plugins/NullFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -25,11 +25,12 @@ */ #include "config.h" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "filter/FilterRegistry.hxx" #include "AudioFormat.hxx" #include "Compiler.h" +#include "util/ConstBuffer.hxx" class NullFilter final : public Filter { public: @@ -40,10 +41,8 @@ public: 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; + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + gcc_unused Error &error) override { return src; } }; diff --git a/src/filter/ReplayGainFilterPlugin.cxx b/src/filter/plugins/ReplayGainFilterPlugin.cxx index b2dcde4cc..651352ac9 100644 --- a/src/filter/ReplayGainFilterPlugin.cxx +++ b/src/filter/plugins/ReplayGainFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,15 +19,16 @@ #include "config.h" #include "ReplayGainFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.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/PcmVolume.hxx" +#include "mixer/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" @@ -55,8 +56,8 @@ class ReplayGainFilter final : public Filter { ReplayGainInfo info; /** - * The current volume, between 0 and a value that may or may not exceed - * #PCM_VOLUME_1. + * 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. @@ -66,16 +67,11 @@ class ReplayGainFilter final : public Filter { * maintain a consistent audio level. Whether clipping will actually * occur depends on what value the user is using for replaygain_preamp. */ - unsigned volume; - - AudioFormat format; - - PcmBuffer buffer; + PcmVolume pv; public: ReplayGainFilter() - :mixer(nullptr), mode(REPLAY_GAIN_OFF), - volume(PCM_VOLUME_1) { + :mixer(nullptr), mode(REPLAY_GAIN_OFF) { info.Clear(); } @@ -118,13 +114,14 @@ 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); + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + Error &error) override; }; 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, @@ -134,8 +131,9 @@ ReplayGainFilter::Update() "scale=%f\n", (double)scale); volume = pcm_float_to_volume(scale); - } else - volume = PCM_VOLUME_1; + } + + pv.SetVolume(volume); if (mixer != nullptr) { /* update the hardware mixer volume */ @@ -160,48 +158,22 @@ replay_gain_filter_init(gcc_unused const config_param ¶m, AudioFormat ReplayGainFilter::Open(AudioFormat &af, gcc_unused Error &error) { - format = af; + if (!pv.Open(af.format, error)) + return AudioFormat::Undefined(); - return format; + return af; } void ReplayGainFilter::Close() { - buffer.Clear(); + pv.Close(); } -const void * -ReplayGainFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error) +ConstBuffer<void> +ReplayGainFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error) { - - *dest_size_r = src_size; - - if (volume == PCM_VOLUME_1) - /* optimized special case: 100% volume = no-op */ - return src; - - void *dest = buffer.Get(src_size); - if (volume <= 0) { - /* optimized special case: 0% volume = memset(0) */ - /* XXX is this valid for all sample formats? What - about floating point? */ - memset(dest, 0, src_size); - return dest; - } - - memcpy(dest, src, src_size); - - bool success = pcm_volume(dest, src_size, - format.format, - volume); - if (!success) { - error.Set(replay_gain_domain, "pcm_volume() has failed"); - return nullptr; - } - - return dest; + return pv.Apply(src); } const struct filter_plugin replay_gain_filter_plugin = { diff --git a/src/filter/ReplayGainFilterPlugin.hxx b/src/filter/plugins/ReplayGainFilterPlugin.hxx index fbd1f2712..346541b97 100644 --- a/src/filter/ReplayGainFilterPlugin.hxx +++ b/src/filter/plugins/ReplayGainFilterPlugin.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify diff --git a/src/filter/RouteFilterPlugin.cxx b/src/filter/plugins/RouteFilterPlugin.cxx index d9042c21f..a252af97d 100644 --- a/src/filter/RouteFilterPlugin.cxx +++ b/src/filter/plugins/RouteFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -40,16 +40,16 @@ */ #include "config.h" -#include "ConfigError.hxx" -#include "ConfigData.hxx" +#include "config/ConfigError.hxx" +#include "config/ConfigData.hxx" #include "AudioFormat.hxx" -#include "CheckAudioFormat.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.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 "util/ConstBuffer.hxx" #include <algorithm> @@ -122,8 +122,8 @@ 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); + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + Error &error) override; }; bool @@ -143,11 +143,11 @@ RouteFilter::Configure(const config_param ¶m, Error &error) { // A cowardly default, just passthrough stereo const char *routes = param.GetBlockValue("routes", "0>0, 1>1"); while (true) { - routes = strchug_fast(routes); + routes = StripLeft(routes); char *endptr; const unsigned source = strtoul(routes, &endptr, 10); - endptr = strchug_fast(endptr); + endptr = StripLeft(endptr); if (endptr == routes || *endptr != '>') { error.Set(config_domain, "Malformed 'routes' specification"); @@ -164,10 +164,10 @@ RouteFilter::Configure(const config_param ¶m, Error &error) { if (source >= min_input_channels) min_input_channels = source + 1; - routes = strchug_fast(endptr + 1); + routes = StripLeft(endptr + 1); unsigned dest = strtoul(routes, &endptr, 10); - endptr = strchug_fast(endptr); + endptr = StripLeft(endptr); if (endptr == routes) { error.Set(config_domain, "Malformed 'routes' specification"); @@ -239,20 +239,19 @@ 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) +ConstBuffer<void> +RouteFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error) { - size_t number_of_frames = src_size / input_frame_size; + 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; + const uint8_t *base_source = (const uint8_t *)src.data; // 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); + const size_t result_size = number_of_frames * output_frame_size; + void *const result = output_buffer.Get(result_size); // 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; @@ -288,7 +287,7 @@ RouteFilter::FilterPCM(const void *src, size_t src_size, } // Here it is, ladies and gentlemen! Rerouted data! - return result; + return { result, result_size }; } const struct filter_plugin route_filter_plugin = { diff --git a/src/filter/VolumeFilterPlugin.cxx b/src/filter/plugins/VolumeFilterPlugin.cxx index 1b663f6eb..7b6ccc51e 100644 --- a/src/filter/VolumeFilterPlugin.cxx +++ b/src/filter/plugins/VolumeFilterPlugin.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,12 +19,12 @@ #include "config.h" #include "VolumeFilterPlugin.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "FilterRegistry.hxx" -#include "pcm/PcmVolume.hxx" -#include "pcm/PcmBuffer.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" @@ -32,35 +32,21 @@ #include <string.h> class VolumeFilter final : public Filter { - /** - * The current volume, from 0 to #PCM_VOLUME_1. - */ - unsigned volume; - - AudioFormat format; - - PcmBuffer buffer; + PcmVolume pv; public: - VolumeFilter() - :volume(PCM_VOLUME_1) {} - unsigned GetVolume() const { - assert(volume <= PCM_VOLUME_1); - - return volume; + return pv.GetVolume(); } void SetVolume(unsigned _volume) { - assert(_volume <= PCM_VOLUME_1); - - volume = _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); + virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src, + Error &error) override; }; static constexpr Domain volume_domain("pcm_volume"); @@ -73,50 +59,24 @@ volume_filter_init(gcc_unused const config_param ¶m, } AudioFormat -VolumeFilter::Open(AudioFormat &audio_format, gcc_unused Error &error) +VolumeFilter::Open(AudioFormat &audio_format, Error &error) { - format = audio_format; + if (!pv.Open(audio_format.format, error)) + return AudioFormat::Undefined(); - return format; + return audio_format; } void VolumeFilter::Close() { - buffer.Clear(); + pv.Close(); } -const void * -VolumeFilter::FilterPCM(const void *src, size_t src_size, - size_t *dest_size_r, Error &error) +ConstBuffer<void> +VolumeFilter::FilterPCM(ConstBuffer<void> src, gcc_unused Error &error) { - *dest_size_r = src_size; - - if (volume >= PCM_VOLUME_1) - /* optimized special case: 100% volume = no-op */ - return src; - - void *dest = buffer.Get(src_size); - - if (volume <= 0) { - /* optimized special case: 0% volume = memset(0) */ - /* XXX is this valid for all sample formats? What - about floating point? */ - memset(dest, 0, src_size); - return dest; - } - - memcpy(dest, src, src_size); - - bool success = pcm_volume(dest, src_size, - format.format, - volume); - if (!success) { - error.Set(volume_domain, "pcm_volume() has failed"); - return NULL; - } - - return dest; + return pv.Apply(src); } const struct filter_plugin volume_filter_plugin = { diff --git a/src/filter/VolumeFilterPlugin.hxx b/src/filter/plugins/VolumeFilterPlugin.hxx index 822b7e93a..b5317dc6f 100644 --- a/src/filter/VolumeFilterPlugin.hxx +++ b/src/filter/plugins/VolumeFilterPlugin.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify |