Skip to content

Instantly share code, notes, and snippets.

@markbeaton
Created June 18, 2021 05:27
Show Gist options
  • Save markbeaton/1b5f19ab1431e521625aa0950691cceb to your computer and use it in GitHub Desktop.
Save markbeaton/1b5f19ab1431e521625aa0950691cceb to your computer and use it in GitHub Desktop.
diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h
index f00a597..cc826b3 100644
--- a/include/vlc/libvlc_media_player.h
+++ b/include/vlc/libvlc_media_player.h
@@ -167,6 +167,13 @@ typedef enum libvlc_teletext_key_t {
*/
typedef struct libvlc_equalizer_t libvlc_equalizer_t;
+/**
+ * Opaque compressor handle.
+ *
+ * Compressor settings can be applied to a media player.
+ */
+typedef struct libvlc_compressor_t libvlc_compressor_t;
+
/**
* Create an empty Media Player object
*
@@ -2039,6 +2046,262 @@ LIBVLC_API float libvlc_audio_equalizer_get_amp_at_index( libvlc_equalizer_t *p_
*/
LIBVLC_API int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer );
+/**
+ * Create a new default compressor, with all values set as their respective
+ * default values.
+ *
+ * The new compressor can subsequently be applied to a media player by invoking
+ * libvlc_media_player_set_compressor().
+ *
+ * The returned handle should be freed via libvlc_audio_compressor_release()
+ * when it is no longer needed.
+ *
+ * \return opaque compressor handle, or NULL on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API libvlc_compressor_t *libvlc_audio_compressor_new( void );
+
+/**
+ * Release a previously created compressor instance.
+ *
+ * The compressor was previously created by using
+ * libvlc_audio_compressor_new().
+ *
+ * It is safe to invoke this method with a NULL p_compressor parameter for no
+ * effect.
+ *
+ * \param p_compressor opaque compressor handle, or NULL
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API void libvlc_audio_compressor_release( libvlc_compressor_t *p_compressor );
+
+/**
+ * Set a new RMS/peak value for a compressor, which is an interpolation
+ * parameter that determines the type of compression. If the parameter is set
+ * to 0, the compressor will use RMS (root-mean-square) compression; on the
+ * other hand, if the parameter is set to 1, the compressor will use peak
+ * compression.
+ *
+ * The new compressor settings are subsequently applied to a media player by
+ * invoking libvlc_media_player_set_compressor().
+ *
+ * The supplied value will be clamped to the 0.0 to 1.0 range.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \param f_rms_peak RMS/peak value (0.0 to 1.0)
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_audio_compressor_set_rms_peak( libvlc_compressor_t *p_compressor, float f_rms_peak );
+
+/**
+ * Get the current RMS/peak value from a compressor, which is an interpolation
+ * parameter that determines the type of compression. If the parameter is set
+ * to 0, the compressor is using RMS (root-mean-square) compression; on the
+ * other hand, if the parameter is set to 1, the compressor is using peak
+ * compression.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \return RMS/peak value
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API float libvlc_audio_compressor_get_rms_peak( libvlc_compressor_t *p_compressor );
+
+/**
+ * Set a new attack value for a compressor. This value represents the amount of
+ * time it takes for the compressor to reduce the audio signal's level to a
+ * level determined by the ratio.
+ *
+ * The new compressor settings are subsequently applied to a media player by
+ * invoking libvlc_media_player_set_compressor().
+ *
+ * The supplied value will be clamped to the 1.5 to 400.0 range.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \param f_attack attack value (1.5 to 400.0 ms)
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_audio_compressor_set_attack( libvlc_compressor_t *p_compressor, float f_attack );
+
+/**
+ * Get the current attack value from a compressor. This value represents the
+ * amount of time it takes for the compressor to reduce the audio signal's
+ * level to a level determined by the ratio.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \return attack value (ms)
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API float libvlc_audio_compressor_get_attack( libvlc_compressor_t *p_compressor );
+
+/**
+ * Set a new release value for a compressor. This value represents the amount
+ * of time it takes for the compressor to increase the audio signal's level to
+ * a level determined by the ratio.
+ *
+ * The new compressor settings are subsequently applied to a media player by
+ * invoking libvlc_media_player_set_compressor().
+ *
+ * The supplied value will be clamped to the 2.0 to 800.0 range.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \param f_release release value (2.0 to 800.0 ms)
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_audio_compressor_set_release( libvlc_compressor_t *p_compressor, float f_release );
+
+/**
+ * Get the current release value from a compressor. This value represents the
+ * amount of time it takes for the compressor to increase the audio signal's
+ * level to a level determined by the ratio.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \return release value (ms)
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API float libvlc_audio_compressor_get_release( libvlc_compressor_t *p_compressor );
+
+/**
+ * Set a new threshold level value for a compressor. Any audio signal level
+ * above this value becomes compressed.
+ *
+ * The new compressor settings are subsequently applied to a media player by
+ * invoking libvlc_media_player_set_compressor().
+ *
+ * The supplied value will be clamped to the -30.0 to 0.0 range.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \param f_threshold threshold level value (-30.0 to +0.0 dB)
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_audio_compressor_set_threshold( libvlc_compressor_t *p_compressor, float f_threshold );
+
+/**
+ * Get the current threshold level value from a compressor. Any audio signal
+ * level above this value becomes compressed.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \return threshold level value (dB)
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API float libvlc_audio_compressor_get_threshold( libvlc_compressor_t *p_compressor );
+
+/**
+ * Set a new ratio value for a compressor. This value represents a ratio of an
+ * audio signal's input level beyond its threshold to its output level.
+ *
+ * The new compressor settings are subsequently applied to a media player by
+ * invoking libvlc_media_player_set_compressor().
+ *
+ * The supplied value will be clamped to the 1.0 to 20.0 range.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \param f_ratio ratio value (1.0 to 20.0)
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_audio_compressor_set_ratio( libvlc_compressor_t *p_compressor, float f_ratio );
+
+/**
+ * Get the current ratio value from a compressor. This value represents a ratio
+ * of an audio signal's input level beyond its threshold to its output level.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \return ratio value
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API float libvlc_audio_compressor_get_ratio( libvlc_compressor_t *p_compressor );
+
+/**
+ * Set a new knee radius value for a compressor. This value determines how
+ * gradual to make the audio signal transition from non-compressed to
+ * compressed at the threshold.
+ *
+ * The new compressor settings are subsequently applied to a media player by
+ * invoking libvlc_media_player_set_compressor().
+ *
+ * The supplied value will be clamped to the 1.0 to 10.0 range.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \param f_knee knee radius value (1.0 to 10.0 dB)
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_audio_compressor_set_knee( libvlc_compressor_t *p_compressor, float f_knee );
+
+/**
+ * Get the current knee radius value from a compressor. This value determines
+ * how gradual to make the audio signal transition from non-compressed to
+ * compressed at the threshold.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \return knee radius value (dB)
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API float libvlc_audio_compressor_get_knee( libvlc_compressor_t *p_compressor );
+
+/**
+ * Set a new makeup gain value for a compressor. This value determines the
+ * amount of gain to add to the compressed signal to make up for its reduction.
+ *
+ * The new compressor settings are subsequently applied to a media player by
+ * invoking libvlc_media_player_set_compressor().
+ *
+ * The supplied value will be clamped to the 0.0 to 24.0 range.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \param f_makeup_gain makeup gain value (0.0 to 24.0 dB)
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_audio_compressor_set_makeup_gain( libvlc_compressor_t *p_compressor, float f_makeup_gain );
+
+/**
+ * Get the current makeup gain value from a compressor. This value determines
+ * the amount of gain to add to the compressed signal to make up for its
+ * reduction.
+ *
+ * \param p_compressor valid compressor handle, must not be NULL
+ * \return makeup gain value (dB)
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API float libvlc_audio_compressor_get_makeup_gain( libvlc_compressor_t *p_compressor );
+
+/**
+ * Apply new compressor settings to a media player.
+ *
+ * The compressor is first created by invoking libvlc_audio_compressor_new().
+ *
+ * It is possible to apply new compressor settings to a media player whether
+ * the media player is currently playing media or not.
+ *
+ * Invoking this method will immediately apply the new compressor settings to
+ * the audio output of the currently playing media if there is any.
+ *
+ * If there is no currently playing media, the new compressor settings will be
+ * applied later if and when new media is played.
+ *
+ * Compressor settings will automatically be applied to subsequently played
+ * media.
+ *
+ * To disable the compressor for a media player invoke this method passing NULL
+ * for the p_compressor parameter.
+ *
+ * The media player does not keep a reference to the supplied compressor so it
+ * is safe for an application to release the compressor reference any time
+ * after this method returns.
+ *
+ * \param p_mi opaque media player handle
+ * \param p_compressor opaque compressor handle, or NULL to disable the
+ * compressor for this media player
+ * \return zero on success, -1 on error
+ * \version LibVLC 3.0.0 or later
+ */
+LIBVLC_API int libvlc_media_player_set_compressor( libvlc_media_player_t *p_mi, libvlc_compressor_t *p_compressor );
+
/**
* Media player roles.
*
diff --git a/lib/audio.c b/lib/audio.c
index 97d7300..8f4ad0d 100644
--- a/lib/audio.c
+++ b/lib/audio.c
@@ -56,6 +56,19 @@ static audio_output_t *GetAOut( libvlc_media_player_t *mp )
return p_aout;
}
+static int SetValue( float * pf_out, float f_in, float f_min, float f_max )
+{
+ if( isnan(f_in) )
+ return -1;
+ if( f_in < f_min )
+ f_in = f_min;
+ else if( f_in > f_max )
+ f_in = f_max;
+
+ *pf_out = f_in;
+ return 0;
+}
+
/*****************************************
* Get the list of available audio outputs
*****************************************/
@@ -646,3 +659,145 @@ float libvlc_audio_equalizer_get_amp_at_index( libvlc_equalizer_t *p_equalizer,
return p_equalizer->f_amp[ u_band ];
}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_new : Create a new dynamic range compressor with default values
+ *****************************************************************************/
+libvlc_compressor_t *libvlc_audio_compressor_new( void )
+{
+ libvlc_compressor_t *p_compressor;
+ p_compressor = malloc( sizeof( *p_compressor ) );
+ if ( unlikely( p_compressor == NULL ) )
+ return NULL;
+
+ p_compressor->f_rms_peak = 0.f;
+ p_compressor->f_attack = 25.f;
+ p_compressor->f_release = 100.f;
+ p_compressor->f_threshold = -11.f;
+ p_compressor->f_ratio = 8.f;
+ p_compressor->f_knee = 2.5f;
+ p_compressor->f_makeup_gain = 7.f;
+
+ return p_compressor;
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_release : Release a previously created compressor
+ *****************************************************************************/
+void libvlc_audio_compressor_release( libvlc_compressor_t *p_compressor )
+{
+ free( p_compressor );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_set_rms_peak : Set the RMS/peak value for a compressor
+ *****************************************************************************/
+int libvlc_audio_compressor_set_rms_peak( libvlc_compressor_t *p_compressor, float f_rms_peak )
+{
+ return SetValue( &p_compressor->f_rms_peak, f_rms_peak, 0.f, 1.f );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_get_rms_peak : Get the RMS/peak value for a compressor
+ *****************************************************************************/
+float libvlc_audio_compressor_get_rms_peak( libvlc_compressor_t *p_compressor )
+{
+ return p_compressor->f_rms_peak;
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_set_attack : Set the attack value for a compressor
+ *****************************************************************************/
+int libvlc_audio_compressor_set_attack( libvlc_compressor_t *p_compressor, float f_attack )
+{
+ return SetValue( &p_compressor->f_attack, f_attack, 1.5f, 400.f );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_get_attack : Get the attack value for a compressor
+ *****************************************************************************/
+float libvlc_audio_compressor_get_attack( libvlc_compressor_t *p_compressor )
+{
+ return p_compressor->f_attack;
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_set_release : Set the release value for a compressor
+ *****************************************************************************/
+int libvlc_audio_compressor_set_release( libvlc_compressor_t *p_compressor, float f_release )
+{
+ return SetValue( &p_compressor->f_release, f_release, 2.f, 800.f );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_get_release : Get the release value for a compressor
+ *****************************************************************************/
+float libvlc_audio_compressor_get_release( libvlc_compressor_t *p_compressor )
+{
+ return p_compressor->f_release;
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_set_threshold : Set the threshold value for a compressor
+ *****************************************************************************/
+int libvlc_audio_compressor_set_threshold( libvlc_compressor_t *p_compressor, float f_threshold )
+{
+ return SetValue( &p_compressor->f_threshold, f_threshold, -30.f, 0.f );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_get_threshold : Get the threshold value for a compressor
+ *****************************************************************************/
+float libvlc_audio_compressor_get_threshold( libvlc_compressor_t *p_compressor )
+{
+ return p_compressor->f_threshold;
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_set_ratio : Set the ratio value for a compressor
+ *****************************************************************************/
+int libvlc_audio_compressor_set_ratio( libvlc_compressor_t *p_compressor, float f_ratio )
+{
+ return SetValue( &p_compressor->f_ratio, f_ratio, 1.f, 20.f );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_get_ratio : Get the ratio value for a compressor
+ *****************************************************************************/
+float libvlc_audio_compressor_get_ratio( libvlc_compressor_t *p_compressor )
+{
+ return p_compressor->f_ratio;
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_set_knee : Set the knee radius value for a compressor
+ *****************************************************************************/
+int libvlc_audio_compressor_set_knee( libvlc_compressor_t *p_compressor, float f_knee )
+{
+ return SetValue( &p_compressor->f_knee, f_knee, 1.f, 10.f );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_get_knee : Get the knee radius value for a compressor
+ *****************************************************************************/
+float libvlc_audio_compressor_get_knee( libvlc_compressor_t *p_compressor )
+{
+ return p_compressor->f_knee;
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_set_makeup_gain : Set the makeup gain value for a compressor
+ *****************************************************************************/
+int libvlc_audio_compressor_set_makeup_gain( libvlc_compressor_t *p_compressor, float f_makeup_gain )
+{
+ return SetValue( &p_compressor->f_makeup_gain, f_makeup_gain, 0.f, 24.f );
+}
+
+/*****************************************************************************
+ * libvlc_audio_compressor_get_makeup_gain : Get the makeup gain value for a compressor
+ *****************************************************************************/
+float libvlc_audio_compressor_get_makeup_gain( libvlc_compressor_t *p_compressor )
+{
+ return p_compressor->f_makeup_gain;
+}
+
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index 482d95f..b5bb3cb 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -3,6 +3,22 @@ libvlc_clearerr
libvlc_printerr
libvlc_vprinterr
libvlc_add_intf
+libvlc_audio_compressor_get_attack
+libvlc_audio_compressor_get_knee
+libvlc_audio_compressor_get_makeup_gain
+libvlc_audio_compressor_get_ratio
+libvlc_audio_compressor_get_release
+libvlc_audio_compressor_get_rms_peak
+libvlc_audio_compressor_get_threshold
+libvlc_audio_compressor_new
+libvlc_audio_compressor_release
+libvlc_audio_compressor_set_attack
+libvlc_audio_compressor_set_knee
+libvlc_audio_compressor_set_makeup_gain
+libvlc_audio_compressor_set_ratio
+libvlc_audio_compressor_set_release
+libvlc_audio_compressor_set_rms_peak
+libvlc_audio_compressor_set_threshold
libvlc_audio_equalizer_get_amp_at_index
libvlc_audio_equalizer_get_band_count
libvlc_audio_equalizer_get_band_frequency
@@ -190,6 +206,7 @@ libvlc_media_player_set_agl
libvlc_media_player_set_android_context
libvlc_media_player_set_chapter
libvlc_media_player_set_equalizer
+libvlc_media_player_set_compressor
libvlc_media_player_set_hwnd
libvlc_media_player_set_media
libvlc_media_player_set_nsobject
diff --git a/lib/media_player.c b/lib/media_player.c
index fda1091..688cd65 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -2036,6 +2036,41 @@ int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equal
return 0;
}
+int libvlc_media_player_set_compressor( libvlc_media_player_t *p_mi, libvlc_compressor_t *p_compressor )
+{
+ if( p_compressor != NULL )
+ {
+ var_SetFloat( p_mi, "compressor-rms-peak", p_compressor->f_rms_peak );
+ var_SetFloat( p_mi, "compressor-attack", p_compressor->f_attack );
+ var_SetFloat( p_mi, "compressor-release", p_compressor->f_release );
+ var_SetFloat( p_mi, "compressor-threshold", p_compressor->f_threshold );
+ var_SetFloat( p_mi, "compressor-ratio", p_compressor->f_ratio );
+ var_SetFloat( p_mi, "compressor-knee", p_compressor->f_knee );
+ var_SetFloat( p_mi, "compressor-makeup-gain", p_compressor->f_makeup_gain );
+ }
+ var_SetString( p_mi, "audio-filter", p_compressor ? "compressor" : "" );
+
+ audio_output_t *p_aout = input_resource_HoldAout( p_mi->input.p_resource );
+ if( p_aout != NULL )
+ {
+ if( p_compressor != NULL )
+ {
+ var_SetFloat( p_aout, "compressor-rms-peak", p_compressor->f_rms_peak );
+ var_SetFloat( p_aout, "compressor-attack", p_compressor->f_attack );
+ var_SetFloat( p_aout, "compressor-release", p_compressor->f_release );
+ var_SetFloat( p_aout, "compressor-threshold", p_compressor->f_threshold );
+ var_SetFloat( p_aout, "compressor-ratio", p_compressor->f_ratio );
+ var_SetFloat( p_aout, "compressor-knee", p_compressor->f_knee );
+ var_SetFloat( p_aout, "compressor-makeup-gain", p_compressor->f_makeup_gain );
+ }
+
+ var_SetString( p_aout, "audio-filter", p_compressor ? "compressor" : "" );
+ vlc_object_release( p_aout );
+ }
+
+ return 0;
+}
+
static const char roles[][16] =
{
[libvlc_role_Music] = "music",
diff --git a/lib/media_player_internal.h b/lib/media_player_internal.h
index 08b44d2..a6ac514 100644
--- a/lib/media_player_internal.h
+++ b/lib/media_player_internal.h
@@ -76,4 +76,18 @@ struct libvlc_equalizer_t
float f_amp[EQZ_BANDS_MAX];
};
+/**
+ * Internal compressor structure.
+ */
+struct libvlc_compressor_t
+{
+ float f_rms_peak;
+ float f_attack;
+ float f_release;
+ float f_threshold;
+ float f_ratio;
+ float f_knee;
+ float f_makeup_gain;
+};
+
#endif
diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index 815c830..3c21c5b 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -350,6 +350,15 @@ audio_output_t *aout_New (vlc_object_t *parent)
var_Create (aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
var_Create (aout, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
+ /* Compressor */
+ var_Create (aout, "compressor-rms-peak", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+ var_Create (aout, "compressor-attack", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+ var_Create (aout, "compressor-release", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+ var_Create (aout, "compressor-threshold", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+ var_Create (aout, "compressor-ratio", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+ var_Create (aout, "compressor-knee", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+ var_Create (aout, "compressor-makeup-gain", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+
return aout;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment