Mercurial > mplayer.hg
annotate libaf/af_equalizer.c @ 36089:d4056035c260
Set file prior to adding to the URL list.
An already existing URL list item won't be added, but the allocated url
string will be freed (which thus can't be uiSetFile() nor be added to
the playlist).
author | ib |
---|---|
date | Mon, 29 Apr 2013 12:10:03 +0000 |
parents | a93891202051 |
children | 2b9bc3c2933d |
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 | |
34174
a93891202051
Add missing mp_msg.h #includes, remove some unnecessary ones.
diego
parents:
32537
diff
changeset
|
32 #include "mp_msg.h" |
8073 | 33 #include "af.h" |
34 | |
8167 | 35 #define L 2 // Storage for filter taps |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
36 #define KM 10 // Max number of bands |
8073 | 37 |
38 #define Q 1.2247449 /* Q value for band-pass filters 1.2247=(3/2)^(1/2) | |
39 gives 4dB suppression @ Fc*2 and Fc/2 */ | |
40 | |
8607 | 41 /* Center frequencies for band-pass filters |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
42 The different frequency bands are: |
8607 | 43 nr. center frequency |
44 0 31.25 Hz | |
45 1 62.50 Hz | |
46 2 125.0 Hz | |
47 3 250.0 Hz | |
48 4 500.0 Hz | |
49 5 1.000 kHz | |
50 6 2.000 kHz | |
51 7 4.000 kHz | |
52 8 8.000 kHz | |
53 9 16.00 kHz | |
54 */ | |
8073 | 55 #define CF {31.25,62.5,125,250,500,1000,2000,4000,8000,16000} |
56 | |
57 // Maximum and minimum gain for the bands | |
58 #define G_MAX +12.0 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
59 #define G_MIN -12.0 |
8073 | 60 |
61 // Data for specific instances of this filter | |
62 typedef struct af_equalizer_s | |
63 { | |
8607 | 64 float a[KM][L]; // A weights |
65 float b[KM][L]; // B weights | |
66 float wq[AF_NCH][KM][L]; // Circular buffer for W data | |
67 float g[AF_NCH][KM]; // Gain factor for each channel and band | |
68 int K; // Number of used eq bands | |
69 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
|
70 float gain_factor; // applied at output to avoid clipping |
8073 | 71 } af_equalizer_t; |
72 | |
73 // 2nd order Band-pass Filter design | |
74 static void bp2(float* a, float* b, float fc, float q){ | |
75 double th= 2.0 * M_PI * fc; | |
76 double C = (1.0 - tan(th*q/2.0))/(1.0 + tan(th*q/2.0)); | |
77 | |
78 a[0] = (1.0 + C) * cos(th); | |
79 a[1] = -1 * C; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
80 |
8073 | 81 b[0] = (1.0 - C)/2.0; |
82 b[1] = -1.0050; | |
83 } | |
84 | |
85 // Initialization and runtime control | |
86 static int control(struct af_instance_s* af, int cmd, void* arg) | |
87 { | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
88 af_equalizer_t* s = (af_equalizer_t*)af->setup; |
8073 | 89 |
90 switch(cmd){ | |
91 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
|
92 int k =0, i =0; |
8073 | 93 float F[KM] = CF; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
94 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
95 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
|
96 |
8073 | 97 // Sanity check |
98 if(!arg) return AF_ERROR; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
99 |
8073 | 100 af->data->rate = ((af_data_t*)arg)->rate; |
101 af->data->nch = ((af_data_t*)arg)->nch; | |
14245 | 102 af->data->format = AF_FORMAT_FLOAT_NE; |
8607 | 103 af->data->bps = 4; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
104 |
8073 | 105 // Calculate number of active filters |
106 s->K=KM; | |
8167 | 107 while(F[s->K-1] > (float)af->data->rate/2.2) |
8073 | 108 s->K--; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
109 |
8167 | 110 if(s->K != KM) |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
111 mp_msg(MSGT_AFILTER, MSGL_INFO, "[equalizer] Limiting the number of filters to" |
8607 | 112 " %i due to low sample rate.\n",s->K); |
8073 | 113 |
114 // Generate filter taps | |
115 for(k=0;k<s->K;k++) | |
116 bp2(s->a[k],s->b[k],F[k]/((float)af->data->rate),Q); | |
117 | |
118 // Calculate how much this plugin adds to the overall time delay | |
24900 | 119 af->delay = 2 * af->data->nch * af->data->bps; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
120 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
121 // 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
|
122 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
|
123 { |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
124 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
|
125 { |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
126 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
|
127 } |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
128 } |
8073 | 129 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
130 s->gain_factor=log10(s->gain_factor + 1.0) * 20.0; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
131 |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
132 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
|
133 { |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
134 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
|
135 }else{ |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
136 s->gain_factor=1; |
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
137 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
138 |
8607 | 139 return af_test_output(af,arg); |
8073 | 140 } |
141 case AF_CONTROL_COMMAND_LINE:{ | |
142 float g[10]={0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; | |
143 int i,j; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
144 sscanf((char*)arg,"%f:%f:%f:%f:%f:%f:%f:%f:%f:%f", &g[0], &g[1], |
8073 | 145 &g[2], &g[3], &g[4], &g[5], &g[6], &g[7], &g[8] ,&g[9]); |
8607 | 146 for(i=0;i<AF_NCH;i++){ |
8073 | 147 for(j=0;j<KM;j++){ |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
148 ((af_equalizer_t*)af->setup)->g[i][j] = |
8073 | 149 pow(10.0,clamp(g[j],G_MIN,G_MAX)/20.0)-1.0; |
150 } | |
151 } | |
152 return AF_OK; | |
153 } | |
8607 | 154 case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_SET:{ |
155 float* gain = ((af_control_ext_t*)arg)->arg; | |
156 int ch = ((af_control_ext_t*)arg)->ch; | |
157 int k; | |
17774
30fa0638b78d
We start with 0, so ch (channel number) == AF_NCH is invalid, too (not just >)
reimar
parents:
17068
diff
changeset
|
158 if(ch >= AF_NCH || ch < 0) |
8073 | 159 return AF_ERROR; |
8607 | 160 |
161 for(k = 0 ; k<KM ; k++) | |
162 s->g[ch][k] = pow(10.0,clamp(gain[k],G_MIN,G_MAX)/20.0)-1.0; | |
163 | |
8073 | 164 return AF_OK; |
165 } | |
8607 | 166 case AF_CONTROL_EQUALIZER_GAIN | AF_CONTROL_GET:{ |
167 float* gain = ((af_control_ext_t*)arg)->arg; | |
168 int ch = ((af_control_ext_t*)arg)->ch; | |
169 int k; | |
17774
30fa0638b78d
We start with 0, so ch (channel number) == AF_NCH is invalid, too (not just >)
reimar
parents:
17068
diff
changeset
|
170 if(ch >= AF_NCH || ch < 0) |
8073 | 171 return AF_ERROR; |
8607 | 172 |
173 for(k = 0 ; k<KM ; k++) | |
174 gain[k] = log10(s->g[ch][k]+1.0) * 20.0; | |
175 | |
8073 | 176 return AF_OK; |
177 } | |
178 } | |
179 return AF_UNKNOWN; | |
180 } | |
181 | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
182 // Deallocate memory |
8073 | 183 static void uninit(struct af_instance_s* af) |
184 { | |
185 free(af->data); | |
186 free(af->setup); | |
187 } | |
188 | |
189 // Filter data through filter | |
190 static af_data_t* play(struct af_instance_s* af, af_data_t* data) | |
191 { | |
192 af_data_t* c = data; // Current working data | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
193 af_equalizer_t* s = (af_equalizer_t*)af->setup; // Setup |
8073 | 194 uint32_t ci = af->data->nch; // Index for channels |
195 uint32_t nch = af->data->nch; // Number of channels | |
196 | |
197 while(ci--){ | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
198 float* g = s->g[ci]; // Gain factor |
8607 | 199 float* in = ((float*)c->audio)+ci; |
200 float* out = ((float*)c->audio)+ci; | |
201 float* end = in + c->len/4; // Block loop end | |
8073 | 202 |
203 while(in < end){ | |
14245 | 204 register int k = 0; // Frequency band index |
8607 | 205 register float yt = *in; // Current input sample |
8073 | 206 in+=nch; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
207 |
8073 | 208 // Run the filters |
209 for(;k<s->K;k++){ | |
210 // Pointer to circular buffer wq | |
211 register float* wq = s->wq[ci][k]; | |
212 // Calculate output from AR part of current filter | |
213 register float w=yt*s->b[k][0] + wq[0]*s->a[k][0] + wq[1]*s->a[k][1]; | |
214 // Calculate output form MA part of current filter | |
215 yt+=(w + wq[1]*s->b[k][1])*g[k]; | |
216 // Update circular buffer | |
217 wq[1] = wq[0]; | |
218 wq[0] = w; | |
219 } | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29049
diff
changeset
|
220 // Calculate output |
17812
1ade5769c97b
added dinamically calculated gain factor at output stage to avoid clipping on sane ranges
reynaldo
parents:
17774
diff
changeset
|
221 *out=yt*s->gain_factor; |
8073 | 222 out+=nch; |
223 } | |
224 } | |
225 return c; | |
226 } | |
227 | |
228 // 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
|
229 static int af_open(af_instance_t* af){ |
8073 | 230 af->control=control; |
231 af->uninit=uninit; | |
232 af->play=play; | |
24888 | 233 af->mul=1; |
8073 | 234 af->data=calloc(1,sizeof(af_data_t)); |
235 af->setup=calloc(1,sizeof(af_equalizer_t)); | |
236 if(af->data == NULL || af->setup == NULL) | |
237 return AF_ERROR; | |
238 return AF_OK; | |
239 } | |
240 | |
241 // Description of this filter | |
242 af_info_t af_info_equalizer = { | |
243 "Equalizer audio filter", | |
244 "equalizer", | |
245 "Anders", | |
246 "", | |
247 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
|
248 af_open |
8073 | 249 }; |