From c29c0d54f8ca0a9b3ba73970f46688e9f1757af5 Mon Sep 17 00:00:00 2001 From: smorlat <smorlat@3f6dc0c8-ddfe-455d-9043-3cd528dc4637> Date: Mon, 13 Jul 2009 20:26:18 +0000 Subject: [PATCH] equalizer - work in progress. git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@535 3f6dc0c8-ddfe-455d-9043-3cd528dc4637 --- linphone/INSTALL | 50 +++--- linphone/mediastreamer2/INSTALL | 50 +++--- .../include/mediastreamer2/Makefile.am | 3 +- .../include/mediastreamer2/allfilters.h | 3 +- linphone/mediastreamer2/src/Makefile.am | 3 +- linphone/mediastreamer2/src/dsptools.c | 2 +- linphone/mediastreamer2/src/equalizer.c | 163 +++++++++++++++--- linphone/po/Makefile.in.in | 4 +- 8 files changed, 204 insertions(+), 74 deletions(-) mode change 100755 => 100644 linphone/INSTALL mode change 100755 => 100644 linphone/mediastreamer2/INSTALL mode change 100755 => 100644 linphone/po/Makefile.in.in diff --git a/linphone/INSTALL b/linphone/INSTALL old mode 100755 new mode 100644 index 5458714e1e..23e5f25d0e --- a/linphone/INSTALL +++ b/linphone/INSTALL @@ -1,8 +1,8 @@ Installation Instructions ************************* -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006 Free Software Foundation, Inc. +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -10,10 +10,7 @@ unlimited permission to copy, distribute and modify it. Basic Installation ================== -Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the `README' file for -instructions specific to this package. +These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses @@ -26,9 +23,9 @@ debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. Caching is +the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale -cache files. +cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail @@ -38,17 +35,20 @@ some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You need `configure.ac' if -you want to change it or regenerate `configure' using a newer version -of `autoconf'. +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. - Running `configure' might take a while. While running, it prints - some messages telling which features it is checking for. + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. 2. Type `make' to compile the package. @@ -78,7 +78,7 @@ details on some of the pertinent environment variables. by setting variables in the command line or in the environment. Here is an example: - ./configure CC=c99 CFLAGS=-g LIBS=-lposix + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. @@ -87,15 +87,17 @@ Compiling For Multiple Architectures You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU `make'. `cd' to the +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. - With a non-GNU `make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use `make distclean' before -reconfiguring for another architecture. + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. Installation Names ================== @@ -188,12 +190,12 @@ them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). +overridden in the site shell script). Here is a another example: -Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: + /bin/bash ./configure CONFIG_SHELL=/bin/bash - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. `configure' Invocation ====================== diff --git a/linphone/mediastreamer2/INSTALL b/linphone/mediastreamer2/INSTALL old mode 100755 new mode 100644 index 5458714e1e..23e5f25d0e --- a/linphone/mediastreamer2/INSTALL +++ b/linphone/mediastreamer2/INSTALL @@ -1,8 +1,8 @@ Installation Instructions ************************* -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, -2006 Free Software Foundation, Inc. +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. @@ -10,10 +10,7 @@ unlimited permission to copy, distribute and modify it. Basic Installation ================== -Briefly, the shell commands `./configure; make; make install' should -configure, build, and install this package. The following -more-detailed instructions are generic; see the `README' file for -instructions specific to this package. +These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses @@ -26,9 +23,9 @@ debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. Caching is +the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale -cache files. +cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail @@ -38,17 +35,20 @@ some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You need `configure.ac' if -you want to change it or regenerate `configure' using a newer version -of `autoconf'. +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. - Running `configure' might take a while. While running, it prints - some messages telling which features it is checking for. + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. 2. Type `make' to compile the package. @@ -78,7 +78,7 @@ details on some of the pertinent environment variables. by setting variables in the command line or in the environment. Here is an example: - ./configure CC=c99 CFLAGS=-g LIBS=-lposix + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. @@ -87,15 +87,17 @@ Compiling For Multiple Architectures You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their -own directory. To do this, you can use GNU `make'. `cd' to the +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. - With a non-GNU `make', it is safer to compile the package for one -architecture at a time in the source code directory. After you have -installed the package for one architecture, use `make distclean' before -reconfiguring for another architecture. + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. Installation Names ================== @@ -188,12 +190,12 @@ them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). +overridden in the site shell script). Here is a another example: -Unfortunately, this technique does not work for `CONFIG_SHELL' due to -an Autoconf bug. Until the bug is fixed you can use this workaround: + /bin/bash ./configure CONFIG_SHELL=/bin/bash - CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. `configure' Invocation ====================== diff --git a/linphone/mediastreamer2/include/mediastreamer2/Makefile.am b/linphone/mediastreamer2/include/mediastreamer2/Makefile.am index 3fb6087260..83343ab969 100644 --- a/linphone/mediastreamer2/include/mediastreamer2/Makefile.am +++ b/linphone/mediastreamer2/include/mediastreamer2/Makefile.am @@ -21,7 +21,8 @@ mediastreamer2_include_HEADERS= ice.h \ mstee.h \ rfc3984.h \ mswebcam.h \ - dsptools.h + dsptools.h \ + msequalizer.h EXTRA_DIST=$(mediastreamer2_include_HEADERS) diff --git a/linphone/mediastreamer2/include/mediastreamer2/allfilters.h b/linphone/mediastreamer2/include/mediastreamer2/allfilters.h index 82664afd24..3643665646 100644 --- a/linphone/mediastreamer2/include/mediastreamer2/allfilters.h +++ b/linphone/mediastreamer2/include/mediastreamer2/allfilters.h @@ -85,7 +85,8 @@ typedef enum MSFilterId{ MS_VOID_SINK_ID, MS_DSCAP_ID, MS_AQ_READ_ID, - MS_AQ_WRITE_ID + MS_AQ_WRITE_ID, + MS_EQUALIZER_ID } MSFilterId; diff --git a/linphone/mediastreamer2/src/Makefile.am b/linphone/mediastreamer2/src/Makefile.am index faf0f61986..8c1d0070a5 100644 --- a/linphone/mediastreamer2/src/Makefile.am +++ b/linphone/mediastreamer2/src/Makefile.am @@ -35,7 +35,8 @@ libmediastreamer_la_SOURCES= mscommon.c \ _kiss_fft_guts.h \ kiss_fft.h \ kiss_fftr.c \ - kiss_fftr.h + kiss_fftr.h \ + equalizer.c #dummy c++ file to force libtool to use c++ linking (because of msdscap-mingw.cc) nodist_EXTRA_libmediastreamer_la_SOURCES = dummy.cxx diff --git a/linphone/mediastreamer2/src/dsptools.c b/linphone/mediastreamer2/src/dsptools.c index 184f0afcb7..d06a7ebdb6 100644 --- a/linphone/mediastreamer2/src/dsptools.c +++ b/linphone/mediastreamer2/src/dsptools.c @@ -229,7 +229,7 @@ void ms_fir_mem16(const ms_word16_t *x, const ms_coef_t *num, ms_word16_t *y, in for (i=0;i<N;i++) { xi=x[i]; - yi = EXTRACT16(SATURATE(ADD32(EXTEND32(x[i]),PSHR32(mem[0],LPC_SHIFT)),32767)); + yi = EXTRACT16(SATURATE(ADD32(EXTEND32(xi),PSHR32(mem[0],LPC_SHIFT)),32767)); for (j=0;j<ord-1;j++) { mem[j] = MAC16_16(mem[j+1], num[j],xi); diff --git a/linphone/mediastreamer2/src/equalizer.c b/linphone/mediastreamer2/src/equalizer.c index 4a585f83b6..937ac49fa6 100644 --- a/linphone/mediastreamer2/src/equalizer.c +++ b/linphone/mediastreamer2/src/equalizer.c @@ -17,21 +17,25 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include <mediastreamer2/msfilter.h> +#include <mediastreamer2/msequalizer.h> #include <mediastreamer2/dsptools.h> +#include <math.h> + #define GAIN_ZERODB 22000 typedef struct _EqualizerState{ int rate; int nfft; //number of fft points in time - int16_t *fft_cpx; + ms_word16_t *fft_cpx; int fir_len; - int16_t *fir; + ms_word16_t *fir; + ms_mem_t *mem; /*memories for filtering computations*/ + bool_t needs_update; } EqualizerState; -static void equalizer_flatten(EqualizerState *s){ +static void equalizer_state_flatten(EqualizerState *s){ int i; for(i=0;i<s->nfft;i+=2) s->fft_cpx[i]=GAIN_ZERODB; @@ -39,13 +43,22 @@ static void equalizer_flatten(EqualizerState *s){ static EqualizerState * equalizer_state_new(int nfft){ EqualizerState *s=ms_new0(EqualizerState,1); - int i; s->rate=8000; s->nfft=nfft; - s->fft_cpx=ms_new0(int16_t,s->nfft); - equalizer_flatten(s); + s->fft_cpx=ms_new0(ms_word16_t,s->nfft); + equalizer_state_flatten(s); s->fir_len=s->nfft; - s->fir=ms_new(int16_t,s->fir_len); + s->fir=ms_new(ms_word16_t,s->fir_len); + s->mem=ms_new0(ms_mem_t,s->fir_len); + s->needs_update=TRUE; + return s; +} + +static void equalizer_state_destroy(EqualizerState *s){ + ms_free(s->fft_cpx); + ms_free(s->fir); + ms_free(s->mem); + ms_free(s); } static int equalizer_state_hz_to_index(EqualizerState *s, int hz){ @@ -62,59 +75,169 @@ static int equalizer_state_hz_to_index(EqualizerState *s, int hz){ return ret; } -static float gain_float(int16_t val){ +static float gain_float(ms_word16_t val){ return (float)val/22000.0; } -static int16_t gain_int16(float val){ +static ms_word16_t gain_int16(float val){ int ret=(int)(val*22000.0); if (ret>=32767) ret=32767; - return (int16_t)ret; + return (ms_word16_t)ret; } -static float equalizer_get(EqualizerState *s, int freqhz){ +static float equalizer_state_get(EqualizerState *s, int freqhz){ int idx=equalizer_state_hz_to_index(s,freqhz); if (idx>=0) return gain_float(s->fft_cpx[idx*2]); return 0; } /* return the frequency band width we want to control around hz*/ -static void equalizer_get_band(EqualizerState *s, int hz, int *low_index, int *high_index){ +static void equalizer_state_get_band(EqualizerState *s, int hz, int *low_index, int *high_index){ int half_band=(int)((float)hz*0.1); *low_index=equalizer_state_hz_to_index(s,hz-half_band); *high_index=equalizer_state_hz_to_index(s,hz+half_band); } -static int16_t equalizer_set(EqualizerState *s, int freqhz, float gain){ +static void equalizer_state_set(EqualizerState *s, int freqhz, float gain){ int low,high; int i; - equalizer_get_band(s,freqhz,&low,&high); + equalizer_state_get_band(s,freqhz,&low,&high); for(i=low;i<=high;++i){ ms_message("Setting gain %f for freq_index %i (freqhz=%i)",gain,i,freqhz); s->fft_cpx[i*2]=gain_int16(gain); } + s->needs_update=TRUE; } -static void dump_table(int16_t *t, int len){ +static void dump_table(ms_word16_t *t, int len){ int i; for(i=0;i<len;i++) +#ifdef MS_FIXED_POINT ms_message("[%i]\t%i",i,t[i]); +#else + ms_message("[%i]\t%f",i,t[i]); +#endif } -static void apodize(int16_t *s, int len){ +/* + *hamming: + * 0.54 - 0.46*cos(2*M_PI*t/T) + * + * blackman + * 0.42 - 0.5*cos(2*M_PI*t/T) + 0.08*cos(4*M_PI*t/T) +*/ + +static void apodize(ms_word16_t *s, int len){ int i; float x; + float w; for(i=0;i<len;++i){ - x=(float)i/ - s[i]=cos + x=(float)i*2*M_PI/(float)len; + w=0.42 - (0.5*cos(x)) + (0.08*cos(2*x)); + s[i]=w*(float)s[i]; } } -static void equalizer_compute_impulse_response(EqualizerState *s){ +static void equalizer_state_compute_impulse_response(EqualizerState *s){ void *fft_handle=ms_fft_init(s->nfft); ms_ifft(fft_handle,s->fft_cpx,s->fir); ms_message("Inverse fft result:"); dump_table(s->fir,s->fir_len); apodize(s->fir,s->fir_len); + ms_message("Apodized impulse response:"); + dump_table(s->fir,s->fir_len); + s->needs_update=FALSE; +} + + + +#ifdef MS_FIXED_POINT +#define INT16_TO_WORD16(i,w,l) w=(i) +#define WORD16_TO_INT16(i,w,l) i=(w) +#else + +static void int16_to_word16(const int16_t *is, ms_word16_t *w, int l){ + int i; + for(i=0;i<l;++i){ + w[i]=(ms_word16_t)is[i]; + } +} + +static void word16_to_int16(const ms_word16_t *w, int16_t *is, int l){ + int i; + for (i=0;i<l;++i) + is[i]=(int16_t)w[i]; +} + +#define INT16_TO_WORD16(i,w,l) w=(ms_word16_t*)alloca(sizeof(ms_word16_t)*(l));int16_to_word16(i,w,l) +#define WORD16_TO_INT16(w,i,l) word16_to_int16(w,i,l) +#endif + +static void equalizer_state_run(EqualizerState *s, int16_t *samples, int nsamples){ + if (s->needs_update) + equalizer_state_compute_impulse_response(s); + ms_word16_t *w; + INT16_TO_WORD16(samples,w,nsamples); + ms_fir_mem16(w,s->fir,w,nsamples,s->fir_len,s->mem); + WORD16_TO_INT16(w,samples,nsamples); +} + + +void equalizer_init(MSFilter *f){ + f->data=equalizer_state_new(128); +} + +void equalizer_uninit(MSFilter *f){ + equalizer_state_destroy((EqualizerState*)f->data); +} + +void equalizer_process(MSFilter *f){ + mblk_t *m; + EqualizerState *s=(EqualizerState*)f->data; + while((m=ms_queue_get(f->inputs[0]))!=NULL){ + equalizer_state_run(s,(int16_t*)m->b_rptr,(m->b_wptr-m->b_rptr)/2); + ms_queue_put(f->outputs[0],m); + } +} + +int equalizer_set_gain(MSFilter *f, void *data){ + EqualizerState *s=(EqualizerState*)f->data; + MSEqualizerGain *d=(MSEqualizerGain*)data; + equalizer_state_set(s,d->frequency,d->gain); + return 0; +} + +int equalizer_get_gain(MSFilter *f, void *data){ + EqualizerState *s=(EqualizerState*)f->data; + MSEqualizerGain *d=(MSEqualizerGain*)data; + d->gain=equalizer_state_get(s,d->frequency); + return 0; +} + +int equalizer_set_rate(MSFilter *f, void *data){ + EqualizerState *s=(EqualizerState*)f->data; + s->rate=*(int*)data; + return 0; } +static MSFilterMethod equalizer_methods[]={ + { MS_EQUALIZER_SET_GAIN , equalizer_set_gain }, + { MS_EQUALIZER_GET_GAIN , equalizer_get_gain }, + { MS_FILTER_SET_SAMPLE_RATE , equalizer_set_rate }, + { 0 , NULL } +}; + +MSFilterDesc ms_equalizer_desc={ + .id= MS_EQUALIZER_ID, + .name="MSEqualizer", + .text=N_("Parametric sound equalizer."), + .category=MS_FILTER_OTHER, + .ninputs=1, + .noutputs=1, + .init=equalizer_init, + .process=equalizer_process, + .uninit=equalizer_uninit, + .methods=equalizer_methods +}; + +MS_FILTER_DESC_EXPORT(ms_equalizer_desc) diff --git a/linphone/po/Makefile.in.in b/linphone/po/Makefile.in.in old mode 100755 new mode 100644 index 57ef267b3e..402a25f7ac --- a/linphone/po/Makefile.in.in +++ b/linphone/po/Makefile.in.in @@ -21,7 +21,7 @@ GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ PACKAGE = @PACKAGE@ VERSION = @VERSION@ -SHELL = /bin/sh +SHELL = @SHELL@ srcdir = @srcdir@ top_srcdir = @top_srcdir@ @@ -56,7 +56,7 @@ ALL_LINGUAS = @ALL_LINGUAS@ PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) -USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep ^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep ^$$lang$$`"; then printf "$$lang "; fi; done; fi) +USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) -- GitLab