[vlc-devel] [PATCH 1/2] libvlc: add equalizer API

Mark Lee mark.lee at capricasoftware.co.uk
Sat Jul 13 20:21:37 CEST 2013


Functions are provided to:

 * query the available equalizer presets
 * create a new default equalizer instance
 * create an equalizer instance from a preset
 * set individual equalizer band amplitudes
 * set equalizer pre-amplification
 * apply an equalizer to a media player

Equalizer settings can be applied whether media is playing or not,
and will automatically be retained when playing media subsequently.
---
 include/vlc/libvlc_media_player.h        | 171 +++++++++++++++++++++++++++++++
 lib/audio.c                              | 135 ++++++++++++++++++++++++
 lib/libvlc.sym                           |  12 +++
 lib/media_player.c                       |  65 ++++++++++++
 lib/media_player_internal.h              |  11 ++
 modules/audio_filter/equalizer.c         |  13 ---
 modules/audio_filter/equalizer_presets.h |  16 +++
 src/audio_output/filters.c               |   8 +-
 src/audio_output/output.c                |   3 +
 9 files changed, 419 insertions(+), 15 deletions(-)

diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h
index 82c7ac2..27f7b97 100644
--- a/include/vlc/libvlc_media_player.h
+++ b/include/vlc/libvlc_media_player.h
@@ -137,6 +137,13 @@ typedef enum libvlc_position_t {
 } libvlc_position_t;
 
 /**
+ * Opaque equalizer handle.
+ *
+ * Equalizer settings can be applied to a media player.
+ */
+typedef struct libvlc_equalizer_t libvlc_equalizer_t;
+
+/**
  * Create an empty Media Player object
  *
  * \param p_libvlc_instance the libvlc instance in which the Media Player
@@ -1648,6 +1655,170 @@ LIBVLC_API int64_t libvlc_audio_get_delay( libvlc_media_player_t *p_mi );
  */
 LIBVLC_API int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay );
 
