aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2013-02-01 18:40:36 +0100
committerMax Kellermann <max@duempel.org>2013-02-02 09:34:07 +0100
commita9ce0218c1879a752c9d9ec6ef21fcf44eab51ab (patch)
treef30de05c9f0a45906d31d2d4a3dad2281fe8d49c /src
parent7bb5a960fde46363adf888db5b05b7b883d2b16b (diff)
downloadmpd-a9ce0218c1879a752c9d9ec6ef21fcf44eab51ab.tar.gz
mpd-a9ce0218c1879a752c9d9ec6ef21fcf44eab51ab.tar.xz
mpd-a9ce0218c1879a752c9d9ec6ef21fcf44eab51ab.zip
FilterInternal: convert struct filter to a OO interface
Diffstat (limited to 'src')
-rw-r--r--src/FilterConfig.cxx15
-rw-r--r--src/FilterConfig.hxx4
-rw-r--r--src/FilterInternal.hxx49
-rw-r--r--src/FilterPlugin.cxx58
-rw-r--r--src/FilterPlugin.hxx87
-rw-r--r--src/OutputFinish.cxx12
-rw-r--r--src/OutputInit.cxx14
-rw-r--r--src/OutputThread.cxx42
-rw-r--r--src/filter/AutoConvertFilterPlugin.cxx127
-rw-r--r--src/filter/AutoConvertFilterPlugin.hxx6
-rw-r--r--src/filter/ChainFilterPlugin.cxx143
-rw-r--r--src/filter/ChainFilterPlugin.hxx6
-rw-r--r--src/filter/ConvertFilterPlugin.cxx101
-rw-r--r--src/filter/ConvertFilterPlugin.hxx5
-rw-r--r--src/filter/NormalizeFilterPlugin.cxx69
-rw-r--r--src/filter/NullFilterPlugin.cxx68
-rw-r--r--src/filter/ReplayGainFilterPlugin.cxx189
-rw-r--r--src/filter/ReplayGainFilterPlugin.hxx9
-rw-r--r--src/filter/RouteFilterPlugin.cxx161
-rw-r--r--src/filter/VolumeFilterPlugin.cxx109
-rw-r--r--src/filter/VolumeFilterPlugin.hxx6
-rw-r--r--src/mixer/SoftwareMixerPlugin.cxx4
-rw-r--r--src/mixer/SoftwareMixerPlugin.hxx4
-rw-r--r--src/output_internal.h14
24 files changed, 515 insertions, 787 deletions
diff --git a/src/FilterConfig.cxx b/src/FilterConfig.cxx
index 7fca2ae67..e56c5a988 100644
--- a/src/FilterConfig.cxx
+++ b/src/FilterConfig.cxx
@@ -78,7 +78,7 @@ filter_plugin_config(const char *filter_template_name, GError **error_r)
* @return the number of filters which were successfully added
*/
unsigned int
-filter_chain_parse(struct filter *chain, const char *spec, GError **error_r)
+filter_chain_parse(Filter &chain, const char *spec, GError **error_r)
{
// Split on comma
@@ -89,26 +89,27 @@ filter_chain_parse(struct filter *chain, const char *spec, GError **error_r)
// Add each name to the filter chain by instantiating an actual filter
char **template_names = tokens;
while (*template_names != NULL) {
- struct filter *f;
- const struct config_param *cfg;
-
// Squeeze whitespace
g_strstrip(*template_names);
- cfg = filter_plugin_config(*template_names, error_r);
+ const struct config_param *cfg =
+ filter_plugin_config(*template_names, error_r);
if (cfg == NULL) {
// The error has already been set, just stop.
break;
}
// Instantiate one of those filter plugins with the template name as a hint
- f = filter_configured_new(cfg, error_r);
+ Filter *f = filter_configured_new(cfg, error_r);
if (f == NULL) {
// The error has already been set, just stop.
break;
}
- filter_chain_append(chain, f);
+ const char *plugin_name =
+ config_get_block_string(cfg, "plugin", "unknown");
+
+ filter_chain_append(chain, plugin_name, f);
++added_filters;
++template_names;
diff --git a/src/FilterConfig.hxx b/src/FilterConfig.hxx
index 18cc5c44f..bad186354 100644
--- a/src/FilterConfig.hxx
+++ b/src/FilterConfig.hxx
@@ -27,7 +27,7 @@
#include "gerror.h"
-struct filter;
+class Filter;
/**
* Builds a filter chain from a configuration string on the form
@@ -39,6 +39,6 @@ struct filter;
* @return the number of filters which were successfully added
*/
unsigned int
-filter_chain_parse(struct filter *chain, const char *spec, GError **error_r);
+filter_chain_parse(Filter &chain, const char *spec, GError **error_r);
#endif
diff --git a/src/FilterInternal.hxx b/src/FilterInternal.hxx
index 7ffcec334..cdc2d0ea1 100644
--- a/src/FilterInternal.hxx
+++ b/src/FilterInternal.hxx
@@ -25,14 +25,47 @@
#ifndef MPD_FILTER_INTERNAL_HXX
#define MPD_FILTER_INTERNAL_HXX
-struct filter {
- const struct filter_plugin *plugin;
-};
+struct audio_format;
+
+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 NULL
+ * to ignore errors.
+ * @return the format of outgoing data
+ */
+ virtual const audio_format *Open(audio_format &af,
+ GError **error_r) = 0;
-static inline void
-filter_init(struct filter *filter, const struct filter_plugin *plugin)
-{
- filter->plugin = plugin;
-}
+ /**
+ * 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 NULL
+ * to ignore errors.
+ * @return the destination buffer on success (will be
+ * invalidated by filter_close() or filter_filter()), NULL on
+ * error
+ */
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r,
+ GError **error_r) = 0;
+};
#endif
diff --git a/src/FilterPlugin.cxx b/src/FilterPlugin.cxx
index f1f7561a9..953f404ed 100644
--- a/src/FilterPlugin.cxx
+++ b/src/FilterPlugin.cxx
@@ -24,13 +24,9 @@
#include "conf.h"
#include "ConfigQuark.hxx"
-#ifndef NDEBUG
-#include "audio_format.h"
-#endif
-
#include <assert.h>
-struct filter *
+Filter *
filter_new(const struct filter_plugin *plugin,
const struct config_param *param, GError **error_r)
{
@@ -40,7 +36,7 @@ filter_new(const struct filter_plugin *plugin,
return plugin->init(param, error_r);
}
-struct filter *
+Filter *
filter_configured_new(const struct config_param *param, GError **error_r)
{
const char *plugin_name;
@@ -65,53 +61,3 @@ filter_configured_new(const struct config_param *param, GError **error_r)
return filter_new(plugin, param, error_r);
}
-
-void
-filter_free(struct filter *filter)
-{
- assert(filter != NULL);
-
- filter->plugin->finish(filter);
-}
-
-const struct audio_format *
-filter_open(struct filter *filter, struct audio_format *audio_format,
- GError **error_r)
-{
- const struct audio_format *out_audio_format;
-
- assert(filter != NULL);
- assert(audio_format != NULL);
- assert(audio_format_valid(audio_format));
- assert(error_r == NULL || *error_r == NULL);
-
- out_audio_format = filter->plugin->open(filter, audio_format, error_r);
-
- assert(out_audio_format == NULL || audio_format_valid(audio_format));
- assert(out_audio_format == NULL ||
- audio_format_valid(out_audio_format));
-
- return out_audio_format;
-}
-
-void
-filter_close(struct filter *filter)
-{
- assert(filter != NULL);
-
- filter->plugin->close(filter);
-}
-
-const void *
-filter_filter(struct filter *filter, const void *src, size_t src_size,
- size_t *dest_size_r,
- GError **error_r)
-{
- assert(filter != NULL);
- assert(src != NULL);
- assert(src_size > 0);
- assert(dest_size_r != NULL);
- assert(error_r == NULL || *error_r == NULL);
-
- return filter->plugin->filter(filter, src, src_size, dest_size_r, error_r);
-}
diff --git a/src/FilterPlugin.hxx b/src/FilterPlugin.hxx
index 6476a621f..80bb8a0b6 100644
--- a/src/FilterPlugin.hxx
+++ b/src/FilterPlugin.hxx
@@ -31,7 +31,7 @@
#include <stddef.h>
struct config_param;
-struct filter;
+class Filter;
struct filter_plugin {
const char *name;
@@ -39,38 +39,7 @@ struct filter_plugin {
/**
* Allocates and configures a filter.
*/
- struct filter *(*init)(const struct config_param *param,
- GError **error_r);
-
- /**
- * Free instance data.
- */
- void (*finish)(struct filter *filter);
-
- /**
- * Opens a filter.
- *
- * @param audio_format the audio format of incoming data; the
- * plugin may modify the object to enforce another input
- * format
- */
- const struct audio_format *
- (*open)(struct filter *filter,
- struct audio_format *audio_format,
- GError **error_r);
-
- /**
- * Closes a filter.
- */
- void (*close)(struct filter *filter);
-
- /**
- * Filters a block of PCM data.
- */
- const void *(*filter)(struct filter *filter,
- const void *src, size_t src_size,
- size_t *dest_buffer_r,
- GError **error_r);
+ Filter *(*init)(const struct config_param *param, GError **error_r);
};
/**
@@ -82,7 +51,7 @@ struct filter_plugin {
* ignore errors.
* @return a new filter object, or NULL on error
*/
-struct filter *
+Filter *
filter_new(const struct filter_plugin *plugin,
const struct config_param *param, GError **error_r);
@@ -95,55 +64,7 @@ filter_new(const struct filter_plugin *plugin,
* ignore errors.
* @return a new filter object, or NULL on error
*/
-struct filter *
+Filter *
filter_configured_new(const struct config_param *param, GError **error_r);
-/**
- * Deletes a filter. It must be closed prior to calling this
- * function, see filter_close().
- *
- * @param filter the filter object
- */
-void
-filter_free(struct filter *filter);
-
-/**
- * Opens the filter, preparing it for filter_filter().
- *
- * @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 NULL to
- * ignore errors.
- * @return the format of outgoing data
- */
-const struct audio_format *
-filter_open(struct filter *filter, struct audio_format *audio_format,
- GError **error_r);
-
-/**
- * Closes the filter. After that, you may call filter_open() again.
- *
- * @param filter the filter object
- */
-void
-filter_close(struct filter *filter);
-
-/**
- * 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 NULL to
- * ignore errors.
- * @return the destination buffer on success (will be invalidated by
- * filter_close() or filter_filter()), NULL on error
- */
-const void *
-filter_filter(struct filter *filter, const void *src, size_t src_size,
- size_t *dest_size_r,
- GError **error_r);
-
#endif
diff --git a/src/OutputFinish.cxx b/src/OutputFinish.cxx
index f5a1f9921..8b9480b88 100644
--- a/src/OutputFinish.cxx
+++ b/src/OutputFinish.cxx
@@ -25,7 +25,7 @@ extern "C" {
#include "mixer_control.h"
}
-#include "FilterPlugin.hxx"
+#include "FilterInternal.hxx"
#include <assert.h>
@@ -42,13 +42,9 @@ ao_base_finish(struct audio_output *ao)
g_cond_free(ao->cond);
g_mutex_free(ao->mutex);
- if (ao->replay_gain_filter != NULL)
- filter_free(ao->replay_gain_filter);
-
- if (ao->other_replay_gain_filter != NULL)
- filter_free(ao->other_replay_gain_filter);
-
- filter_free(ao->filter);
+ delete ao->replay_gain_filter;
+ delete ao->other_replay_gain_filter;
+ delete ao->filter;
pcm_buffer_deinit(&ao->cross_fade_buffer);
}
diff --git a/src/OutputInit.cxx b/src/OutputInit.cxx
index 5acb8c6cb..8c60fe4f1 100644
--- a/src/OutputInit.cxx
+++ b/src/OutputInit.cxx
@@ -100,7 +100,7 @@ static struct mixer *
audio_output_load_mixer(struct audio_output *ao,
const struct config_param *param,
const struct mixer_plugin *plugin,
- struct filter *filter_chain,
+ Filter &filter_chain,
GError **error_r)
{
struct mixer *mixer;
@@ -120,7 +120,7 @@ audio_output_load_mixer(struct audio_output *ao,
mixer = mixer_new(&software_mixer_plugin, NULL, NULL, NULL);
assert(mixer != NULL);
- filter_chain_append(filter_chain,
+ filter_chain_append(filter_chain, "software_mixer",
software_mixer_get_filter(mixer));
return mixer;
}
@@ -190,15 +190,15 @@ ao_base_init(struct audio_output *ao,
/* create the normalization filter (if configured) */
if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) {
- struct filter *normalize_filter =
+ Filter *normalize_filter =
filter_new(&normalize_filter_plugin, NULL, NULL);
assert(normalize_filter != NULL);
- filter_chain_append(ao->filter,
+ filter_chain_append(*ao->filter, "normalize",
autoconvert_filter_new(normalize_filter));
}
- filter_chain_parse(ao->filter,
+ filter_chain_parse(*ao->filter,
config_get_block_string(param, AUDIO_FILTERS, ""),
&error
);
@@ -258,7 +258,7 @@ audio_output_setup(struct audio_output *ao, const struct config_param *param,
GError *error = NULL;
ao->mixer = audio_output_load_mixer(ao, param,
ao->plugin->mixer_plugin,
- ao->filter, &error);
+ *ao->filter, &error);
if (ao->mixer == NULL && error != NULL) {
g_warning("Failed to initialize hardware mixer for '%s': %s",
ao->name, error->message);
@@ -285,7 +285,7 @@ audio_output_setup(struct audio_output *ao, const struct config_param *param,
ao->convert_filter = filter_new(&convert_filter_plugin, NULL, NULL);
assert(ao->convert_filter != NULL);
- filter_chain_append(ao->filter, ao->convert_filter);
+ filter_chain_append(*ao->filter, "convert", ao->convert_filter);
return true;
}
diff --git a/src/OutputThread.cxx b/src/OutputThread.cxx
index e3efbceaa..f1ffe876f 100644
--- a/src/OutputThread.cxx
+++ b/src/OutputThread.cxx
@@ -27,7 +27,7 @@ extern "C" {
}
#include "notify.hxx"
-#include "FilterPlugin.hxx"
+#include "FilterInternal.hxx"
#include "filter/ConvertFilterPlugin.hxx"
#include "filter/ReplayGainFilterPlugin.hxx"
#include "PlayerControl.hxx"
@@ -98,26 +98,24 @@ ao_disable(struct audio_output *ao)
}
static const struct audio_format *
-ao_filter_open(struct audio_output *ao,
- struct audio_format *audio_format,
+ao_filter_open(struct audio_output *ao, audio_format &format,
GError **error_r)
{
- assert(audio_format_valid(audio_format));
+ assert(audio_format_valid(&format));
/* the replay_gain filter cannot fail here */
if (ao->replay_gain_filter != NULL)
- filter_open(ao->replay_gain_filter, audio_format, error_r);
+ ao->replay_gain_filter->Open(format, error_r);
if (ao->other_replay_gain_filter != NULL)
- filter_open(ao->other_replay_gain_filter, audio_format,
- error_r);
+ ao->other_replay_gain_filter->Open(format, error_r);
const struct audio_format *af
- = filter_open(ao->filter, audio_format, error_r);
+ = ao->filter->Open(format, error_r);
if (af == NULL) {
if (ao->replay_gain_filter != NULL)
- filter_close(ao->replay_gain_filter);
+ ao->replay_gain_filter->Close();
if (ao->other_replay_gain_filter != NULL)
- filter_close(ao->other_replay_gain_filter);
+ ao->other_replay_gain_filter->Close();
}
return af;
@@ -127,11 +125,11 @@ static void
ao_filter_close(struct audio_output *ao)
{
if (ao->replay_gain_filter != NULL)
- filter_close(ao->replay_gain_filter);
+ ao->replay_gain_filter->Close();
if (ao->other_replay_gain_filter != NULL)
- filter_close(ao->other_replay_gain_filter);
+ ao->other_replay_gain_filter->Close();
- filter_close(ao->filter);
+ ao->filter->Close();
}
static void
@@ -139,7 +137,6 @@ ao_open(struct audio_output *ao)
{
bool success;
GError *error = NULL;
- const struct audio_format *filter_audio_format;
struct audio_format_string af_string;
assert(!ao->open);
@@ -164,7 +161,8 @@ ao_open(struct audio_output *ao)
/* open the filter */
- filter_audio_format = ao_filter_open(ao, &ao->in_audio_format, &error);
+ const audio_format *filter_audio_format =
+ ao_filter_open(ao, ao->in_audio_format, &error);
if (filter_audio_format == NULL) {
g_warning("Failed to open filter for \"%s\" [%s]: %s",
ao->name, ao->plugin->name, error->message);
@@ -196,7 +194,7 @@ ao_open(struct audio_output *ao)
return;
}
- convert_filter_set(ao->convert_filter, &ao->out_audio_format);
+ convert_filter_set(ao->convert_filter, ao->out_audio_format);
ao->open = true;
@@ -244,7 +242,7 @@ ao_reopen_filter(struct audio_output *ao)
GError *error = NULL;
ao_filter_close(ao);
- filter_audio_format = ao_filter_open(ao, &ao->in_audio_format, &error);
+ filter_audio_format = ao_filter_open(ao, ao->in_audio_format, &error);
if (filter_audio_format == NULL) {
g_warning("Failed to open filter for \"%s\" [%s]: %s",
ao->name, ao->plugin->name, error->message);
@@ -267,7 +265,7 @@ ao_reopen_filter(struct audio_output *ao)
return;
}
- convert_filter_set(ao->convert_filter, &ao->out_audio_format);
+ convert_filter_set(ao->convert_filter, ao->out_audio_format);
}
static void
@@ -322,7 +320,7 @@ ao_wait(struct audio_output *ao)
static const void *
ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
- struct filter *replay_gain_filter,
+ Filter *replay_gain_filter,
unsigned *replay_gain_serial_p,
size_t *length_r)
{
@@ -347,8 +345,8 @@ ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
}
GError *error = NULL;
- data = filter_filter(replay_gain_filter, data, length,
- &length, &error);
+ data = replay_gain_filter->FilterPCM(data, length,
+ &length, &error);
if (data == NULL) {
g_warning("\"%s\" [%s] failed to filter: %s",
ao->name, ao->plugin->name, error->message);
@@ -421,7 +419,7 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
/* apply filter chain */
- data = filter_filter(ao->filter, data, length, &length, &error);
+ data = ao->filter->FilterPCM(data, length, &length, &error);
if (data == NULL) {
g_warning("\"%s\" [%s] failed to filter: %s",
ao->name, ao->plugin->name, error->message);
diff --git a/src/filter/AutoConvertFilterPlugin.cxx b/src/filter/AutoConvertFilterPlugin.cxx
index 2a183b579..55ee46948 100644
--- a/src/filter/AutoConvertFilterPlugin.cxx
+++ b/src/filter/AutoConvertFilterPlugin.cxx
@@ -27,143 +27,106 @@
#include <assert.h>
-struct AutoConvertFilter {
- struct filter base;
-
+class AutoConvertFilter final : public Filter {
/**
* The audio format being fed to the underlying filter. This
* plugin actually doesn't need this variable, we have it here
* just so our open() method doesn't return a stack pointer.
*/
- struct audio_format in_audio_format;
+ audio_format child_audio_format;
/**
* The underlying filter.
*/
- struct filter *filter;
+ Filter *filter;
/**
* A convert_filter, just in case conversion is needed. nullptr
* if unused.
*/
- struct filter *convert;
-
- AutoConvertFilter(const filter_plugin &plugin, struct filter *_filter)
- :filter(_filter) {
- filter_init(&base, &plugin);
- }
+ Filter *convert;
+public:
+ AutoConvertFilter(Filter *_filter):filter(_filter) {}
~AutoConvertFilter() {
- filter_free(filter);
+ delete filter;
}
-};
-static void
-autoconvert_filter_finish(struct filter *_filter)
-{
- AutoConvertFilter *filter = (AutoConvertFilter *)_filter;
-
- delete filter;
-}
+ virtual const audio_format *Open(audio_format &af, GError **error_r);
+ virtual void Close();
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r);
+};
-static const struct audio_format *
-autoconvert_filter_open(struct filter *_filter,
- struct audio_format *in_audio_format,
- GError **error_r)
+const struct audio_format *
+AutoConvertFilter::Open(audio_format &in_audio_format, GError **error_r)
{
- AutoConvertFilter *filter = (AutoConvertFilter *)_filter;
- const struct audio_format *out_audio_format;
-
- assert(audio_format_valid(in_audio_format));
+ assert(audio_format_valid(&in_audio_format));
/* open the "real" filter */
- filter->in_audio_format = *in_audio_format;
-
- out_audio_format = filter_open(filter->filter,
- &filter->in_audio_format, error_r);
+ child_audio_format = in_audio_format;
+ const audio_format *out_audio_format =
+ filter->Open(child_audio_format, error_r);
if (out_audio_format == nullptr)
return nullptr;
/* need to convert? */
- if (!audio_format_equals(&filter->in_audio_format, in_audio_format)) {
+ if (!audio_format_equals(&child_audio_format, &in_audio_format)) {
/* yes - create a convert_filter */
- struct audio_format audio_format2 = *in_audio_format;
- const struct audio_format *audio_format3;
- filter->convert = filter_new(&convert_filter_plugin, nullptr,
- error_r);
- if (filter->convert == nullptr) {
- filter_close(filter->filter);
+ convert = filter_new(&convert_filter_plugin, nullptr, error_r);
+ if (convert == nullptr) {
+ filter->Close();
return nullptr;
}
- audio_format3 = filter_open(filter->convert, &audio_format2,
- error_r);
+ audio_format audio_format2 = in_audio_format;
+ const audio_format *audio_format3 =
+ convert->Open(audio_format2, error_r);
if (audio_format3 == nullptr) {
- filter_free(filter->convert);
- filter_close(filter->filter);
+ delete convert;
+ filter->Close();
return nullptr;
}
- assert(audio_format_equals(&audio_format2, in_audio_format));
+ assert(audio_format_equals(&audio_format2, &in_audio_format));
- convert_filter_set(filter->convert, &filter->in_audio_format);
+ convert_filter_set(convert, child_audio_format);
} else
/* no */
- filter->convert = nullptr;
+ convert = nullptr;
return out_audio_format;
}
-static void
-autoconvert_filter_close(struct filter *_filter)
+void
+AutoConvertFilter::Close()
{
- AutoConvertFilter *filter =
- (AutoConvertFilter *)_filter;
-
- if (filter->convert != nullptr) {
- filter_close(filter->convert);
- filter_free(filter->convert);
+ if (convert != nullptr) {
+ convert->Close();
+ delete convert;
}
- filter_close(filter->filter);
+ filter->Close();
}
-static const void *
-autoconvert_filter_filter(struct filter *_filter, const void *src,
- size_t src_size, size_t *dest_size_r,
- GError **error_r)
+const void *
+AutoConvertFilter::FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r)
{
- AutoConvertFilter *filter = (AutoConvertFilter *)_filter;
-
- if (filter->convert != nullptr) {
- src = filter_filter(filter->convert, src, src_size, &src_size,
- error_r);
+ if (convert != nullptr) {
+ src = convert->FilterPCM(src, src_size, &src_size, error_r);
if (src == nullptr)
return nullptr;
}
- return filter_filter(filter->filter, src, src_size, dest_size_r,
- error_r);
+ return filter->FilterPCM(src, src_size, dest_size_r, error_r);
}
-static const struct filter_plugin autoconvert_filter_plugin = {
- "convert",
- nullptr,
- autoconvert_filter_finish,
- autoconvert_filter_open,
- autoconvert_filter_close,
- autoconvert_filter_filter,
-};
-
-struct filter *
-autoconvert_filter_new(struct filter *_filter)
+Filter *
+autoconvert_filter_new(Filter *filter)
{
- AutoConvertFilter *filter =
- new AutoConvertFilter(autoconvert_filter_plugin,
- _filter);
-
- return &filter->base;
+ return new AutoConvertFilter(filter);
}
diff --git a/src/filter/AutoConvertFilterPlugin.hxx b/src/filter/AutoConvertFilterPlugin.hxx
index 062efcbd0..7db72a345 100644
--- a/src/filter/AutoConvertFilterPlugin.hxx
+++ b/src/filter/AutoConvertFilterPlugin.hxx
@@ -20,7 +20,7 @@
#ifndef MPD_AUTOCONVERT_FILTER_PLUGIN_HXX
#define MPD_AUTOCONVERT_FILTER_PLUGIN_HXX
-struct filter;
+class Filter;
/**
* Creates a new "autoconvert" filter. When opened, it ensures that
@@ -28,7 +28,7 @@ struct filter;
* requests a different format, it automatically creates a
* convert_filter.
*/
-struct filter *
-autoconvert_filter_new(struct filter *filter);
+Filter *
+autoconvert_filter_new(Filter *filter);
#endif
diff --git a/src/filter/ChainFilterPlugin.cxx b/src/filter/ChainFilterPlugin.cxx
index b232d6568..c8666615f 100644
--- a/src/filter/ChainFilterPlugin.cxx
+++ b/src/filter/ChainFilterPlugin.cxx
@@ -31,20 +31,39 @@
#include <assert.h>
-struct ChainFilter {
- /** the base class */
- struct filter base;
+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;
+ }
- std::list<struct filter *> children;
+ Child(const Child &) = delete;
+ Child &operator=(const Child &) = delete;
+ };
- ChainFilter() {
- filter_init(&base, &chain_filter_plugin);
- }
+ std::list<Child> children;
- ~ChainFilter() {
- for (auto i : children)
- filter_free(i);
+public:
+ void Append(const char *name, Filter *filter) {
+ children.emplace_back(name, filter);
}
+
+ virtual const audio_format *Open(audio_format &af, GError **error_r);
+ virtual void Close();
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r);
+
+private:
+ /**
+ * Close all filters in the chain until #until is reached.
+ * #until itself is not closed.
+ */
+ void CloseUntil(const Filter *until);
};
static inline GQuark
@@ -53,37 +72,23 @@ filter_quark(void)
return g_quark_from_static_string("filter");
}
-static struct filter *
+static Filter *
chain_filter_init(gcc_unused const struct config_param *param,
gcc_unused GError **error_r)
{
- ChainFilter *chain = new ChainFilter();
-
- return &chain->base;
-}
-
-static void
-chain_filter_finish(struct filter *_filter)
-{
- ChainFilter *chain = (ChainFilter *)_filter;
-
- delete chain;
+ return new ChainFilter();
}
-/**
- * Close all filters in the chain until #until is reached. #until
- * itself is not closed.
- */
-static void
-chain_close_until(ChainFilter *chain, const struct filter *until)
+void
+ChainFilter::CloseUntil(const Filter *until)
{
- for (auto filter : chain->children) {
- if (filter == until)
+ for (auto &child : children) {
+ if (child.filter == until)
/* don't close this filter */
return;
/* close this filter */
- filter_close(filter);
+ child.filter->Close();
}
/* this assertion fails if #until does not exist (anymore) */
@@ -91,43 +96,41 @@ chain_close_until(ChainFilter *chain, const struct filter *until)
}
static const struct audio_format *
-chain_open_child(struct filter *filter,
- const struct audio_format *prev_audio_format,
+chain_open_child(const char *name, Filter *filter,
+ const audio_format &prev_audio_format,
GError **error_r)
{
- struct audio_format conv_audio_format = *prev_audio_format;
- const struct audio_format *next_audio_format;
-
- next_audio_format = filter_open(filter, &conv_audio_format, error_r);
+ audio_format conv_audio_format = prev_audio_format;
+ const audio_format *next_audio_format =
+ filter->Open(conv_audio_format, error_r);
if (next_audio_format == NULL)
return NULL;
- if (!audio_format_equals(&conv_audio_format, prev_audio_format)) {
+ if (!audio_format_equals(&conv_audio_format, &prev_audio_format)) {
struct audio_format_string s;
- filter_close(filter);
+ filter->Close();
g_set_error(error_r, filter_quark(), 0,
"Audio format not supported by filter '%s': %s",
- filter->plugin->name,
- audio_format_to_string(prev_audio_format, &s));
+ name,
+ audio_format_to_string(&prev_audio_format, &s));
return NULL;
}
return next_audio_format;
}
-static const struct audio_format *
-chain_filter_open(struct filter *_filter, struct audio_format *in_audio_format,
- GError **error_r)
+const audio_format *
+ChainFilter::Open(audio_format &in_audio_format, GError **error_r)
{
- ChainFilter *chain = (ChainFilter *)_filter;
- const struct audio_format *audio_format = in_audio_format;
+ const audio_format *audio_format = &in_audio_format;
- for (auto filter : chain->children) {
- audio_format = chain_open_child(filter, audio_format, error_r);
+ for (auto &child : children) {
+ audio_format = chain_open_child(child.name, child.filter,
+ *audio_format, error_r);
if (audio_format == NULL) {
/* rollback, close all children */
- chain_close_until(chain, filter);
+ CloseUntil(child.filter);
return NULL;
}
}
@@ -136,26 +139,22 @@ chain_filter_open(struct filter *_filter, struct audio_format *in_audio_format,
return audio_format;
}
-static void
-chain_filter_close(struct filter *_filter)
+void
+ChainFilter::Close()
{
- ChainFilter *chain = (ChainFilter *)_filter;
-
- for (auto filter : chain->children)
- filter_close(filter);
+ for (auto &child : children)
+ child.filter->Close();
}
-static const void *
-chain_filter_filter(struct filter *_filter,
- const void *src, size_t src_size,
- size_t *dest_size_r, GError **error_r)
+const void *
+ChainFilter::FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r)
{
- ChainFilter *chain = (ChainFilter *)_filter;
-
- for (auto filter : chain->children) {
+ for (auto &child : children) {
/* feed the output of the previous filter as input
into the current one */
- src = filter_filter(filter, src, src_size, &src_size, error_r);
+ src = child.filter->FilterPCM(src, src_size, &src_size,
+ error_r);
if (src == NULL)
return NULL;
}
@@ -168,26 +167,18 @@ chain_filter_filter(struct filter *_filter,
const struct filter_plugin chain_filter_plugin = {
"chain",
chain_filter_init,
- chain_filter_finish,
- chain_filter_open,
- chain_filter_close,
- chain_filter_filter,
};
-struct filter *
+Filter *
filter_chain_new(void)
{
- struct filter *filter = filter_new(&chain_filter_plugin, NULL, NULL);
- /* chain_filter_init() never fails */
- assert(filter != NULL);
-
- return filter;
+ return new ChainFilter();
}
void
-filter_chain_append(struct filter *_chain, struct filter *filter)
+filter_chain_append(Filter &_chain, const char *name, Filter *filter)
{
- ChainFilter *chain = (ChainFilter *)_chain;
+ ChainFilter &chain = (ChainFilter &)_chain;
- chain->children.push_back(filter);
+ chain.Append(name, filter);
}
diff --git a/src/filter/ChainFilterPlugin.hxx b/src/filter/ChainFilterPlugin.hxx
index 242d29dae..884c7ca19 100644
--- a/src/filter/ChainFilterPlugin.hxx
+++ b/src/filter/ChainFilterPlugin.hxx
@@ -27,12 +27,12 @@
#ifndef MPD_FILTER_CHAIN_HXX
#define MPD_FILTER_CHAIN_HXX
-struct filter;
+class Filter;
/**
* Creates a new filter chain.
*/
-struct filter *
+Filter *
filter_chain_new(void);
/**
@@ -43,6 +43,6 @@ filter_chain_new(void);
* @param filter the filter to be appended to #chain
*/
void
-filter_chain_append(struct filter *chain, struct filter *filter);
+filter_chain_append(Filter &chain, const char *name, Filter *filter);
#endif
diff --git a/src/filter/ConvertFilterPlugin.cxx b/src/filter/ConvertFilterPlugin.cxx
index b07cf80f1..2c6907655 100644
--- a/src/filter/ConvertFilterPlugin.cxx
+++ b/src/filter/ConvertFilterPlugin.cxx
@@ -31,114 +31,89 @@
#include <assert.h>
#include <string.h>
-struct ConvertFilter {
- struct filter base;
-
+class ConvertFilter final : public Filter {
/**
* The input audio format; PCM data is passed to the filter()
* method in this format.
*/
- struct audio_format in_audio_format;
+ audio_format in_audio_format;
/**
* 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().
*/
- struct audio_format out_audio_format;
+ audio_format out_audio_format;
Manual<PcmConvert> state;
- ConvertFilter() {
- filter_init(&base, &convert_filter_plugin);
+public:
+ void Set(const audio_format &_out_audio_format) {
+ assert(audio_format_valid(&in_audio_format));
+ assert(audio_format_valid(&out_audio_format));
+ assert(audio_format_valid(&_out_audio_format));
+
+ out_audio_format = _out_audio_format;
}
+
+ virtual const audio_format *Open(audio_format &af, GError **error_r);
+ virtual void Close();
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r);
};
-static struct filter *
+static Filter *
convert_filter_init(gcc_unused const struct config_param *param,
gcc_unused GError **error_r)
{
- ConvertFilter *filter = new ConvertFilter();
- return &filter->base;
-}
-
-static void
-convert_filter_finish(struct filter *filter)
-{
- delete filter;
+ return new ConvertFilter();
}
-static const struct audio_format *
-convert_filter_open(struct filter *_filter, struct audio_format *audio_format,
- gcc_unused GError **error_r)
+const struct audio_format *
+ConvertFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
{
- ConvertFilter *filter = (ConvertFilter *)_filter;
+ assert(audio_format_valid(&audio_format));
- assert(audio_format_valid(audio_format));
+ in_audio_format = out_audio_format = audio_format;
+ state.Construct();
- filter->in_audio_format = filter->out_audio_format = *audio_format;
- filter->state.Construct();
-
- return &filter->in_audio_format;
+ return &in_audio_format;
}
-static void
-convert_filter_close(struct filter *_filter)
+void
+ConvertFilter::Close()
{
- ConvertFilter *filter = (ConvertFilter *)_filter;
-
- filter->state.Destruct();
+ state.Destruct();
- poison_undefined(&filter->in_audio_format,
- sizeof(filter->in_audio_format));
- poison_undefined(&filter->out_audio_format,
- sizeof(filter->out_audio_format));
+ poison_undefined(&in_audio_format, sizeof(in_audio_format));
+ poison_undefined(&out_audio_format, sizeof(out_audio_format));
}
-static const void *
-convert_filter_filter(struct filter *_filter, const void *src, size_t src_size,
- size_t *dest_size_r, GError **error_r)
+const void *
+ConvertFilter::FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r)
{
- ConvertFilter *filter = (ConvertFilter *)_filter;
- const void *dest;
-
- if (audio_format_equals(&filter->in_audio_format,
- &filter->out_audio_format)) {
+ if (audio_format_equals(&in_audio_format, &out_audio_format)) {
/* optimized special case: no-op */
*dest_size_r = src_size;
return src;
}
- dest = filter->state->Convert(&filter->in_audio_format,
- src, src_size,
- &filter->out_audio_format, dest_size_r,
- error_r);
- if (dest == NULL)
- return NULL;
-
- return dest;
+ return state->Convert(&in_audio_format,
+ src, src_size,
+ &out_audio_format, dest_size_r,
+ error_r);
}
const struct filter_plugin convert_filter_plugin = {
"convert",
convert_filter_init,
- convert_filter_finish,
- convert_filter_open,
- convert_filter_close,
- convert_filter_filter,
};
void
-convert_filter_set(struct filter *_filter,
- const struct audio_format *out_audio_format)
+convert_filter_set(Filter *_filter, const audio_format &out_audio_format)
{
ConvertFilter *filter = (ConvertFilter *)_filter;
- assert(filter != NULL);
- assert(audio_format_valid(&filter->in_audio_format));
- assert(audio_format_valid(&filter->out_audio_format));
- assert(out_audio_format != NULL);
- assert(audio_format_valid(out_audio_format));
-
- filter->out_audio_format = *out_audio_format;
+ filter->Set(out_audio_format);
}
diff --git a/src/filter/ConvertFilterPlugin.hxx b/src/filter/ConvertFilterPlugin.hxx
index 15f0fa92c..840bf496f 100644
--- a/src/filter/ConvertFilterPlugin.hxx
+++ b/src/filter/ConvertFilterPlugin.hxx
@@ -20,7 +20,7 @@
#ifndef MPD_CONVERT_FILTER_PLUGIN_HXX
#define MPD_CONVERT_FILTER_PLUGIN_HXX
-struct filter;
+class Filter;
struct audio_format;
/**
@@ -30,7 +30,6 @@ struct audio_format;
* the last in a chain.
*/
void
-convert_filter_set(struct filter *filter,
- const audio_format *out_audio_format);
+convert_filter_set(Filter *filter, const audio_format &out_audio_format);
#endif
diff --git a/src/filter/NormalizeFilterPlugin.cxx b/src/filter/NormalizeFilterPlugin.cxx
index af7a5efbd..e18c5cdf9 100644
--- a/src/filter/NormalizeFilterPlugin.cxx
+++ b/src/filter/NormalizeFilterPlugin.cxx
@@ -28,68 +28,51 @@
#include <assert.h>
#include <string.h>
-struct normalize_filter {
- struct filter filter;
-
+class NormalizeFilter final : public Filter {
struct Compressor *compressor;
struct pcm_buffer buffer;
+
+public:
+ virtual const audio_format *Open(audio_format &af, GError **error_r);
+ virtual void Close();
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r);
};
-static struct filter *
+static Filter *
normalize_filter_init(gcc_unused const struct config_param *param,
gcc_unused GError **error_r)
{
- struct normalize_filter *filter = g_new(struct normalize_filter, 1);
-
- filter_init(&filter->filter, &normalize_filter_plugin);
-
- return &filter->filter;
+ return new NormalizeFilter();
}
-static void
-normalize_filter_finish(struct filter *filter)
+const struct audio_format *
+NormalizeFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
{
- g_free(filter);
-}
+ audio_format.format = SAMPLE_FORMAT_S16;
-static const struct audio_format *
-normalize_filter_open(struct filter *_filter,
- struct audio_format *audio_format,
- gcc_unused GError **error_r)
-{
- struct normalize_filter *filter = (struct normalize_filter *)_filter;
+ compressor = Compressor_new(0);
+ pcm_buffer_init(&buffer);
- audio_format->format = SAMPLE_FORMAT_S16;
-
- filter->compressor = Compressor_new(0);
-
- pcm_buffer_init(&filter->buffer);
-
- return audio_format;
+ return &audio_format;
}
-static void
-normalize_filter_close(struct filter *_filter)
+void
+NormalizeFilter::Close()
{
- struct normalize_filter *filter = (struct normalize_filter *)_filter;
-
- pcm_buffer_deinit(&filter->buffer);
- Compressor_delete(filter->compressor);
+ pcm_buffer_deinit(&buffer);
+ Compressor_delete(compressor);
}
-static const void *
-normalize_filter_filter(struct filter *_filter,
- const void *src, size_t src_size, size_t *dest_size_r,
- gcc_unused GError **error_r)
+const void *
+NormalizeFilter::FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, gcc_unused GError **error_r)
{
- struct normalize_filter *filter = (struct normalize_filter *)_filter;
-
- int16_t *dest = (int16_t *)pcm_buffer_get(&filter->buffer, src_size);
-
+ int16_t *dest = (int16_t *)pcm_buffer_get(&buffer, src_size);
memcpy(dest, src, src_size);
- Compressor_Process_int16(filter->compressor, dest, src_size / 2);
+ Compressor_Process_int16(compressor, dest, src_size / 2);
*dest_size_r = src_size;
return dest;
@@ -98,8 +81,4 @@ normalize_filter_filter(struct filter *_filter,
const struct filter_plugin normalize_filter_plugin = {
"normalize",
normalize_filter_init,
- normalize_filter_finish,
- normalize_filter_open,
- normalize_filter_close,
- normalize_filter_filter,
};
diff --git a/src/filter/NullFilterPlugin.cxx b/src/filter/NullFilterPlugin.cxx
index 83082de55..d68065a39 100644
--- a/src/filter/NullFilterPlugin.cxx
+++ b/src/filter/NullFilterPlugin.cxx
@@ -30,65 +30,31 @@
#include "FilterRegistry.hxx"
#include "gcc.h"
-#include <glib.h>
-
-struct null_filter {
- struct filter filter;
+class NullFilter final : public Filter {
+public:
+ virtual const audio_format *Open(audio_format &af,
+ gcc_unused GError **error_r) {
+ return &af;
+ }
+
+ virtual void Close() {}
+
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r,
+ gcc_unused GError **error_r) {
+ *dest_size_r = src_size;
+ return src;
+ }
};
-static struct filter *
+static Filter *
null_filter_init(gcc_unused const struct config_param *param,
gcc_unused GError **error_r)
{
- struct null_filter *filter = g_new(struct null_filter, 1);
-
- filter_init(&filter->filter, &null_filter_plugin);
- return &filter->filter;
-}
-
-static void
-null_filter_finish(struct filter *_filter)
-{
- struct null_filter *filter = (struct null_filter *)_filter;
-
- g_free(filter);
-}
-
-static const struct audio_format *
-null_filter_open(struct filter *_filter, struct audio_format *audio_format,
- gcc_unused GError **error_r)
-{
- struct null_filter *filter = (struct null_filter *)_filter;
- (void)filter;
-
- return audio_format;
-}
-
-static void
-null_filter_close(struct filter *_filter)
-{
- struct null_filter *filter = (struct null_filter *)_filter;
- (void)filter;
-}
-
-static const void *
-null_filter_filter(struct filter *_filter,
- const void *src, size_t src_size,
- size_t *dest_size_r, gcc_unused GError **error_r)
-{
- struct null_filter *filter = (struct null_filter *)_filter;
- (void)filter;
-
- /* return the unmodified source buffer */
- *dest_size_r = src_size;
- return src;
+ return new NullFilter();
}
const struct filter_plugin null_filter_plugin = {
"null",
null_filter_init,
- null_filter_finish,
- null_filter_open,
- null_filter_close,
- null_filter_filter,
};
diff --git a/src/filter/ReplayGainFilterPlugin.cxx b/src/filter/ReplayGainFilterPlugin.cxx
index 59756a619..13c8a4063 100644
--- a/src/filter/ReplayGainFilterPlugin.cxx
+++ b/src/filter/ReplayGainFilterPlugin.cxx
@@ -38,9 +38,7 @@ extern "C" {
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "replay_gain"
-struct replay_gain_filter {
- struct filter filter;
-
+class ReplayGainFilter final : public Filter {
/**
* If set, then this hardware mixer is used for applying
* replay gain, instead of the software volume library.
@@ -71,9 +69,56 @@ struct replay_gain_filter {
*/
unsigned volume;
- struct audio_format audio_format;
+ struct audio_format format;
struct pcm_buffer buffer;
+
+public:
+ ReplayGainFilter()
+ :mixer(nullptr), mode(REPLAY_GAIN_OFF),
+ volume(PCM_VOLUME_1) {
+ replay_gain_info_init(&info);
+ }
+
+ void SetMixer(struct mixer *_mixer, unsigned _base) {
+ assert(_mixer == NULL || (_base > 0 && _base <= 100));
+
+ mixer = _mixer;
+ base = _base;
+
+ Update();
+ }
+
+ void SetInfo(const struct replay_gain_info *_info) {
+ if (_info != NULL) {
+ info = *_info;
+ replay_gain_info_complete(&info);
+ } else
+ replay_gain_info_init(&info);
+
+ Update();
+ }
+
+ void SetMode(enum replay_gain_mode _mode) {
+ if (_mode == mode)
+ /* no change */
+ return;
+
+ g_debug("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 const audio_format *Open(audio_format &af, GError **error_r);
+ virtual void Close();
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r);
};
static inline GQuark
@@ -82,30 +127,27 @@ replay_gain_quark(void)
return g_quark_from_static_string("replay_gain");
}
-/**
- * Recalculates the new volume after a property was changed.
- */
-static void
-replay_gain_filter_update(struct replay_gain_filter *filter)
+void
+ReplayGainFilter::Update()
{
- if (filter->mode != REPLAY_GAIN_OFF) {
- float scale = replay_gain_tuple_scale(&filter->info.tuples[filter->mode],
+ if (mode != REPLAY_GAIN_OFF) {
+ float scale = replay_gain_tuple_scale(&info.tuples[mode],
replay_gain_preamp, replay_gain_missing_preamp, replay_gain_limit);
g_debug("scale=%f\n", (double)scale);
- filter->volume = pcm_float_to_volume(scale);
+ volume = pcm_float_to_volume(scale);
} else
- filter->volume = PCM_VOLUME_1;
+ volume = PCM_VOLUME_1;
- if (filter->mixer != NULL) {
+ if (mixer != NULL) {
/* update the hardware mixer volume */
- unsigned volume = (filter->volume * filter->base) / PCM_VOLUME_1;
- if (volume > 100)
- volume = 100;
+ unsigned _volume = (volume * base) / PCM_VOLUME_1;
+ if (_volume > 100)
+ _volume = 100;
GError *error = NULL;
- if (!mixer_set_volume(filter->mixer, volume, &error)) {
+ if (!mixer_set_volume(mixer, _volume, &error)) {
g_warning("Failed to update hardware mixer: %s",
error->message);
g_error_free(error);
@@ -113,70 +155,41 @@ replay_gain_filter_update(struct replay_gain_filter *filter)
}
}
-static struct filter *
+static Filter *
replay_gain_filter_init(gcc_unused const struct config_param *param,
gcc_unused GError **error_r)
{
- struct replay_gain_filter *filter = g_new(struct replay_gain_filter, 1);
-
- filter_init(&filter->filter, &replay_gain_filter_plugin);
- filter->mixer = NULL;
-
- filter->mode = REPLAY_GAIN_OFF;
- replay_gain_info_init(&filter->info);
- filter->volume = PCM_VOLUME_1;
-
- return &filter->filter;
+ return new ReplayGainFilter();
}
-static void
-replay_gain_filter_finish(struct filter *filter)
+const audio_format *
+ReplayGainFilter::Open(audio_format &af, gcc_unused GError **error_r)
{
- g_free(filter);
-}
-
-static const struct audio_format *
-replay_gain_filter_open(struct filter *_filter,
- struct audio_format *audio_format,
- gcc_unused GError **error_r)
-{
- struct replay_gain_filter *filter =
- (struct replay_gain_filter *)_filter;
-
- filter->audio_format = *audio_format;
- pcm_buffer_init(&filter->buffer);
+ format = af;
+ pcm_buffer_init(&buffer);
- return &filter->audio_format;
+ return &format;
}
-static void
-replay_gain_filter_close(struct filter *_filter)
+void
+ReplayGainFilter::Close()
{
- struct replay_gain_filter *filter =
- (struct replay_gain_filter *)_filter;
-
- pcm_buffer_deinit(&filter->buffer);
+ pcm_buffer_deinit(&buffer);
}
-static const void *
-replay_gain_filter_filter(struct filter *_filter,
- const void *src, size_t src_size,
- size_t *dest_size_r, GError **error_r)
+const void *
+ReplayGainFilter::FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r)
{
- struct replay_gain_filter *filter =
- (struct replay_gain_filter *)_filter;
- bool success;
- void *dest;
*dest_size_r = src_size;
- if (filter->volume == PCM_VOLUME_1)
+ if (volume == PCM_VOLUME_1)
/* optimized special case: 100% volume = no-op */
return src;
- dest = pcm_buffer_get(&filter->buffer, src_size);
-
- if (filter->volume <= 0) {
+ void *dest = pcm_buffer_get(&buffer, src_size);
+ if (volume <= 0) {
/* optimized special case: 0% volume = memset(0) */
/* XXX is this valid for all sample formats? What
about floating point? */
@@ -186,9 +199,9 @@ replay_gain_filter_filter(struct filter *_filter,
memcpy(dest, src, src_size);
- success = pcm_volume(dest, src_size,
- sample_format(filter->audio_format.format),
- filter->volume);
+ bool success = pcm_volume(dest, src_size,
+ sample_format(format.format),
+ volume);
if (!success) {
g_set_error(error_r, replay_gain_quark(), 0,
"pcm_volume() has failed");
@@ -201,55 +214,29 @@ replay_gain_filter_filter(struct filter *_filter,
const struct filter_plugin replay_gain_filter_plugin = {
"replay_gain",
replay_gain_filter_init,
- replay_gain_filter_finish,
- replay_gain_filter_open,
- replay_gain_filter_close,
- replay_gain_filter_filter,
};
void
-replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer,
+replay_gain_filter_set_mixer(Filter *_filter, struct mixer *mixer,
unsigned base)
{
- struct replay_gain_filter *filter =
- (struct replay_gain_filter *)_filter;
-
- assert(mixer == NULL || (base > 0 && base <= 100));
-
- filter->mixer = mixer;
- filter->base = base;
+ ReplayGainFilter *filter = (ReplayGainFilter *)_filter;
- replay_gain_filter_update(filter);
+ filter->SetMixer(mixer, base);
}
void
-replay_gain_filter_set_info(struct filter *_filter,
- const struct replay_gain_info *info)
+replay_gain_filter_set_info(Filter *_filter, const replay_gain_info *info)
{
- struct replay_gain_filter *filter =
- (struct replay_gain_filter *)_filter;
+ ReplayGainFilter *filter = (ReplayGainFilter *)_filter;
- if (info != NULL) {
- filter->info = *info;
- replay_gain_info_complete(&filter->info);
- } else
- replay_gain_info_init(&filter->info);
-
- replay_gain_filter_update(filter);
+ filter->SetInfo(info);
}
void
-replay_gain_filter_set_mode(struct filter *_filter, enum replay_gain_mode mode)
+replay_gain_filter_set_mode(Filter *_filter, enum replay_gain_mode mode)
{
- struct replay_gain_filter *filter =
- (struct replay_gain_filter *)_filter;
-
- if (mode == filter->mode)
- /* no change */
- return;
-
- g_debug("replay gain mode has changed %d->%d\n", filter->mode, mode);
+ ReplayGainFilter *filter = (ReplayGainFilter *)_filter;
- filter->mode = mode;
- replay_gain_filter_update(filter);
+ filter->SetMode(mode);
}
diff --git a/src/filter/ReplayGainFilterPlugin.hxx b/src/filter/ReplayGainFilterPlugin.hxx
index 9b4ffc522..dd8ceb953 100644
--- a/src/filter/ReplayGainFilterPlugin.hxx
+++ b/src/filter/ReplayGainFilterPlugin.hxx
@@ -22,7 +22,7 @@
#include "replay_gain_info.h"
-struct filter;
+class Filter;
struct mixer;
/**
@@ -34,7 +34,7 @@ struct mixer;
* (including).
*/
void
-replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer,
+replay_gain_filter_set_mixer(Filter *_filter, struct mixer *mixer,
unsigned base);
/**
@@ -44,10 +44,9 @@ replay_gain_filter_set_mixer(struct filter *_filter, struct mixer *mixer,
* gain data is available for the current song
*/
void
-replay_gain_filter_set_info(struct filter *filter,
- const struct replay_gain_info *info);
+replay_gain_filter_set_info(Filter *filter, const replay_gain_info *info);
void
-replay_gain_filter_set_mode(struct filter *filter, enum replay_gain_mode mode);
+replay_gain_filter_set_mode(Filter *filter, enum replay_gain_mode mode);
#endif
diff --git a/src/filter/RouteFilterPlugin.cxx b/src/filter/RouteFilterPlugin.cxx
index dd24bde9a..559578938 100644
--- a/src/filter/RouteFilterPlugin.cxx
+++ b/src/filter/RouteFilterPlugin.cxx
@@ -53,14 +53,7 @@
#include <string.h>
#include <stdlib.h>
-
-struct route_filter {
-
- /**
- * Inherit (and support cast to/from) filter
- */
- struct filter base;
-
+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
@@ -110,21 +103,31 @@ struct route_filter {
*/
struct pcm_buffer output_buffer;
+public:
+ RouteFilter():sources(nullptr) {}
+ ~RouteFilter() {
+ g_free(sources);
+ }
+
+ /**
+ * 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 *param, GError **error_r);
+
+ virtual const audio_format *Open(audio_format &af, GError **error_r);
+ virtual void Close();
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r);
};
-/**
- * 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
- */
-static bool
-route_filter_parse(const struct config_param *param,
- struct route_filter *filter,
- GError **error_r) {
+bool
+RouteFilter::Configure(const config_param *param, GError **error_r) {
/* TODO:
* With a more clever way of marking "don't copy to output N",
@@ -139,8 +142,8 @@ route_filter_parse(const struct config_param *param,
const char *routes =
config_get_block_string(param, "routes", "0>0, 1>1");
- filter->min_input_channels = 0;
- filter->min_output_channels = 0;
+ min_input_channels = 0;
+ min_output_channels = 0;
tokens = g_strsplit(routes, ",", 255);
number_of_copies = g_strv_length(tokens);
@@ -171,28 +174,28 @@ route_filter_parse(const struct config_param *param,
// Keep track of the highest channel numbers seen
// as either in- or outputs
- if (source >= filter->min_input_channels)
- filter->min_input_channels = source + 1;
- if (dest >= filter->min_output_channels)
- filter->min_output_channels = dest + 1;
+ if (source >= min_input_channels)
+ min_input_channels = source + 1;
+ if (dest >= min_output_channels)
+ min_output_channels = dest + 1;
g_strfreev(sd);
}
- if (!audio_valid_channel_count(filter->min_output_channels)) {
+ if (!audio_valid_channel_count(min_output_channels)) {
g_strfreev(tokens);
g_set_error(error_r, audio_format_quark(), 0,
"Invalid number of output channels requested: %d",
- filter->min_output_channels);
+ min_output_channels);
return false;
}
// Allocate a map of "copy nothing to me"
- filter->sources = (signed char *)
- g_malloc(filter->min_output_channels * sizeof(signed char));
+ sources = (signed char *)
+ g_malloc(min_output_channels * sizeof(signed char));
- for (int i=0; i<filter->min_output_channels; ++i)
- filter->sources[i] = -1;
+ for (int i=0; i<min_output_channels; ++i)
+ sources[i] = -1;
// Run through the spec again, and save the
// actual mapping output <- input
@@ -216,7 +219,7 @@ route_filter_parse(const struct config_param *param,
source = strtol(sd[0], NULL, 10);
dest = strtol(sd[1], NULL, 10);
- filter->sources[dest] = source;
+ sources[dest] = source;
g_strfreev(sd);
}
@@ -226,73 +229,53 @@ route_filter_parse(const struct config_param *param,
return true;
}
-static struct filter *
-route_filter_init(const struct config_param *param,
- gcc_unused GError **error_r)
-{
- struct route_filter *filter = g_new(struct route_filter, 1);
- filter_init(&filter->base, &route_filter_plugin);
-
- // Allocate and set the filter->sources[] array
- route_filter_parse(param, filter, error_r);
-
- return &filter->base;
-}
-
-static void
-route_filter_finish(struct filter *_filter)
+static Filter *
+route_filter_init(const config_param *param, GError **error_r)
{
- struct route_filter *filter = (struct route_filter *)_filter;
+ RouteFilter *filter = new RouteFilter();
+ if (!filter->Configure(param, error_r)) {
+ delete filter;
+ return nullptr;
+ }
- g_free(filter->sources);
- g_free(filter);
+ return filter;
}
-static const struct audio_format *
-route_filter_open(struct filter *_filter, struct audio_format *audio_format,
- gcc_unused GError **error_r)
+const struct audio_format *
+RouteFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
{
- struct route_filter *filter = (struct route_filter *)_filter;
-
// Copy the input format for later reference
- filter->input_format = *audio_format;
- filter->input_frame_size =
- audio_format_frame_size(&filter->input_format);
+ input_format = audio_format;
+ input_frame_size = audio_format_frame_size(&input_format);
// Decide on an output format which has enough channels,
// and is otherwise identical
- filter->output_format = *audio_format;
- filter->output_format.channels = filter->min_output_channels;
+ output_format = audio_format;
+ output_format.channels = min_output_channels;
// Precalculate this simple value, to speed up allocation later
- filter->output_frame_size =
- audio_format_frame_size(&filter->output_format);
+ output_frame_size = audio_format_frame_size(&output_format);
// This buffer grows as needed
- pcm_buffer_init(&filter->output_buffer);
+ pcm_buffer_init(&output_buffer);
- return &filter->output_format;
+ return &output_format;
}
-static void
-route_filter_close(struct filter *_filter)
+void
+RouteFilter::Close()
{
- struct route_filter *filter = (struct route_filter *)_filter;
-
- pcm_buffer_deinit(&filter->output_buffer);
+ pcm_buffer_deinit(&output_buffer);
}
-static const void *
-route_filter_filter(struct filter *_filter,
- const void *src, size_t src_size,
- size_t *dest_size_r, gcc_unused GError **error_r)
+const void *
+RouteFilter::FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, gcc_unused GError **error_r)
{
- struct route_filter *filter = (struct route_filter *)_filter;
-
- size_t number_of_frames = src_size / filter->input_frame_size;
+ size_t number_of_frames = src_size / input_frame_size;
size_t bytes_per_frame_per_channel =
- audio_format_sample_size(&filter->input_format);
+ audio_format_sample_size(&input_format);
// 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;
@@ -301,18 +284,18 @@ route_filter_filter(struct filter *_filter,
uint8_t *chan_destination;
// Grow our reusable buffer, if needed, and set the moving pointer
- *dest_size_r = number_of_frames * filter->output_frame_size;
+ *dest_size_r = number_of_frames * output_frame_size;
chan_destination = (uint8_t *)
- pcm_buffer_get(&filter->output_buffer, *dest_size_r);
+ pcm_buffer_get(&output_buffer, *dest_size_r);
// Perform our copy operations, with N input channels and M output channels
for (unsigned int s=0; s<number_of_frames; ++s) {
// Need to perform one copy per output channel
- for (unsigned int c=0; c<filter->min_output_channels; ++c) {
- if (filter->sources[c] == -1 ||
- (unsigned)filter->sources[c] >= filter->input_format.channels) {
+ for (unsigned int c=0; c<min_output_channels; ++c) {
+ if (sources[c] == -1 ||
+ (unsigned)sources[c] >= input_format.channels) {
// No source for this destination output,
// give it zeroes as input
memset(chan_destination,
@@ -322,7 +305,7 @@ route_filter_filter(struct filter *_filter,
// Get the data from channel sources[c]
// and copy it to the output
const uint8_t *data = base_source +
- (filter->sources[c] * bytes_per_frame_per_channel);
+ (sources[c] * bytes_per_frame_per_channel);
memcpy(chan_destination,
data,
bytes_per_frame_per_channel);
@@ -333,18 +316,14 @@ route_filter_filter(struct filter *_filter,
// Go on to the next N input samples
- base_source += filter->input_frame_size;
+ base_source += input_frame_size;
}
// Here it is, ladies and gentlemen! Rerouted data!
- return (void *) filter->output_buffer.buffer;
+ return (void *) output_buffer.buffer;
}
const struct filter_plugin route_filter_plugin = {
"route",
route_filter_init,
- route_filter_finish,
- route_filter_open,
- route_filter_close,
- route_filter_filter,
};
diff --git a/src/filter/VolumeFilterPlugin.cxx b/src/filter/VolumeFilterPlugin.cxx
index 86c99b83a..0689f5da5 100644
--- a/src/filter/VolumeFilterPlugin.cxx
+++ b/src/filter/VolumeFilterPlugin.cxx
@@ -30,17 +30,36 @@
#include <assert.h>
#include <string.h>
-struct volume_filter {
- struct filter filter;
-
+class VolumeFilter final : public Filter {
/**
* The current volume, from 0 to #PCM_VOLUME_1.
*/
unsigned volume;
- struct audio_format audio_format;
+ struct audio_format format;
struct pcm_buffer buffer;
+
+public:
+ VolumeFilter()
+ :volume(PCM_VOLUME_1) {}
+
+ unsigned GetVolume() const {
+ assert(volume <= PCM_VOLUME_1);
+
+ return volume;
+ }
+
+ void SetVolume(unsigned _volume) {
+ assert(_volume <= PCM_VOLUME_1);
+
+ volume = _volume;
+ }
+
+ virtual const audio_format *Open(audio_format &af, GError **error_r);
+ virtual void Close();
+ virtual const void *FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r);
};
static inline GQuark
@@ -49,61 +68,41 @@ volume_quark(void)
return g_quark_from_static_string("pcm_volume");
}
-static struct filter *
+static Filter *
volume_filter_init(gcc_unused const struct config_param *param,
gcc_unused GError **error_r)
{
- struct volume_filter *filter = g_new(struct volume_filter, 1);
-
- filter_init(&filter->filter, &volume_filter_plugin);
- filter->volume = PCM_VOLUME_1;
-
- return &filter->filter;
+ return new VolumeFilter();
}
-static void
-volume_filter_finish(struct filter *filter)
+const struct audio_format *
+VolumeFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
{
- g_free(filter);
-}
-
-static const struct audio_format *
-volume_filter_open(struct filter *_filter, struct audio_format *audio_format,
- gcc_unused GError **error_r)
-{
- struct volume_filter *filter = (struct volume_filter *)_filter;
-
- filter->audio_format = *audio_format;
- pcm_buffer_init(&filter->buffer);
+ format = audio_format;
+ pcm_buffer_init(&buffer);
- return &filter->audio_format;
+ return &format;
}
-static void
-volume_filter_close(struct filter *_filter)
+void
+VolumeFilter::Close()
{
- struct volume_filter *filter = (struct volume_filter *)_filter;
-
- pcm_buffer_deinit(&filter->buffer);
+ pcm_buffer_deinit(&buffer);
}
-static const void *
-volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
- size_t *dest_size_r, GError **error_r)
+const void *
+VolumeFilter::FilterPCM(const void *src, size_t src_size,
+ size_t *dest_size_r, GError **error_r)
{
- struct volume_filter *filter = (struct volume_filter *)_filter;
- bool success;
- void *dest;
-
*dest_size_r = src_size;
- if (filter->volume >= PCM_VOLUME_1)
+ if (volume >= PCM_VOLUME_1)
/* optimized special case: 100% volume = no-op */
return src;
- dest = pcm_buffer_get(&filter->buffer, src_size);
+ void *dest = pcm_buffer_get(&buffer, src_size);
- if (filter->volume <= 0) {
+ if (volume <= 0) {
/* optimized special case: 0% volume = memset(0) */
/* XXX is this valid for all sample formats? What
about floating point? */
@@ -113,9 +112,9 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
memcpy(dest, src, src_size);
- success = pcm_volume(dest, src_size,
- sample_format(filter->audio_format.format),
- filter->volume);
+ bool success = pcm_volume(dest, src_size,
+ sample_format(format.format),
+ volume);
if (!success) {
g_set_error(error_r, volume_quark(), 0,
"pcm_volume() has failed");
@@ -128,32 +127,22 @@ volume_filter_filter(struct filter *_filter, const void *src, size_t src_size,
const struct filter_plugin volume_filter_plugin = {
"volume",
volume_filter_init,
- volume_filter_finish,
- volume_filter_open,
- volume_filter_close,
- volume_filter_filter,
};
unsigned
-volume_filter_get(const struct filter *_filter)
+volume_filter_get(const Filter *_filter)
{
- const struct volume_filter *filter =
- (const struct volume_filter *)_filter;
+ const VolumeFilter *filter =
+ (const VolumeFilter *)_filter;
- assert(filter->filter.plugin == &volume_filter_plugin);
- assert(filter->volume <= PCM_VOLUME_1);
-
- return filter->volume;
+ return filter->GetVolume();
}
void
-volume_filter_set(struct filter *_filter, unsigned volume)
+volume_filter_set(Filter *_filter, unsigned volume)
{
- struct volume_filter *filter = (struct volume_filter *)_filter;
-
- assert(filter->filter.plugin == &volume_filter_plugin);
- assert(volume <= PCM_VOLUME_1);
+ VolumeFilter *filter = (VolumeFilter *)_filter;
- filter->volume = volume;
+ filter->SetVolume(volume);
}
diff --git a/src/filter/VolumeFilterPlugin.hxx b/src/filter/VolumeFilterPlugin.hxx
index e3d29b87d..822b7e93a 100644
--- a/src/filter/VolumeFilterPlugin.hxx
+++ b/src/filter/VolumeFilterPlugin.hxx
@@ -20,12 +20,12 @@
#ifndef MPD_VOLUME_FILTER_PLUGIN_HXX
#define MPD_VOLUME_FILTER_PLUGIN_HXX
-struct filter;
+class Filter;
unsigned
-volume_filter_get(const struct filter *filter);
+volume_filter_get(const Filter *filter);
void
-volume_filter_set(struct filter *filter, unsigned volume);
+volume_filter_set(Filter *filter, unsigned volume);
#endif
diff --git a/src/mixer/SoftwareMixerPlugin.cxx b/src/mixer/SoftwareMixerPlugin.cxx
index 9b8f083f4..16463938f 100644
--- a/src/mixer/SoftwareMixerPlugin.cxx
+++ b/src/mixer/SoftwareMixerPlugin.cxx
@@ -32,7 +32,7 @@ struct software_mixer {
/** the base mixer class */
struct mixer base;
- struct filter *filter;
+ Filter *filter;
unsigned volume;
};
@@ -100,7 +100,7 @@ const struct mixer_plugin software_mixer_plugin = {
true,
};
-struct filter *
+Filter *
software_mixer_get_filter(struct mixer *mixer)
{
struct software_mixer *sm = (struct software_mixer *)mixer;
diff --git a/src/mixer/SoftwareMixerPlugin.hxx b/src/mixer/SoftwareMixerPlugin.hxx
index 9a625868d..33e9e6c6f 100644
--- a/src/mixer/SoftwareMixerPlugin.hxx
+++ b/src/mixer/SoftwareMixerPlugin.hxx
@@ -21,13 +21,13 @@
#define MPD_SOFTWARE_MIXER_PLUGIN_HXX
struct mixer;
-struct filter;
+class Filter;
/**
* Returns the (volume) filter associated with this mixer. All users
* of this mixer plugin should install this filter.
*/
-struct filter *
+Filter *
software_mixer_get_filter(struct mixer *mixer);
#endif
diff --git a/src/output_internal.h b/src/output_internal.h
index 692233f3c..201962a72 100644
--- a/src/output_internal.h
+++ b/src/output_internal.h
@@ -27,6 +27,12 @@
#include <time.h>
+#ifdef __cplusplus
+class Filter;
+#else
+typedef void *Filter;
+#endif
+
struct config_param;
enum audio_output_command {
@@ -156,13 +162,13 @@ struct audio_output {
* The filter object of this audio output. This is an
* instance of chain_filter_plugin.
*/
- struct filter *filter;
+ Filter *filter;
/**
* The replay_gain_filter_plugin instance of this audio
* output.
*/
- struct filter *replay_gain_filter;
+ Filter *replay_gain_filter;
/**
* The serial number of the last replay gain info. 0 means no
@@ -175,7 +181,7 @@ struct audio_output {
* output, to be applied to the second chunk during
* cross-fading.
*/
- struct filter *other_replay_gain_filter;
+ Filter *other_replay_gain_filter;
/**
* The serial number of the last replay gain info by the
@@ -189,7 +195,7 @@ struct audio_output {
* for converting the input data into the appropriate format
* for this audio output.
*/
- struct filter *convert_filter;
+ Filter *convert_filter;
/**
* The thread handle, or NULL if the output thread isn't