Mercurial > mplayer.hg
annotate libaf/af_equalizer.c @ 32282:606e4157cd4c
Split alloc and init of context so that parameters can be set in the context
instead of requireing being passed through function parameters. This also
makes sws work with AVOptions.
author | michael |
---|---|
date | Sun, 26 Sep 2010 19:33:57 +0000 |
parents | 32725ca88fed |
children | 8fa2f43cb760 |
rev | line source |
---|---|
28229
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
1 /* |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
2 * Equalizer filter, implementation of a 10 band time domain graphic |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
3 * equalizer using IIR filters. The IIR filters are implemented using a |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
4 * Direct Form II approach, but has been modified (b1 == 0 always) to |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
5 * save computation. |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
6 * |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
7 * Copyright (C) 2001 Anders Johansson ajh@atri.curtin.edu.au |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
8 * |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
9 * This file is part of MPlayer. |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
10 * |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
11 * MPlayer is free software; you can redistribute it and/or modify |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
12 * it under the terms of the GNU General Public License as published by |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
13 * the Free Software Foundation; either version 2 of the License, or |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
14 * (at your option) any later version. |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
15 * |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
16 * MPlayer is distributed in the hope that it will be useful, |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
19 * GNU General Public License for more details. |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
20 * |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
21 * You should have received a copy of the GNU General Public License along |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
22 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
72d0b1444141
Replace informal license notices by standard license header
diego
parents:
24900
diff
changeset
|
24 */ |
8073 | 25 |
26 #include <stdio.h> | |
27 #include <stdlib.h> | |
28 | |
29 #include <inttypes.h> | |
30 #include <math.h> | |
31 | |
32 #include "af.h" | |
33 | |
8167 | 34 #define L 2 // Storage for filter taps |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
35 #define KM 10 // Max number of bands |
8073 | 36 |
37 #define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2) | |
38 gives 4dB suppression @ Fc*2 and Fc/2 */ | |
39 | |
8607 | 40 /* Center frequencies for band-pass filters |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
41 The different frequency bands are: |
8607 | 42 nr. center frequency |
43 0 31.25 Hz | |
44 1 62.50 Hz | |
45 2 125.0 Hz | |
46 3 250.0 Hz | |
47 4 500.0 Hz | |
48 5 1.000 kHz | |
49 6 2.000 kHz | |
50 7 4.000 kHz | |
51 8 8.000 kHz | |
52 9 16.00 kHz | |
53 */ | |
8073 | 54 #define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000} |
55 | |
56 // Maximum and minimum gain for the bands | |
57 #define G_MAX +12.0 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
58 #define G_MIN -12.0 |
8073 | 59 |
60 // Data for specific instances of this filter | |
61 typedef struct af_equalizer_s | |
62 { | |
8607 | 63 float a[KM][L]; // A weights |
64 float b[KM][L]; // B weights | |
65 float wq[AF_NCH][KM][L]; // Circular buffer for W data | |
66 float g[AF_NCH][KM]; // Gain factor for each channel and band | |
67 int K; // Number of used eq bands | |
68 int channels; // Number of channels | |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
69 float gain_factor; // applied at output to avoid clipping |
8073 | 70 } af_equalizer_t; |
71 | |
72 // 2nd order Band-pass Filter design | |
73 static void bp2(float* a, float* b, float fc, float q){ | |
74 double th= 2.0 * M_PI * fc; | |
75 double C = (1.0 - tan(th*q/2.0))/(1.0 + tan(th*q/2.0)); | |
76 | |
77 a[0] = (1.0 + C) * cos(th); | |
78 a[1] = -1 * C; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
79 |
8073 | 80 b[0] = (1.0 - C)/2.0; |
81 b[1] = -1.0050; | |
82 } | |
83 | |
84 // Initialization and runtime control | |
85 static int control(struct af_instance_s* af, int cmd, void* arg) | |
86 { | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
87 af_equalizer_t* s = (af_equalizer_t*)af->setup; |
8073 | 88 |
89 switch(cmd){ | |
90 case AF_CONTROL_REINIT:{ | |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
91 int k =0, i =0; |
8073 | 92 float F[KM] = CF; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
93 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
94 s->gain_factor=0.0; |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
95 |
8073 | 96 // Sanity check |
97 if(!arg) return AF_ERROR; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
98 |
8073 | 99 af->data->rate = ((af_data_t*)arg)->rate; |
100 af->data->nch = ((af_data_t*)arg)->nch; | |
14245 | 101 af->data->format = AF_FORMAT_FLOAT_NE; |
8607 | 102 af->data->bps = 4; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
103 |
8073 | 104 // Calculate number of active filters |
105 s->K=KM; | |
8167 | 106 while(F[s->K-1] > (float)af->data->rate/2.2) |
8073 | 107 s->K--; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
108 |
8167 | 109 if(s->K != KM) |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
110 mp_msg(MSGT_AFILTER, MSGL_INFO, "[equalizer] Limiting the number of filters to" |
8607 | 111 " %i due to low sample rate.\n",s->K); |
8073 | 112 |
113 // Generate filter taps | |
114 for(k=0;k<s->K;k++) | |
115 bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q); | |
116 | |
117 // Calculate how much this plugin adds to the overall time delay | |
24900 | 118 af->delay = 2 * af->data->nch * af->data->bps; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
119 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
120 // Calculate gain factor to prevent clipping at output |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
121 for(k=0;k<AF_NCH;k++) |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
122 { |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
123 for(i=0;i<KM;i++) |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
124 { |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
125 if(s->gain_factor < s->g[k][i]) s->gain_factor=s->g[k][i]; |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
126 } |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
127 } |
8073 | 128 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
129 s->gain_factor=log10(s->gain_factor + 1.0) * 20.0; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
130 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
131 if(s->gain_factor > 0.0) |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
132 { |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
133 s->gain_factor=0.1+(s->gain_factor/12.0); |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
134 }else{ |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
135 s->gain_factor=1; |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
136 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
137 |
8607 | 138 return af_test_output(af,arg); |
8073 | 139 } |
140 case AF_CONTROL_COMMAND_LINE:{ | |
141 float g[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; | |
142 int i,j; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
143 sscanf((char*)arg,"%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", &g[0], &g[1], |
8073 | 144 &g[2], &g[3], &g[4], &g[5], &g[6], &g[7], &g[8] ,&g[9]); |
8607 | 145 for(i=0;i<AF_NCH;i++){ |
8073 | 146 for(j=0;j<KM;j++){ |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
147 ((af_equalizer_t*)af->setup)->g[i][j] = |
8073 | 148 pow(10.0,clamp(g[j],G_MIN,G_MAX)/20.0)-1.0; |
149 } | |
150 } | |
151 return AF_OK; | |
152 } | |
8607 | 153 case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{ |
154 float* gain = ((af_control_ext_t*)arg)->arg; | |
155 int ch = ((af_control_ext_t*)arg)->ch; | |
156 int k; | |
17774
30fa0638b78d
We start with 0, so ch (channel number) == AF_NCH is invalid, too (not just >)
reimar
parents:
17068
diff
changeset
|
157 if(ch >= AF_NCH || ch < 0) |
8073 | 158 return AF_ERROR; |
8607 | 159 |
160 for(k = 0 ; k<KM ; k++) | |
161 s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0; | |
162 | |
8073 | 163 return AF_OK; |
164 } | |
8607 | 165 case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{ |
166 float* gain = ((af_control_ext_t*)arg)->arg; | |
167 int ch = ((af_control_ext_t*)arg)->ch; | |
168 int k; | |
17774
30fa0638b78d
We start with 0, so ch (channel number) == AF_NCH is invalid, too (not just >)
reimar
parents:
17068
diff
changeset
|
169 if(ch >= AF_NCH || ch < 0) |
8073 | 170 return AF_ERROR; |
8607 | 171 |
172 for(k = 0 ; k<KM ; k++) | |
173 gain[k] = log10(s->g[ch][k]+1.0) * 20.0; | |
174 | |
8073 | 175 return AF_OK; |
176 } | |
177 } | |
178 return AF_UNKNOWN; | |
179 } | |
180 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
181 // Deallocate memory |
8073 | 182 static void uninit(struct af_instance_s* af) |
183 { | |
184 if(af->data) | |
185 free(af->data); | |
186 if(af->setup) | |
187 free(af->setup); | |
188 } | |
189 | |
190 // Filter data through filter | |
191 static af_data_t* play(struct af_instance_s* af, af_data_t* data) | |
192 { | |
193 af_data_t* c = data; // Current working data | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
194 af_equalizer_t* s = (af_equalizer_t*)af->setup; // Setup |
8073 | 195 uint32_t ci = af->data->nch; // Index for channels |
196 uint32_t nch = af->data->nch; // Number of channels | |
197 | |
198 while(ci--){ | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
199 float* g = s->g[ci]; // Gain factor |
8607 | 200 float* in = ((float*)c->audio)+ci; |
201 float* out = ((float*)c->audio)+ci; | |
202 float* end = in + c->len/4; // Block loop end | |
8073 | 203 |
204 while(in < end){ | |
14245 | 205 register int k = 0; // Frequency band index |
8607 | 206 register float yt = *in; // Current input sample |
8073 | 207 in+=nch; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
208 |
8073 | 209 // Run the filters |
210 for(;k<s->K;k++){ | |
211 // Pointer to circular buffer wq | |
212 register float* wq = s->wq[ci][k]; | |
213 // Calculate output from AR part of current filter | |
214 register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1]; | |
215 // Calculate output form MA part of current filter | |
216 yt+=(w + wq[1]*s->b[k][1])*g[k]; | |
217 // Update circular buffer | |
218 wq[1] = wq[0]; | |
219 wq[0] = w; | |
220 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
221 // Calculate output |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
222 *out=yt*s->gain_factor; |
8073 | 223 out+=nch; |
224 } | |
225 } | |
226 return c; | |
227 } | |
228 | |
229 // Allocate memory and set function pointers | |
22746
fd6f824ef894
Rename open to af_open so as not to conflict with a previous header definition.
diego
parents:
17812
diff
changeset
|
230 static int af_open(af_instance_t* af){ |
8073 | 231 af->control=control; |
232 af->uninit=uninit; | |
233 af->play=play; | |
24888 | 234 af->mul=1; |
8073 | 235 af->data=calloc(1,sizeof(af_data_t)); |
236 af->setup=calloc(1,sizeof(af_equalizer_t)); | |
237 if(af->data == NULL || af->setup == NULL) | |
238 return AF_ERROR; | |
239 return AF_OK; | |
240 } | |
241 | |
242 // Description of this filter | |
243 af_info_t af_info_equalizer = { | |
244 "Equalizer audio filter", | |
245 "equalizer", | |
246 "Anders", | |
247 "", | |
248 AF_FLAGS_NOT_REENTRANT, | |
22746
fd6f824ef894
Rename open to af_open so as not to conflict with a previous header definition.
diego
parents:
17812
diff
changeset
|
249 af_open |
8073 | 250 }; |