+/**
+ * Get the number of equalizer presets.
+ *
+ * \return number of presets
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API unsigned libvlc_audio_equalizer_get_preset_count( void );
+
+/**
+ * Get the name of a particular equalizer preset.
+ *
+ * This name can be used, for example, to prepare a preset label or menu in a user
+ * interface.
+ *
+ * \param u_index index of the preset, counting from zero
+ * \return preset name, or NULL if there is no such preset
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API const char *libvlc_audio_equalizer_get_preset_name( unsigned u_index );
+
+/**
+ * Get the number of distinct frequency bands for an equalizer.
+ *
+ * \return number of frequency bands
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API unsigned libvlc_audio_equalizer_get_band_count( void );
+
+/**
+ * Get a particular equalizer band frequency.
+ *
+ * This value can be used, for example, to create a label for an equalizer band control
+ * in a user interface.
+ *
+ * \param u_index index of the band, counting from zero
+ * \return equalizer band frequency (Hz), or -1 if there is no such band
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API float libvlc_audio_equalizer_get_band_frequency( unsigned u_index );
+
+/**
+ * Create a new default equalizer, with all frequency values zeroed.
+ *
+ * The new equalizer can subsequently be applied to a media player by invoking
+ * libvlc_media_player_set_equalizer().
+ *
+ * The returned handle should be freed via libvlc_audio_equalizer_release() when
+ * it is no longer needed.
+ *
+ * \return opaque equalizer handle, or NULL on error
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API libvlc_equalizer_t *libvlc_audio_equalizer_new( void );
+
+/**
+ * Create a new equalizer, with initial frequency values copied from an existing
+ * preset.
+ *
+ * The new equalizer can subsequently be applied to a media player by invoking
+ * libvlc_media_player_set_equalizer().
+ *
+ * The returned handle should be freed via libvlc_audio_equalizer_release() when
+ * it is no longer needed.
+ *
+ * \param u_index index of the preset, counting from zero
+ * \return opaque equalizer handle, or NULL on error
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API libvlc_equalizer_t *libvlc_audio_equalizer_new_from_preset( unsigned u_index );
+
+/**
+ * Release a previously created equalizer instance.
+ *
+ * The equalizer was previously created by using libvlc_audio_equalizer_new() or
+ * libvlc_audio_equalizer_new_from_preset().
+ *
+ * It is safe to invoke this method with a NULL p_equalizer parameter for no effect.
+ *
+ * \param p_equalizer opaque equalizer handle, or NULL
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API void libvlc_audio_equalizer_release( libvlc_equalizer_t *p_equalizer );
+
+/**
+ * Set a new pre-amplification value for an equalizer.
+ *
+ * The new equalizer settings are subsequently applied to a media player by invoking
+ * libvlc_media_player_set_equalizer().
+ *
+ * The supplied amplification value will be clamped to the -20.0 to +20.0 range.
+ *
+ * \param p_equalizer valid equalizer handle, must not be NULL
+ * \param f_preamp preamp value (-20.0 to 20.0 Hz)
+ * \return zero on success, -1 on error
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API int libvlc_audio_equalizer_set_preamp( libvlc_equalizer_t *p_equalizer, float f_preamp );
+
+/**
+ * Get the current pre-amplification value from an equalizer.
+ *
+ * \param p_equalizer valid equalizer handle, must not be NULL
+ * \return preamp value (Hz)
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API float libvlc_audio_equalizer_get_preamp( libvlc_equalizer_t *p_equalizer );
+
+/**
+ * Set a new amplification value for a particular equalizer frequency band.
+ *
+ * The new equalizer settings are subsequently applied to a media player by invoking
+ * libvlc_media_player_set_equalizer().
+ *
+ * The supplied amplification value will be clamped to the -20.0 to +20.0 range.
+ *
+ * \param p_equalizer valid equalizer handle, must not be NULL
+ * \param f_amp amplification value (-20.0 to 20.0 Hz)
+ * \param u_band index, counting from zero, of the frequency band to set
+ * \return zero on success, -1 on error
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API int libvlc_audio_equalizer_set_amp_at_index( libvlc_equalizer_t *p_equalizer, float f_amp, unsigned u_band );
+
+/**
+ * Get the amplification value for a particular equalizer frequency band.
+ *
+ * \param p_equalizer valid equalizer handle, must not be NULL
+ * \param u_band index, counting from zero, of the frequency band to get
+ * \return amplification value (Hz); zero if there is no such frequency band
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API float libvlc_audio_equalizer_get_amp_at_index( libvlc_equalizer_t *p_equalizer, unsigned u_band );
+
+/**
+ * Apply new equalizer settings to a media player.
+ *
+ * The equalizer is first created by invoking libvlc_audio_equalizer_new() or
+ * libvlc_audio_equalizer_new_from_preset().
+ *
+ * It is possible to apply new equalizer settings to a media player whether the media
+ * player is currently playing media or not.
+ *
+ * Invoking this method will immediately apply the new equalizer settings to the audio
+ * output of the currently playing media if there is any.
+ *
+ * If there is no currently playing media, the new equalizer settings will be applied
+ * later if and when new media is played.
+ *
+ * Equalizer settings will automatically be applied to subsequently played media.
+ *
+ * To disable the equalizer for a media player invoke this method passing NULL for the
+ * p_equalizer parameter.
+ *
+ * The media player does not keep a reference to the supplied equalizer so it is safe
+ * for an application to release the equalizer reference any time after this method
+ * returns.
+ *
+ * \param p_mi opaque media player handle
+ * \param p_equalizer opaque equalizer handle, or NULL to disable the equalizer for this media player
+ * \return zero on success, -1 on error
+ * \version LibVLC 2.2.0 or later
+ */
+LIBVLC_API int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer );
+
 /** @} audio */
 
 /** @} media_player */
