Mercurial > mplayer.hg
changeset 6430:97857ca97a8f
Adding equalizer plugin
author | anders |
---|---|
date | Sat, 15 Jun 2002 06:15:07 +0000 |
parents | bff56f37f2ff |
children | bf1fec03a065 |
files | libao2/Makefile libao2/audio_plugin.h libao2/eq.h libao2/pl_eq.c |
diffstat | 4 files changed, 245 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/libao2/Makefile Fri Jun 14 17:40:36 2002 +0000 +++ b/libao2/Makefile Sat Jun 15 06:15:07 2002 +0000 @@ -4,7 +4,7 @@ LIBNAME = libao2.a # TODO: moveout ao_sdl.c so it's only used when SDL is detected -SRCS=afmt.c audio_out.c ao_mpegpes.c ao_null.c ao_pcm.c ao_plugin.c pl_delay.c pl_format.c pl_surround.c remez.c pl_resample.c pl_volume.c pl_extrastereo.c pl_volnorm.c $(OPTIONAL_SRCS) +SRCS=afmt.c audio_out.c ao_mpegpes.c ao_null.c ao_pcm.c ao_plugin.c pl_delay.c pl_format.c pl_surround.c remez.c pl_resample.c pl_volume.c pl_extrastereo.c pl_volnorm.c pl_eq.c $(OPTIONAL_SRCS) OBJS=$(SRCS:.c=.o)
--- a/libao2/audio_plugin.h Fri Jun 14 17:40:36 2002 +0000 +++ b/libao2/audio_plugin.h Sat Jun 15 06:15:07 2002 +0000 @@ -56,7 +56,7 @@ // This block should not be available in the pl_xxxx files // due to compilation issues #ifndef PLUGIN -#define NPL 7+1 // Number of PLugins ( +1 list ends with NULL ) +#define NPL 8+1 // Number of PLugins ( +1 list ends with NULL ) // List of plugins extern ao_plugin_functions_t audio_plugin_delay; extern ao_plugin_functions_t audio_plugin_format; @@ -65,7 +65,7 @@ extern ao_plugin_functions_t audio_plugin_volume; extern ao_plugin_functions_t audio_plugin_extrastereo; extern ao_plugin_functions_t audio_plugin_volnorm; - +extern ao_plugin_functions_t audio_plugin_eq; #define AO_PLUGINS { \ &audio_plugin_delay, \ @@ -75,6 +75,7 @@ &audio_plugin_volume, \ &audio_plugin_extrastereo, \ &audio_plugin_volnorm, \ + &audio_plugin_eq, \ NULL \ } #endif /* PLUGIN */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libao2/eq.h Sat Jun 15 06:15:07 2002 +0000 @@ -0,0 +1,36 @@ +/*============================================================================= +// +// This software has been released under the terms of the GNU Public +// license. See http://www.gnu.org/copyleft/gpl.html for details. +// +// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au +// +//============================================================================= +*/ + +/* Equalizer plugin header file defines struct used for setting or + getting the gain of a specific channel and frequency */ + +typedef struct equalizer_s +{ + float gain; // Gain in db -15 - 15 + int channel; // Channel number 0 - 5 + int band; // Frequency band 0 - 9 +}equalizer_t; + +/* The different frequency bands are: +nr. center frequency +0 31.25 Hz +1 62.50 Hz +2 125.0 Hz +3 250.0 Hz +4 500.0 Hz +5 1.000 kHz +6 2.000 kHz +7 4.000 kHz +8 8.000 kHz +9 16.00 kHz +*/ + +#define AOCONTROL_PLUGIN_EQ_SET_GAIN 2 // Use this to set the gain +#define AOCONTROL_PLUGIN_EQ_GET_GAIN 3 // Use this to get the gain
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libao2/pl_eq.c Sat Jun 15 06:15:07 2002 +0000 @@ -0,0 +1,205 @@ +/*============================================================================= +// +// This software has been released under the terms of the GNU Public +// license. See http://www.gnu.org/copyleft/gpl.html for details. +// +// Copyright 2001 Anders Johansson ajh@atri.curtin.edu.au +// +//============================================================================= +*/ + +/* Equalizer plugin, implementation of a 10 band time domain graphic + equalizer using IIR filters. The IIR filters are implemented using a + Direct Form II approach. But has been modified (b1 == 0 always) to + save computation. +*/ +#define PLUGIN + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <inttypes.h> +#include <math.h> + +#include "audio_out.h" +#include "audio_plugin.h" +#include "audio_plugin_internal.h" +#include "afmt.h" +#include "eq.h" + +static ao_info_t info = +{ + "Equalizer audio plugin", + "eq", + "Anders", + "" +}; + +LIBAO_PLUGIN_EXTERN(eq) + + +#define CH 6 // Max number of channels +#define L 2 // Storage for filter taps +#define KM 10 // Max number of octaves + +#define Q 1.2247 /* Q value for band-pass filters 1.2247=(3/2)^(1/2) + gives 4db suppression @ Fc*2 and Fc/2 */ + +// Center frequencies for band-pass filters +#define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000} + +// local data +typedef struct pl_eq_s +{ + int16_t a[KM][L]; // A weights + int16_t b[KM][L]; // B weights + int16_t wq[CH][KM][L]; // Circular buffer for W data + int16_t g[CH][KM]; // Gain factor for each channel and band + int16_t K; // Number of used eq bands + int channels; // Number of channels +} pl_eq_t; + +static pl_eq_t pl_eq; + +// to set/get/query special features/parameters +static int control(int cmd,int arg){ + switch(cmd){ + case AOCONTROL_PLUGIN_SET_LEN: + return CONTROL_OK; + case AOCONTROL_PLUGIN_EQ_SET_GAIN:{ + float gain = ((equalizer_t*)arg)->gain; + int ch =((equalizer_t*)arg)->channel; + int band =((equalizer_t*)arg)->band; + if(ch > CH || ch < 0 || band > KM || band < 0) + return CONTROL_ERROR; + + pl_eq.g[ch][band]=(int16_t) 4096 * (pow(10.0,gain/20.0)-1.0); + return CONTROL_OK; + } + case AOCONTROL_PLUGIN_EQ_GET_GAIN:{ + int ch =((equalizer_t*)arg)->channel; + int band =((equalizer_t*)arg)->band; + if(ch > CH || ch < 0 || band > KM || band < 0) + return CONTROL_ERROR; + + ((equalizer_t*)arg)->gain = log10((float)pl_eq.g[ch][band]/4096.0+1) * 20.0; + return CONTROL_OK; + } + } + return CONTROL_UNKNOWN; +} + +// 2nd order Band-pass Filter design +void bp2(int16_t* a, int16_t* b, float fc, float q){ + double th=2*3.141592654*fc; + double C=(1 - tan(th*q/2))/(1 + tan(th*q/2)); + + a[0] = (int16_t)lround( 16383.0 * (1 + C) * cos(th)); + a[1] = (int16_t)lround(-16383.0 * C); + + b[0] = (int16_t)lround(-16383.0 * (C - 1)/2); + b[1] = (int16_t)lround(-16383.0 * 1.0050); +} + +// empty buffers +static void reset(){ + int k,l,c; + for(c=0;c<pl_eq.channels;c++) + for(k=0;k<pl_eq.K;k++) + for(l=0;l<L*2;l++) + pl_eq.wq[c][k][l]=0; +} + +// open & setup audio device +// return: 1=success 0=fail +static int init(){ + int c,k = 0; + float F[KM] = CF; + + // Check input format + if(ao_plugin_data.format != AFMT_S16_LE){ + fprintf(stderr,"[pl_eq] Input audio format not yet supported. \n"); + return 0; + } + + // Check number of channels + if(ao_plugin_data.channels>CH){ + fprintf(stderr,"[pl_eq] Too many channels, max is 6.\n"); + return 0; + } + pl_eq.channels=ao_plugin_data.channels; + + // Calculate number of active filters + pl_eq.K=KM; + while(F[pl_eq.K-1] > (float)ao_plugin_data.rate/2) + pl_eq.K--; + + // Generate filter taps + for(k=0;k<pl_eq.K;k++) + bp2(pl_eq.a[k],pl_eq.b[k],F[k]/((float)ao_plugin_data.rate),Q); + + // Reset buffers + reset(); + + // Reset gain factors + for(c=0;c<pl_eq.channels;c++) + for(k=0;k<pl_eq.K;k++) + pl_eq.g[c][k]=0; + + // Tell ao_plugin how much this plugin adds to the overall time delay + ao_plugin_data.delay_fix-=2/((float)pl_eq.channels*(float)ao_plugin_data.rate); + // Print some cool remark of what the plugin does + printf("[pl_eq] Equalizer in use.\n"); + return 1; +} + +// close plugin +static void uninit(){ +} + +// processes 'ao_plugin_data.len' bytes of 'data' +// called for every block of data +static int play(){ + uint16_t ci = pl_eq.channels; // Index for channels + uint16_t nch = pl_eq.channels; // Number of channels + + while(ci--){ + int16_t* g = pl_eq.g[ci]; // Gain factor + int16_t* in = ((int16_t*)ao_plugin_data.data)+ci; + int16_t* out = ((int16_t*)ao_plugin_data.data)+ci; + int16_t* end = in+ao_plugin_data.len/2; // Block loop end + + while(in < end){ + register int16_t k = 0; // Frequency band index + register int32_t yt = 0; // Total output from filters + register int16_t x = *in; /* Current input sample scale + to prevent overflow in wq */ + in+=nch; + + // Run the filters + for(;k<pl_eq.K;k++){ + // Pointer to circular buffer wq + register int16_t* wq = pl_eq.wq[ci][k]; + // Calculate output from AR part of current filter + register int32_t xt = (x*pl_eq.b[k][0]) >> 4; + register int32_t w = xt + wq[0]*pl_eq.a[k][0] + wq[1]*pl_eq.a[k][1]; + // Calculate output form MA part of current filter + yt+=(((w + wq[1]*pl_eq.b[k][1]) >> 10)*g[k]) >> 12; + // Update circular buffer + wq[1] = wq[0]; wq[0] = w >> 14; + } + + // Calculate output + *out=(int16_t)(yt+x); + out+=nch; + } + } + return 1; +} + + + + + + +