diff options
Diffstat (limited to 'src/filter/ReplayGainFilterPlugin.cxx')
-rw-r--r-- | src/filter/ReplayGainFilterPlugin.cxx | 189 |
1 files changed, 88 insertions, 101 deletions
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); } |