[vlc-commits] [Git][videolan/vlc][master] audio_filter: Add noise gate filter

Steve Lhomme (@robUx4) gitlab at videolan.org
Mon Jun 23 08:11:31 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
4014ed4d by Paschalis Melissas at 2025-06-23T07:48:44+00:00
audio_filter: Add noise gate filter

Implements noise gate functionality to reduce background noise by attenuating signals below configurable threshold.

- - - - -


2 changed files:

- modules/audio_filter/Makefile.am
- + modules/audio_filter/gate.c


Changes:

=====================================
modules/audio_filter/Makefile.am
=====================================
@@ -9,6 +9,8 @@ libcompressor_plugin_la_LIBADD = $(LIBM)
 libequalizer_plugin_la_SOURCES = audio_filter/equalizer.c \
 	audio_filter/equalizer_presets.h
 libequalizer_plugin_la_LIBADD = $(LIBM)
+libgate_plugin_la_SOURCES = audio_filter/gate.c
+libgate_plugin_la_LIBADD  = $(LIBM)
 libkaraoke_plugin_la_SOURCES = audio_filter/karaoke.c
 libnormvol_plugin_la_SOURCES = audio_filter/normvol.c
 libnormvol_plugin_la_LIBADD = $(LIBM)
@@ -43,6 +45,7 @@ audio_filter_LTLIBRARIES = \
 	libchorus_flanger_plugin.la \
 	libcompressor_plugin.la \
 	libequalizer_plugin.la \
+	libgate_plugin.la \ 
 	libkaraoke_plugin.la \
 	libnormvol_plugin.la \
 	libgain_plugin.la \