diff --git a/lib/audio.c b/lib/audio.c
index d125f5e..fd022ca 100644
--- a/lib/audio.c
+++ b/lib/audio.c
@@ -429,3 +429,138 @@ int libvlc_audio_set_delay( libvlc_media_player_t *p_mi, int64_t i_delay )
     }
     return ret;
 }
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_get_preset_count : Get the number of equalizer presets
+ *****************************************************************************/
+unsigned libvlc_audio_equalizer_get_preset_count( void )
+{
+    return NB_PRESETS;
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_get_preset_name : Get the name for a preset
+ *****************************************************************************/
+const char *libvlc_audio_equalizer_get_preset_name( unsigned u_index )
+{
+    if ( u_index >= NB_PRESETS )
+        return NULL;
+
+    return preset_list_text[ u_index ];
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_get_band_count : Get the number of equalizer frequency bands
+ *****************************************************************************/
+unsigned libvlc_audio_equalizer_get_band_count( void )
+{
+    return EQZ_BANDS_MAX;
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_get_band_frequency : Get the frequency for a band
+ *****************************************************************************/
+float libvlc_audio_equalizer_get_band_frequency( unsigned u_index )
+{
+    if ( u_index >= EQZ_BANDS_MAX )
+        return -1.f;
+
+    return f_vlc_frequency_table_10b[ u_index ];
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_new : Create a new audio equalizer with zeroed values
+ *****************************************************************************/
+libvlc_equalizer_t *libvlc_audio_equalizer_new( void )
+{
+    libvlc_equalizer_t *p_equalizer;
+    p_equalizer = malloc( sizeof( *p_equalizer ) );
+    if ( unlikely( p_equalizer == NULL ) )
+        return NULL;
+
+    p_equalizer->f_preamp = 0.f;
+    for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
+        p_equalizer->f_amp[ i ] = 0.f;
+
+    return p_equalizer;
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_new_from_preset : Create a new audio equalizer based on a preset
+ *****************************************************************************/
+libvlc_equalizer_t *libvlc_audio_equalizer_new_from_preset( unsigned u_index )
+{
+    libvlc_equalizer_t *p_equalizer;
+
+    if ( u_index >= NB_PRESETS )
+        return NULL;
+
+    p_equalizer = malloc( sizeof( *p_equalizer ) );
+    if ( unlikely( p_equalizer == NULL ) )
+        return NULL;
+
+    p_equalizer->f_preamp = eqz_preset_10b[ u_index ].f_preamp;
+
+    for ( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
+        p_equalizer->f_amp[ i ] = eqz_preset_10b[ u_index ].f_amp[ i ];
+
+    return p_equalizer;
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_release : Release a previously created equalizer
+ *****************************************************************************/
+void libvlc_audio_equalizer_release( libvlc_equalizer_t *p_equalizer )
+{
+    free( p_equalizer );
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_set_preamp : Set the preamp value for an equalizer
+ *****************************************************************************/
+int libvlc_audio_equalizer_set_preamp( libvlc_equalizer_t *p_equalizer, float f_preamp )
+{
+    if ( f_preamp < -20.0f )
+        f_preamp = -20.0f;
+    else if ( f_preamp > 20.0f )
+        f_preamp = 20.0f;
+
+    p_equalizer->f_preamp = f_preamp;
+    return 0;
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_get_preamp : Get the preamp value for an equalizer
+ *****************************************************************************/
+float libvlc_audio_equalizer_get_preamp( libvlc_equalizer_t *p_equalizer )
+{
+    return p_equalizer->f_preamp;
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_set_amp_at_index : Set the amplification value for an equalizer band
+ *****************************************************************************/
+int libvlc_audio_equalizer_set_amp_at_index( libvlc_equalizer_t *p_equalizer, float f_amp, unsigned u_band )
+{
+    if ( u_band >= EQZ_BANDS_MAX )
+        return -1;
+
+    if ( f_amp < -20.0f )
+        f_amp = -20.0f;
+    else if ( f_amp > 20.0f )
+        f_amp = 20.0f;
+
+    p_equalizer->f_amp[ u_band ] = f_amp;
+    return 0;
+}
+
+/*****************************************************************************
+ * libvlc_audio_equalizer_get_amp_at_index : Get the amplification value for an equalizer band
+ *****************************************************************************/
+float libvlc_audio_equalizer_get_amp_at_index( libvlc_equalizer_t *p_equalizer, unsigned u_band )
+{
+    if ( u_band >= EQZ_BANDS_MAX )
+        return 0.f;
+
+    return p_equalizer->f_amp[ u_band ];
+}
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index 6a430df..7c99668 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -3,6 +3,17 @@ libvlc_clearerr
 libvlc_printerr
 libvlc_vprinterr
 libvlc_add_intf
+libvlc_audio_equalizer_get_amp_at_index
+libvlc_audio_equalizer_get_band_count
+libvlc_audio_equalizer_get_band_frequency
+libvlc_audio_equalizer_get_preamp
+libvlc_audio_equalizer_get_preset_count
+libvlc_audio_equalizer_get_preset_name
+libvlc_audio_equalizer_new
+libvlc_audio_equalizer_new_from_preset
+libvlc_audio_equalizer_release
+libvlc_audio_equalizer_set_amp_at_index
+libvlc_audio_equalizer_set_preamp
 libvlc_audio_output_device_count
 libvlc_audio_output_device_id
 libvlc_audio_output_device_list_get
@@ -153,6 +164,7 @@ libvlc_media_player_release
 libvlc_media_player_retain
 libvlc_media_player_set_agl
 libvlc_media_player_set_chapter
+libvlc_media_player_set_equalizer
 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 376159f..b4a7250 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -33,6 +33,7 @@
 #include <vlc_demux.h>
 #include <vlc_input.h>
 #include <vlc_vout.h>
+#include <vlc_aout.h>
 #include <vlc_keys.h>
 
 #include "libvlc_internal.h"
@@ -462,6 +463,10 @@ libvlc_media_player_new( libvlc_instance_t *instance )
     var_Create (mp, "video-title-position", VLC_VAR_INTEGER);
     var_Create (mp, "video-title-timeout", VLC_VAR_INTEGER);
 
+    /* Equalizer */
+    var_Create (mp, "equalizer-preamp", VLC_VAR_FLOAT);
+    var_Create (mp, "equalizer-bands", VLC_VAR_STRING);
+
     mp->p_md = NULL;
     mp->state = libvlc_NothingSpecial;
     mp->p_libvlc_instance = instance;
@@ -1404,3 +1409,63 @@ void libvlc_media_player_set_video_title_display( libvlc_media_player_t *p_mi, l
         var_SetBool( p_mi, "video-title-show", false );
     }
 }
+
+/**
+ * Maximum size of a formatted equalizer amplification band frequency value.
+ *
+ * The allowed value range is supposed to be constrained from -20.0 to 20.0.
+ *
+ * The format string " %.07f" with a minimum value of "-20" gives a maximum
+ * string length of e.g. " -19.1234567", i.e. 12 bytes (not including the null
+ * terminator).
+ */
+#define EQZ_BAND_VALUE_SIZE 12
+
+int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer )
+{
+    float f_preamp;
+    char *psz_bands;
+
+    if ( p_equalizer )
+    {
+        f_preamp = p_equalizer->f_preamp;
+
+        psz_bands = malloc( EQZ_BANDS_MAX * EQZ_BAND_VALUE_SIZE + 1 );
+        if ( unlikely( psz_bands == NULL ) )
+            return -1;
+
+        char *p = psz_bands;
+        int c;
+        for ( int i = 0; i < EQZ_BANDS_MAX; i++ )
+        {
+            c = snprintf( p, EQZ_BAND_VALUE_SIZE + 1, " %.07f", p_equalizer->f_amp[i] );
+            if ( unlikely( c >= EQZ_BAND_VALUE_SIZE + 1 ) )
+            {
+                free( psz_bands );
+                return -1;
+            }
+
+            p += c;
+        }
+    }
+    else
+    {
+        f_preamp = 0.f;
+        psz_bands = NULL;
+    }
+
+    var_SetFloat( p_mi, "equalizer-preamp", f_preamp );
+    var_SetString( p_mi, "equalizer-bands", psz_bands );
+
+    audio_output_t *p_aout = input_resource_HoldAout( p_mi->input.p_resource );
+    if ( p_aout )
+    {
+        var_SetFloat( p_aout, "equalizer-preamp", f_preamp );
+        var_SetString( p_aout, "equalizer-bands", psz_bands );
+
+        vlc_object_release( p_aout );
+    }
+
+    free( psz_bands );
+    return 0;
+}
diff --git a/lib/media_player_internal.h b/lib/media_player_internal.h
index 185f183..27fbf1f 100644
--- a/lib/media_player_internal.h
+++ b/lib/media_player_internal.h
@@ -34,6 +34,8 @@
 #include <vlc/libvlc_media.h>
 #include <vlc_input.h>
 
+#include "../modules/audio_filter/equalizer_presets.h"
+
 struct libvlc_media_player_t
 {
     VLC_COMMON_MEMBERS
@@ -62,4 +64,13 @@ libvlc_track_description_t * libvlc_get_track_description(
         libvlc_media_player_t *p_mi,
         const char *psz_variable );
 
+/**
+ * Internal equalizer structure.
+ */
+struct libvlc_equalizer_t
+{
+    float f_preamp;
+    float f_amp[EQZ_BANDS_MAX];
+};
+
 #endif
diff --git a/modules/audio_filter/equalizer.c b/modules/audio_filter/equalizer.c
index 651b4a1..4a362c4 100644
--- a/modules/audio_filter/equalizer.c
+++ b/modules/audio_filter/equalizer.c
@@ -217,19 +217,6 @@ typedef struct
 
 } eqz_config_t;
 
-/* The frequency tables */
-static const float f_vlc_frequency_table_10b[EQZ_BANDS_MAX] =
-{
-    60.0f, 170.0f, 310.0f, 600.0f, 1000.0f, 3000.0f, 6000.0f, 12000.0f,
-    14000.0f, 16000.0f,
-};
-
-static const float f_iso_frequency_table_10b[EQZ_BANDS_MAX] =
-{
-    31.25f, 62.5f, 125.0f, 250.0f, 500.0f, 1000.0f, 2000.0f, 4000.0f,
-    8000.0f, 16000.0f,
-};
-
 /* Equalizer coefficient calculation function based on equ-xmms */
 static void EqzCoeffs( int i_rate, float f_octave_percent,
                        bool b_use_vlc_freqs,
diff --git a/modules/audio_filter/equalizer_presets.h b/modules/audio_filter/equalizer_presets.h
index 03f9f6f..63c9eec 100644
--- a/modules/audio_filter/equalizer_presets.h
+++ b/modules/audio_filter/equalizer_presets.h
@@ -21,6 +21,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
+#ifndef _EQUALIZER_PRESETS_H
+#define _EQUALIZER_PRESETS_H 1
+
 /*****************************************************************************
  * Equalizer presets
  *****************************************************************************/
@@ -30,6 +33,17 @@
 
 #define EQZ_BANDS_MAX 10
 
+/* The frequency tables */
+static const float f_vlc_frequency_table_10b[EQZ_BANDS_MAX] =
+{
+    60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000,
+};
+
+static const float f_iso_frequency_table_10b[EQZ_BANDS_MAX] =
+{
+    31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, 16000,
+};
+
 #define NB_PRESETS 18
 static const char *const preset_list[NB_PRESETS] = {
     "flat", "classical", "club", "dance", "fullbass", "fullbasstreble",
@@ -139,3 +153,5 @@ static const eqz_preset_t eqz_preset_10b[NB_PRESETS] =
           9.6f, 8.8f }
     },
 };
+
+#endif
diff --git a/src/audio_output/filters.c b/src/audio_output/filters.c
index 41b23b4..ea451a3 100644
--- a/src/audio_output/filters.c
+++ b/src/audio_output/filters.c
@@ -314,8 +314,7 @@ static int EqualizerCallback (vlc_object_t *obj, const char *var,
                               void *data)
 {
     const char *val = newval.psz_string;
-
-    if (*val)
+    if (!strcmp("equalizer", var) && *val)
     {
         var_Create (obj, "equalizer-preset", VLC_VAR_STRING);
         var_SetString (obj, "equalizer-preset", val);
@@ -418,7 +417,10 @@ aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
     if (request_vout != NULL)
     {
         var_AddCallback (obj, "equalizer", EqualizerCallback, NULL);
+        var_AddCallback (obj, "equalizer-bands", EqualizerCallback, NULL);
         var_AddCallback (obj, "visual", VisualizationCallback, NULL);
+
+        var_TriggerCallback( obj, "equalizer-bands" );
     }
 
     /* Now add user filters */
@@ -495,6 +497,7 @@ aout_filters_t *aout_FiltersNew (vlc_object_t *obj,
 error:
     aout_FiltersPipelineDestroy (filters->tab, filters->count);
     var_DelCallback (obj, "equalizer", EqualizerCallback, NULL);
+    var_DelCallback (obj, "equalizer-bands", EqualizerCallback, NULL);
     var_DelCallback (obj, "visual", VisualizationCallback, NULL);
     free (filters);
     return NULL;
@@ -517,6 +520,7 @@ void aout_FiltersDelete (vlc_object_t *obj, aout_filters_t *filters)
     if (obj != NULL)
     {
         var_DelCallback (obj, "equalizer", EqualizerCallback, NULL);
+        var_DelCallback (obj, "equalizer-bands", EqualizerCallback, NULL);
         var_DelCallback (obj, "visual", VisualizationCallback, NULL);
     }
     free (filters);
diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index 988d200..185eee6 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -299,6 +299,9 @@ audio_output_t *aout_New (vlc_object_t *parent)
                             &val, &text);
         }
 
+    var_Create (aout, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
+    var_Create (aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
+
     return aout;
 }
 
-- 
1.8.1.2




More information about the vlc-devel mailing list