From 94ab78803273ee3e1b3a79f65c0475fd3b0f4be7 Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Tue, 27 Jun 2023 05:06:10 +0300 Subject: [PATCH] GstEnginePipeline: actually perform (EBU R 128) loudness normalization The magic: if EBU R 128 loudness normalization is enabled, just insert `volume` GST element into the pipeline (where ReplayGain would be inserted) and configure it. We currently don't support changing said gain after the pipeline was created. We might need to, though, for a number of reasons. --- src/engine/gstenginepipeline.cpp | 27 ++++++++++++++++++++++++++- src/engine/gstenginepipeline.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/engine/gstenginepipeline.cpp b/src/engine/gstenginepipeline.cpp index 9dc335531..b703be8f1 100644 --- a/src/engine/gstenginepipeline.cpp +++ b/src/engine/gstenginepipeline.cpp @@ -110,6 +110,7 @@ GstEnginePipeline::GstEnginePipeline(QObject *parent) audiosink_(nullptr), audioqueue_(nullptr), audioqueueconverter_(nullptr), + ebur128_volume_(nullptr), volume_(nullptr), volume_sw_(nullptr), volume_fading_(nullptr), @@ -567,8 +568,9 @@ bool GstEnginePipeline::InitAudioBin(QString &error) { } - // Create the replaygain elements if it's enabled. eventprobe_ = audioqueueconverter_; + + // Create the replaygain elements if it's enabled. GstElement *rgvolume = nullptr; GstElement *rglimiter = nullptr; GstElement *rgconverter = nullptr; @@ -593,6 +595,20 @@ bool GstEnginePipeline::InitAudioBin(QString &error) { g_object_set(G_OBJECT(rglimiter), "enabled", static_cast(rg_compression_), nullptr); } + // Create the EBU R 128 loudness normalization volume element if enabled. + if (ebur128_loudness_normalization_) { + ebur128_volume_ = CreateElement("volume", "ebur128_volume", audiobin_, error); + if (!ebur128_volume_) { + return false; + } + + auto dB_to_mult = [](const double gain_dB) { return std::pow(10., gain_dB / 20.); }; + + g_object_set(G_OBJECT(ebur128_volume_), "volume", dB_to_mult(ebur128_loudness_normalizing_gain_db_), nullptr); + + eventprobe_ = ebur128_volume_; + } + GstElement *bs2b = nullptr; if (bs2b_enabled_) { bs2b = CreateElement("bs2b", "bs2b", audiobin_, error); @@ -651,6 +667,15 @@ bool GstEnginePipeline::InitAudioBin(QString &error) { element_link = rgconverter; } + // Link EBU R 128 loudness normalization volume element if enabled. + if (ebur128_loudness_normalization_ && ebur128_volume_) { + if (!gst_element_link(element_link, ebur128_volume_)) { + error = "Failed to link EBU R 128 volume element."; + return false; + } + element_link = ebur128_volume_; + } + // Link equalizer elements if enabled. if (eq_enabled_ && equalizer_ && equalizer_preamp_) { if (!gst_element_link_many(element_link, equalizer_preamp_, equalizer_, nullptr)) { diff --git a/src/engine/gstenginepipeline.h b/src/engine/gstenginepipeline.h index a46ebe862..fc04e8322 100644 --- a/src/engine/gstenginepipeline.h +++ b/src/engine/gstenginepipeline.h @@ -301,6 +301,7 @@ class GstEnginePipeline : public QObject { GstElement *audiosink_; GstElement *audioqueue_; GstElement *audioqueueconverter_; + GstElement *ebur128_volume_; GstElement *volume_; GstElement *volume_sw_; GstElement *volume_fading_;