2
mediastreamer2 library - modular sound and video processing and streaming
3
Copyright (C) 2009 Simon MORLAT (simon.morlat@linphone.org)
5
This program is free software; you can redistribute it and/or
6
modify it under the terms of the GNU General Public License
7
as published by the Free Software Foundation; either version 2
8
of the License, or (at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
#include <mediastreamer2/msequalizer.h>
21
#include <mediastreamer2/dsptools.h>
27
#define alloca _alloca
31
#define M_PI 3.14159265358979323846
35
#define GAIN_ZERODB 20000
37
#define GAIN_ZERODB 1.0
42
typedef struct _EqualizerState{
44
int nfft; //number of fft points in time
48
ms_mem_t *mem; /*memories for filtering computations*/
53
static void equalizer_state_flatten(EqualizerState *s){
55
ms_word16_t val=GAIN_ZERODB/s->nfft;
57
for(i=1;i<s->nfft;i+=2)
61
static EqualizerState * equalizer_state_new(int nfft){
62
EqualizerState *s=(EqualizerState *)ms_new0(EqualizerState,1);
65
s->fft_cpx=(ms_word16_t*)ms_new0(ms_word16_t,s->nfft);
66
equalizer_state_flatten(s);
68
s->fir=(ms_word16_t*)ms_new(ms_word16_t,s->fir_len);
69
s->mem=(ms_mem_t*)ms_new0(ms_mem_t,s->fir_len);
75
static void equalizer_state_destroy(EqualizerState *s){
82
static int equalizer_state_hz_to_index(EqualizerState *s, int hz){
85
ms_error("Bad frequency value %i",hz);
91
/*round to nearest integer*/
92
ret=((hz*s->nfft)+(s->rate/2))/s->rate;
93
if (ret==s->nfft/2) ret=(s->nfft/2)-1;
97
static int equalizer_state_index2hz(EqualizerState *s, int index){
98
return (index * s->rate + s->nfft/2) / s->nfft;
101
static float gain_float(ms_word16_t val){
102
return (float)val/GAIN_ZERODB;
105
static float equalizer_state_get(EqualizerState *s, int freqhz){
106
int idx=equalizer_state_hz_to_index(s,freqhz);
107
if (idx>=0) return gain_float(s->fft_cpx[idx*2])*s->nfft;
111
/* The natural peaking equalizer amplitude transfer function is multiplied to the discrete f-points.
112
* Note that for PEQ no sqrt is needed for the overall calculation, applying it to gain yields the
115
static float equalizer_compute_gainpoint(int f, int freq_0, float sqrt_gain, int freq_bw)
118
k1 = ((float)(f*f)-(float)(freq_0*freq_0));
120
k2 = (float)(f*freq_bw);
122
return (k1+k2*sqrt_gain)/(k1+k2/sqrt_gain);
125
static void equalizer_point_set(EqualizerState *s, int i, int f, float gain){
126
ms_message("Setting gain %f for freq_index %i (%i Hz)\n",gain,i,f);
127
s->fft_cpx[1+((i-1)*2)] = (s->fft_cpx[1+((i-1)*2)]*(int)(gain*32768))/32768;
130
static void equalizer_state_set(EqualizerState *s, int freq_0, float gain, int freq_bw){
133
int delta_f = equalizer_state_index2hz(s, 1);
134
float sqrt_gain = sqrt(gain);
135
int mid = equalizer_state_hz_to_index(s, freq_0);
136
freq_bw-= delta_f/2; /* subtract a constant - compensates for limited fft steepness at low f */
137
if (freq_bw < delta_f/2)
140
f = equalizer_state_index2hz(s, i);
141
equalizer_point_set(s, i, f, gain); /* gain according to argument */
142
do { /* note: to better accomodate limited fft steepness, -delta is applied in f-calc ... */
144
f = equalizer_state_index2hz(s, i);
145
gain = equalizer_compute_gainpoint(f-delta_f, freq_0, sqrt_gain, freq_bw);
146
equalizer_point_set(s, i, f, gain);
148
while (i<TAPS && (gain>1.1 || gain<0.9));
150
do { /* ... and here +delta, as to */
152
f = equalizer_state_index2hz(s, i);
153
gain = equalizer_compute_gainpoint(f+delta_f, freq_0, sqrt_gain, freq_bw);
154
equalizer_point_set(s, i, f, gain);
156
while (i>=0 && (gain>1.1 || gain<0.9));
157
s->needs_update=TRUE;
160
static void dump_table(ms_word16_t *t, int len){
163
#ifdef MS_FIXED_POINT
164
ms_message("[%i]\t%i",i,t[i]);
166
ms_message("[%i]\t%f",i,t[i]);
170
static void time_shift(ms_word16_t *s, int len){
174
for (i=0;i<half;++i){
183
* 0.54 - 0.46*cos(2*M_PI*t/T)
186
* 0.42 - 0.5*cos(2*M_PI*t/T) + 0.08*cos(4*M_PI*t/T)
189
static void norm_and_apodize(ms_word16_t *s, int len){
194
x=(float)i*2*M_PI/(float)len;
195
w=0.54 - (0.46*cos(x));
196
//w=0.42 - (0.5*cos(x)) + (0.08*cos(2*x));
201
static void equalizer_state_compute_impulse_response(EqualizerState *s){
202
void *fft_handle=ms_fft_init(s->nfft);
203
ms_message("Spectral domain:");
204
dump_table(s->fft_cpx,s->nfft);
205
ms_ifft(fft_handle,s->fft_cpx,s->fir);
206
ms_fft_destroy(fft_handle);
208
ms_message("Inverse fft result:");
209
dump_table(s->fir,s->fir_len);
211
time_shift(s->fir,s->fir_len);
213
ms_message("Time shifted:");
214
dump_table(s->fir,s->fir_len);
216
norm_and_apodize(s->fir,s->fir_len);
217
ms_message("Apodized impulse response:");
218
dump_table(s->fir,s->fir_len);
219
s->needs_update=FALSE;
224
#ifdef MS_FIXED_POINT
225
#define INT16_TO_WORD16(i,w,l) w=(i)
226
#define WORD16_TO_INT16(i,w,l) i=(w)
229
static void int16_to_word16(const int16_t *is, ms_word16_t *w, int l){
232
w[i]=(ms_word16_t)is[i];
236
static void word16_to_int16(const ms_word16_t *w, int16_t *is, int l){
242
#define INT16_TO_WORD16(i,w,l) w=(ms_word16_t*)alloca(sizeof(ms_word16_t)*(l));int16_to_word16(i,w,l)
243
#define WORD16_TO_INT16(w,i,l) word16_to_int16(w,i,l)
246
static void equalizer_state_run(EqualizerState *s, int16_t *samples, int nsamples){
248
equalizer_state_compute_impulse_response(s);
250
INT16_TO_WORD16(samples,w,nsamples);
251
ms_fir_mem16(w,s->fir,w,nsamples,s->fir_len,s->mem);
252
WORD16_TO_INT16(w,samples,nsamples);
256
static void equalizer_init(MSFilter *f){
257
f->data=equalizer_state_new(TAPS);
260
static void equalizer_uninit(MSFilter *f){
261
equalizer_state_destroy((EqualizerState*)f->data);
264
static void equalizer_process(MSFilter *f){
266
EqualizerState *s=(EqualizerState*)f->data;
267
while((m=ms_queue_get(f->inputs[0]))!=NULL){
269
equalizer_state_run(s,(int16_t*)m->b_rptr,(m->b_wptr-m->b_rptr)/2);
271
ms_queue_put(f->outputs[0],m);
275
static int equalizer_set_gain(MSFilter *f, void *data){
276
EqualizerState *s=(EqualizerState*)f->data;
277
MSEqualizerGain *d=(MSEqualizerGain*)data;
278
equalizer_state_set(s,d->frequency,d->gain,d->width);
282
static int equalizer_get_gain(MSFilter *f, void *data){
283
EqualizerState *s=(EqualizerState*)f->data;
284
MSEqualizerGain *d=(MSEqualizerGain*)data;
285
d->gain=equalizer_state_get(s,d->frequency);
290
static int equalizer_set_rate(MSFilter *f, void *data){
291
EqualizerState *s=(EqualizerState*)f->data;
293
s->needs_update=TRUE;
297
static int equalizer_set_active(MSFilter *f, void *data){
298
EqualizerState *s=(EqualizerState*)f->data;
299
s->active=*(int*)data;
303
static int equalizer_dump(MSFilter *f, void *data){
304
EqualizerState *s=(EqualizerState*)f->data;
305
float *t=(float*)data;
309
for (i=1;i<s->nfft;i+=2){
310
*t=((float)s->fft_cpx[i]*(float)s->nfft)/(float)GAIN_ZERODB;
316
static int equalizer_get_nfreqs(MSFilter *f, void *data){
317
EqualizerState *s=(EqualizerState*)f->data;
318
*(int*)data=s->nfft/2;
322
static MSFilterMethod equalizer_methods[]={
323
{ MS_EQUALIZER_SET_GAIN , equalizer_set_gain },
324
{ MS_EQUALIZER_GET_GAIN , equalizer_get_gain },
325
{ MS_EQUALIZER_SET_ACTIVE , equalizer_set_active },
326
{ MS_FILTER_SET_SAMPLE_RATE , equalizer_set_rate },
327
{ MS_EQUALIZER_DUMP_STATE , equalizer_dump },
328
{ MS_EQUALIZER_GET_NUM_FREQUENCIES, equalizer_get_nfreqs },
334
MSFilterDesc ms_equalizer_desc={
337
N_("Parametric sound equalizer."),
352
MSFilterDesc ms_equalizer_desc={
353
.id= MS_EQUALIZER_ID,
355
.text=N_("Parametric sound equalizer."),
356
.category=MS_FILTER_OTHER,
359
.init=equalizer_init,
360
.process=equalizer_process,
361
.uninit=equalizer_uninit,
362
.methods=equalizer_methods
367
MS_FILTER_DESC_EXPORT(ms_equalizer_desc)