=====================================
modules/audio_filter/gate.c
=====================================
@@ -0,0 +1,242 @@
+/*****************************************************************************
+ * gate.c : noise gate audio filter
+ *****************************************************************************
+ * Copyright © 2025 VLC authors and VideoLAN
+ * 
+ * Authors: Paschalis Melissas <melissaspaschalis at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_aout.h>
+#include <vlc_aout_volume.h>
+#include <vlc_filter.h>
+#include <vlc_modules.h>
+#include <vlc_plugin.h>
+#include <math.h>
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+static int      Open        ( vlc_object_t * );
+static void     Close       ( filter_t * );
+static block_t  *Process    ( filter_t *, block_t * );
+
+typedef struct
+{
+    float time;		        /* Time to estimate power [ms] */
+    float thresh;	        /* Threshold [dB] */
+    float attack;	        /* Attack time [ms] */
+    float release;	        /* Release time [ms] */
+
+    float *pow;		        /* Estimated power level [dB] - per channel */
+    float *gain;            /* Current gain per channel (for smooth transitions) */
+
+    /* additional data - filter state */
+    int channels;
+    float alpha;            /* smoothing factor - this is actually the forgetting factor for power estimate of the Anders Johansson approach. */
+    float thresh_linear;    /* Threshold in linear scale */
+    float attack_factor;    /* Attack factor for smoothing */
+    float release_factor;   /* Release factor for smoothing */
+} filter_sys_t;
+
+static float db_to_linear(float db)
+{
+    return powf(10.0f, db / 20.0f);
+}
+
+static float set_alpha(int sample_rate, float smoothing_time)
+{
+    /* reference : https://en.wikipedia.org/wiki/Exponential_smoothing#Time_constant */
+
+    /* Calculate smoothing factor (alpha) from time constant */
+    float time_constant_sec = smoothing_time / 1000.0f;  /* τ in seconds */
+    float delta_t = 1.0f / sample_rate;  /* Time between samples (ΔT) in seconds */
+    float tau_normalizer = -delta_t / time_constant_sec;  /* -ΔT/τ */
+    float alpha = 1.0f - expf(tau_normalizer);  /* α = 1 - e^(-ΔT/τ) */
+    return alpha;
+}
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+
+#define THRESHOLD_TEXT N_("Threshold")
+#define THRESHOLD_LONGTEXT N_("Threshold level in dB (negative values)")
+
+#define ATTACK_TEXT N_("Attack time")
+#define ATTACK_LONGTEXT N_("Attack time in milliseconds")
+
+#define RELEASE_TEXT N_("Release time")
+#define RELEASE_LONGTEXT N_("Release time in milliseconds")
+
+#define SMOOTHING_TEXT N_("Smoothing time")
+#define SMOOTHING_LONGTEXT N_("Amount of time for the smoothed response in milliseconds")
+
+vlc_module_begin()
+    set_shortname( N_("Noise Gate") )
+    set_description( N_("Noise gate audio filter") )
+    set_subcategory( SUBCAT_AUDIO_AFILTER )
+    add_float_with_range( "gate-threshold", -30.0, -60.0, 0.0, 
+                        THRESHOLD_TEXT, THRESHOLD_LONGTEXT)
+    add_float_with_range( "gate-attack", 50, 10, 500, 
+                            ATTACK_TEXT, ATTACK_LONGTEXT )
+    add_float_with_range( "gate-release", 300, 50, 1000, 
+                            RELEASE_TEXT, RELEASE_LONGTEXT )
+    add_float_with_range( "smoothing-time", 10, 1, 30, 
+                            SMOOTHING_TEXT, SMOOTHING_LONGTEXT )
+    set_capability( "audio filter", 0 )
+    add_shortcut( "gate" )
+    set_callback( Open )
+vlc_module_end()
+
+/*****************************************************************************
+ * Open: initialize filter
+ *****************************************************************************/
+
+static int Open(vlc_object_t *p_this)
+{
+    filter_t *p_filter = (filter_t *)p_this;
+    
+    if (p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32) 
+    {
+        msg_Warn( p_filter, "unsupported format" );
+        return VLC_EGENERIC;
+    }
+
+    filter_sys_t *p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
+    if (!p_sys)
+        return VLC_ENOMEM;
+
+    /* Initialize parameters */
+    p_sys->channels = p_filter->fmt_in.audio.i_channels;
+    unsigned int sample_rate = p_filter->fmt_in.audio.i_rate;
+    if (sample_rate == 0) 
+    {
+        msg_Err(p_filter, "sample rate is zero");
+        free(p_sys);
+        return VLC_EINVAL;
+    }
+    p_sys->thresh = var_InheritFloat(p_filter, "gate-threshold");
+    float thresh_lin = db_to_linear(p_sys->thresh); /* Convert parameters to linear scale */
+    p_sys->thresh_linear = thresh_lin * thresh_lin; /*Convert to power domain */
+    p_sys->attack = var_InheritFloat(p_filter, "gate-attack");
+    p_sys->release = var_InheritFloat(p_filter, "gate-release");
+    float attack_samples = (sample_rate * p_sys->attack) / 1000;
+    float release_samples = (sample_rate * p_sys->release) / 1000;
+    /* Calculate smoothing factors */
+    p_sys->attack_factor = attack_samples > 0 ? 1.0f / attack_samples : 1.0f;
+    p_sys->release_factor = release_samples > 0 ? 1.0f / release_samples : 1.0f;
+    float smoothing_time = var_InheritFloat(p_filter, "smoothing-time");
+    if(smoothing_time <= 0.0f)
+    {
+        msg_Err(p_filter, "Invalid smoothing time (%f), smoothing time must be between 1 and 30 ms",smoothing_time);
+        free(p_sys);
+        return VLC_EINVAL;
+    }
+    p_sys->alpha = set_alpha(sample_rate,smoothing_time);
+    p_sys->pow = (float*)calloc( p_sys->channels,sizeof(float));
+    p_sys->gain = (float*)calloc(p_sys->channels, sizeof(float));
+
+    if (!p_sys->pow || !p_sys->gain) 
+    {
+        free(p_sys->pow);
+        free(p_sys->gain);
+        free(p_sys);
+        return VLC_ENOMEM;
+    }
+    for (int i = 0; i < p_sys->channels; i++) 
+    {
+        p_sys->pow[i] = 0.0f;
+        p_sys->gain[i] = 1.0f; /* Start with full gain */
+    }
+        
+    p_filter->fmt_out.audio = p_filter->fmt_in.audio;
+
+    static const struct vlc_filter_operations filter_ops = 
+    {
+        .filter_audio = Process, .close = Close,
+    };
+    p_filter->ops = &filter_ops;
+    
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Process: apply noise gate to samples
+ *****************************************************************************/
+
+static block_t *Process(filter_t *p_filter, block_t *p_block)
+{
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if (!p_block || !p_block->i_nb_samples)
+        return p_block;
+
+    float *p_samples = (float *)p_block->p_buffer;
+    int i_nb_samples = p_block->i_nb_samples;
+    int channels = p_sys->channels;
+
+    /* iterate over interleaved data */
+    for (int ch = 0; ch < channels; ch++) {
+        for (int i = ch; i < i_nb_samples * channels; i += channels) {
+            float x = p_samples[i];
+            float pow = x * x;
+
+            /* Update power estimate with low-pass filter */
+            p_sys->pow[ch] = (1.0f - p_sys->alpha) * p_sys->pow[ch] + pow * p_sys->alpha;
+            
+            /* Determine target gain */
+            float target_gain = (p_sys->pow[ch] < p_sys->thresh_linear) ? 0.0f : 1.0f;
+            
+            /* Calculate gain delta */
+            float gain_delta = target_gain - p_sys->gain[ch];
+
+            /* Apply smoothing to gain changes */
+            float gain_change_factor = ( gain_delta > 0.0f ) ? 
+                                                p_sys->attack_factor : p_sys->release_factor;
+
+            /* Smoothly adjust gain */
+            p_sys->gain[ch] += gain_change_factor * gain_delta;
+
+            /* Apply gain to sample */
+            p_samples[i] = x * p_sys->gain[ch];
+        }
+    }
+    return p_block;
+}
+
+/*****************************************************************************
+ * Close: close filter
+ *****************************************************************************/
+
+static void Close( filter_t *p_filter )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    free( p_sys->pow );
+    free( p_sys->gain );
+    free( p_sys );
+}
\ No newline at end of file



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/4014ed4dc215a5e58ef063121be6cd8f411ea1b2

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/4014ed4dc215a5e58ef063121be6cd8f411ea1b2
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list