3 # Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org>
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 # $FreeBSD: head/sys/tools/sound/feeder_eq_mkfilter.awk 193889 2009-06-10 06:49:45Z ariff $
31 # Biquad coefficients generator for Parametric Software Equalizer. Not as ugly
32 # as 'feeder_rate_mkfilter.awk'
36 # "Cookbook formulae for audio EQ biquad filter coefficients"
37 # by Robert Bristow-Johnson <rbj@audioimagination.com>
39 # - http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
45 # Some basic Math functions.
49 return (((x
< 0) ?
-x
: x
) + 0);
54 return (((x
< 0.0) ?
-x
: x
) + 0.0);
67 return (exp
(1.0 * y
* log
(1.0 * x
)));
82 function feedeq_w0
(fc
, rate
)
84 return ((2.0 * M_PI
* fc
) / (1.0 * rate
));
87 function feedeq_A
(gain
, A
)
89 if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ
|| FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF
)
90 A = pow
(10, gain
/ 40.0);
92 A = sqrt
(pow
(10, gain
/ 20.0));
97 function feedeq_alpha
(w0
, A
, QS
)
99 if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ
)
100 alpha = sin
(w0
) / (2.0 * QS
);
101 else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF
)
102 alpha = sin
(w0
) * 0.5 * sqrt
(A
+ ((1.0 / A
) * \
103 ((1.0 / QS
) - 1.0)) + 2.0);
110 function feedeq_fx_floor
(v
, r
)
112 if (fabs
(v
) < fabs
(smallest
))
114 if (fabs
(v
) > fabs
(largest
))
117 r = floor
((v
* FEEDEQ_COEFF_ONE
) + 0.5);
119 if (r
< INT32_MIN
|| r
> INT32_MAX
)
120 printf("\n#error overflow v=%f, " \
121 "please reduce FEEDEQ_COEFF_SHIFT\n", v
);
126 function feedeq_gen_biquad_coeffs
(coeffs
, rate
, gain
, \
127 w0
, A
, alpha
, a0
, a1
, a2
, b0
, b1
, b2
)
129 w0 = feedeq_w0
(FEEDEQ_TREBLE_SFREQ
, 1.0 * rate
);
130 A = feedeq_A
(1.0 * gain
);
131 alpha = feedeq_alpha
(w0
, A
, FEEDEQ_TREBLE_SLOPE
);
133 if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ
) {
134 b0 =
1.0 + (alpha
* A
);
136 b2 =
1.0 - (alpha
* A
);
137 a0 =
1.0 + (alpha
/ A
);
139 a2 =
1.0 - (alpha
/ A
);
140 } else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF
) {
141 b0 = A
*((A
+1.0)+((A
-1.0)*cos
(w0
))+(2.0*sqrt
(A
)*alpha
));
142 b1 =
-2.0*A
*((A
-1.0)+((A
+1.0)*cos
(w0
)) );
143 b2 = A
*((A
+1.0)+((A
-1.0)*cos
(w0
))-(2.0*sqrt
(A
)*alpha
));
144 a0 =
(A
+1.0)-((A
-1.0)*cos
(w0
))+(2.0*sqrt
(A
)*alpha
);
145 a1 =
2.0 * ((A
-1.0)-((A
+1.0)*cos
(w0
)) );
146 a2 =
(A
+1.0)-((A
-1.0)*cos
(w0
))-(2.0*sqrt
(A
)*alpha
);
148 b0 = b1 = b2 = a0 = a1 = a2 =
0.0;
156 coeffs
["treble", gain
, 0] = feedeq_fx_floor
(a0
);
157 coeffs
["treble", gain
, 1] = feedeq_fx_floor
(a1
);
158 coeffs
["treble", gain
, 2] = feedeq_fx_floor
(a2
);
159 coeffs
["treble", gain
, 3] = feedeq_fx_floor
(b0
);
160 coeffs
["treble", gain
, 4] = feedeq_fx_floor
(b1
);
161 coeffs
["treble", gain
, 5] = feedeq_fx_floor
(b2
);
163 w0 = feedeq_w0
(FEEDEQ_BASS_SFREQ
, 1.0 * rate
);
164 A = feedeq_A
(1.0 * gain
);
165 alpha = feedeq_alpha
(w0
, A
, FEEDEQ_BASS_SLOPE
);
167 if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ
) {
168 b0 =
1.0 + (alpha
* A
);
170 b2 =
1.0 - (alpha
* A
);
171 a0 =
1.0 + (alpha
/ A
);
173 a2 =
1.0 - (alpha
/ A
);
174 } else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF
) {
175 b0 = A
*((A
+1.0)-((A
-1.0)*cos
(w0
))+(2.0*sqrt
(A
)*alpha
));
176 b1 =
2.0*A
*((A
-1.0)-((A
+1.0)*cos
(w0
)) );
177 b2 = A
*((A
+1.0)-((A
-1.0)*cos
(w0
))-(2.0*sqrt
(A
)*alpha
));
178 a0 =
(A
+1.0)+((A
-1.0)*cos
(w0
))+(2.0*sqrt
(A
)*alpha
);
179 a1 =
-2.0 * ((A
-1.0)+((A
+1.0)*cos
(w0
)) );
180 a2 =
(A
+1.0)+((A
-1.0)*cos
(w0
))-(2.0*sqrt
(A
)*alpha
);
182 b0 = b1 = b2 = a0 = a1 = a2 =
0.0;
190 coeffs
["bass", gain
, 0] = feedeq_fx_floor
(a0
);
191 coeffs
["bass", gain
, 1] = feedeq_fx_floor
(a1
);
192 coeffs
["bass", gain
, 2] = feedeq_fx_floor
(a2
);
193 coeffs
["bass", gain
, 3] = feedeq_fx_floor
(b0
);
194 coeffs
["bass", gain
, 4] = feedeq_fx_floor
(b1
);
195 coeffs
["bass", gain
, 5] = feedeq_fx_floor
(b2
);
198 function feedeq_gen_freq_coeffs
(frq
, g
, i
, v
)
202 for (g =
(FEEDEQ_GAIN_MIN
* FEEDEQ_GAIN_DIV
); \
203 g
<=
(FEEDEQ_GAIN_MAX
* FEEDEQ_GAIN_DIV
); \
204 g
+= FEEDEQ_GAIN_STEP
) {
205 feedeq_gen_biquad_coeffs
(coeffs
, frq
, \
206 g
* FEEDEQ_GAIN_RECIPROCAL
);
209 printf("\nstatic struct feed_eq_coeff eq_%d[%d] " \
210 "= {\n", frq
, FEEDEQ_LEVELS
);
211 for (g =
(FEEDEQ_GAIN_MIN
* FEEDEQ_GAIN_DIV
); \
212 g
<=
(FEEDEQ_GAIN_MAX
* FEEDEQ_GAIN_DIV
); \
213 g
+= FEEDEQ_GAIN_STEP
) {
215 for (i =
1; i
< 6; i
++) {
216 v = coeffs
["treble", g
* FEEDEQ_GAIN_RECIPROCAL
, i
];
217 printf("%s0x%08x%s", \
218 (v
< 0) ?
"-" : " ", abs
(v
), \
219 (i ==
5) ?
" " : ", ");
222 for (i =
1; i
< 6; i
++) {
223 v = coeffs
["bass", g
* FEEDEQ_GAIN_RECIPROCAL
, i
];
224 printf("%s0x%08x%s", \
225 (v
< 0) ?
"-" : " ", abs
(v
), \
226 (i ==
5) ?
" " : ", ");
229 (g
< (FEEDEQ_GAIN_MAX
* FEEDEQ_GAIN_DIV
)) ?
"," : "");
234 function feedeq_calc_preamp
(norm
, gain
, shift
, mul
, bit
, attn
)
236 shift = FEEDEQ_PREAMP_SHIFT
;
238 if (floor
(FEEDEQ_PREAMP_BITDB
) ==
6 && \
239 (1.0 * floor
(gain
)) == gain
&& (floor
(gain
) %
6) ==
0) {
241 shift = floor
(floor
(gain
) / 6);
243 bit =
32.0 - ((1.0 * gain
) / (1.0 * FEEDEQ_PREAMP_BITDB
));
244 attn = pow
(2.0, bit
) / pow
(2.0, 32.0);
245 mul = floor
((attn
* FEEDEQ_PREAMP_ONE
) + 0.5);
248 while ((mul %
2) ==
0 && shift
> 0) {
249 mul = floor
(mul
/ 2);
254 norm
["shift"] = shift
;
258 M_PI = atan2
(0.0, -1.0);
260 INT32_MAX =
1 + ((shl
(1, 30) - 1) * 2);
261 INT32_MIN =
-1 - INT32_MAX
;
264 FEEDEQ_TYPE_SHELF =
1;
266 FEEDEQ_TYPE = FEEDEQ_TYPE_PEQ
;
268 FEEDEQ_COEFF_SHIFT =
24;
269 FEEDEQ_COEFF_ONE = shl
(1, FEEDEQ_COEFF_SHIFT
);
271 FEEDEQ_PREAMP_SHIFT =
31;
272 FEEDEQ_PREAMP_ONE = shl
(1, FEEDEQ_PREAMP_SHIFT
);
273 FEEDEQ_PREAMP_BITDB =
6; # 20.0 * (log(2.0) / log(10.0));
275 FEEDEQ_GAIN_DIV =
10;
278 while (j
< FEEDEQ_GAIN_DIV
) {
282 FEEDEQ_GAIN_SHIFT = i
;
283 FEEDEQ_GAIN_FMASK = shl
(1, FEEDEQ_GAIN_SHIFT
) - 1;
285 FEEDEQ_GAIN_RECIPROCAL =
1.0 / FEEDEQ_GAIN_DIV
;
289 split(ARGV[1], arg
, ":");
290 while (match(arg
[i
], "^[^0-9]*$")) {
291 if (arg
[i
] ==
"PEQ") {
292 FEEDEQ_TYPE = FEEDEQ_TYPE_PEQ
;
293 } else if (arg
[i
] ==
"SHELF") {
294 FEEDEQ_TYPE = FEEDEQ_TYPE_SHELF
;
298 split(arg
[i
++], subarg
, ",");
299 FEEDEQ_TREBLE_SFREQ =
1.0 * subarg
[1];
300 FEEDEQ_TREBLE_SLOPE =
1.0 * subarg
[2];
301 split(arg
[i
++], subarg
, ",");
302 FEEDEQ_BASS_SFREQ =
1.0 * subarg
[1];
303 FEEDEQ_BASS_SLOPE =
1.0 * subarg
[2];
304 split(arg
[i
++], subarg
, ",");
305 FEEDEQ_GAIN_MIN = floor
(1.0 * subarg
[1]);
306 FEEDEQ_GAIN_MAX = floor
(1.0 * subarg
[2]);
307 if (length(subarg
) > 2) {
308 j = floor
(1.0 * FEEDEQ_GAIN_DIV
* subarg
[3]);
317 if (j
> FEEDEQ_GAIN_DIV
|| (FEEDEQ_GAIN_DIV % j
) != 0)
319 FEEDEQ_GAIN_STEP = j
;
321 FEEDEQ_GAIN_STEP = FEEDEQ_GAIN_DIV
;
322 split(arg
[i
], subarg
, ",");
323 for (i =
1; i
<=
length(subarg
); i
++)
324 allfreq
[i
- 1] = floor
(1.0 * subarg
[i
]);
326 FEEDEQ_TREBLE_SFREQ =
16000.0;
327 FEEDEQ_TREBLE_SLOPE =
0.25;
328 FEEDEQ_BASS_SFREQ =
62.0;
329 FEEDEQ_BASS_SLOPE =
0.25;
331 FEEDEQ_GAIN_MIN =
-9;
334 FEEDEQ_GAIN_STEP = FEEDEQ_GAIN_DIV
;
345 FEEDEQ_LEVELS =
((FEEDEQ_GAIN_MAX
- FEEDEQ_GAIN_MIN
) * \
346 floor
(FEEDEQ_GAIN_DIV
/ FEEDEQ_GAIN_STEP
)) + 1;
350 smallest =
10.000000;
353 printf("#ifndef _FEEDER_EQ_GEN_H_\n");
354 printf("#define _FEEDER_EQ_GEN_H_\n\n");
356 printf(" * Generated using feeder_eq_mkfilter.awk, heaven, wind and awesome.\n");
358 printf(" * DO NOT EDIT!\n");
361 printf(" * EQ: %s\n", (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF
) ? \
362 "Shelving" : "Peaking EQ");
364 printf("#define FEEDER_EQ_PRESETS\t\"");
365 printf("%s:%d,%.4f,%d,%.4f:%d,%d,%.1f:", \
366 (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF
) ?
"SHELF" : "PEQ", \
367 FEEDEQ_TREBLE_SFREQ
, FEEDEQ_TREBLE_SLOPE
, \
368 FEEDEQ_BASS_SFREQ
, FEEDEQ_BASS_SLOPE
, \
369 FEEDEQ_GAIN_MIN
, FEEDEQ_GAIN_MAX
, \
370 FEEDEQ_GAIN_STEP
* FEEDEQ_GAIN_RECIPROCAL
);
371 for (i =
0; i
< length(allfreq
); i
++) {
374 printf("%d", allfreq
[i
]);
377 printf("struct feed_eq_coeff_tone {\n");
378 printf("\tint32_t a1, a2;\n");
379 printf("\tint32_t b0, b1, b2;\n");
381 printf("struct feed_eq_coeff {\n");
382 #printf("\tstruct {\n");
383 #printf("\t\tint32_t a1, a2;\n");
384 #printf("\t\tint32_t b0, b1, b2;\n");
385 #printf("\t} treble, bass;\n");
386 printf("\tstruct feed_eq_coeff_tone treble;\n");
387 printf("\tstruct feed_eq_coeff_tone bass;\n");
388 #printf("\tstruct {\n");
389 #printf("\t\tint32_t a1, a2;\n");
390 #printf("\t\tint32_t b0, b1, b2;\n");
391 #printf("\t} bass;\n");
393 for (i =
0; i
< length(allfreq
); i
++)
394 feedeq_gen_freq_coeffs
(allfreq
[i
]);
396 printf("static const struct {\n");
397 printf("\tuint32_t rate;\n");
398 printf("\tstruct feed_eq_coeff *coeff;\n");
399 printf("} feed_eq_tab[] = {\n");
400 for (i =
0; i
< length(allfreq
); i
++) {
401 printf("\t{ %6d, eq_%-6d },\n", allfreq
[i
], allfreq
[i
]);
405 printf("\n#define FEEDEQ_RATE_MIN\t\t%d\n", allfreq
[0]);
406 printf("#define FEEDEQ_RATE_MAX\t\t%d\n", allfreq
[length(allfreq
) - 1]);
407 printf("\n#define FEEDEQ_TAB_SIZE\t\t\t\t\t\t\t\\\n");
408 printf("\t((int32_t)(sizeof(feed_eq_tab) / sizeof(feed_eq_tab[0])))\n");
410 printf("\nstatic const struct {\n");
411 printf("\tint32_t mul, shift;\n");
412 printf("} feed_eq_preamp[] = {\n");
413 for (i =
(FEEDEQ_GAIN_MAX
* 2 * FEEDEQ_GAIN_DIV
); i
>=
0; \
414 i
-= FEEDEQ_GAIN_STEP
) {
415 feedeq_calc_preamp
(norm
, i
* FEEDEQ_GAIN_RECIPROCAL
);
416 dbgain =
((FEEDEQ_GAIN_MAX
* FEEDEQ_GAIN_DIV
) - i
) * \
417 FEEDEQ_GAIN_RECIPROCAL
;
418 printf("\t{ 0x%08x, 0x%08x },\t/* %+5.1f dB */\n", \
419 norm
["mul"], norm
["shift"], dbgain
);
423 printf("\n#define FEEDEQ_GAIN_MIN\t\t%d", FEEDEQ_GAIN_MIN
);
424 printf("\n#define FEEDEQ_GAIN_MAX\t\t%d\n", FEEDEQ_GAIN_MAX
);
426 printf("\n#define FEEDEQ_GAIN_SHIFT\t%d\n", FEEDEQ_GAIN_SHIFT
);
427 printf("#define FEEDEQ_GAIN_DIV\t\t%d\n", FEEDEQ_GAIN_DIV
);
428 printf("#define FEEDEQ_GAIN_FMASK\t0x%08x\n", FEEDEQ_GAIN_FMASK
);
429 printf("#define FEEDEQ_GAIN_STEP\t%d\n", FEEDEQ_GAIN_STEP
);
431 #printf("\n#define FEEDEQ_PREAMP_MIN\t-%d\n", \
432 # shl(FEEDEQ_GAIN_MAX, FEEDEQ_GAIN_SHIFT));
433 #printf("#define FEEDEQ_PREAMP_MAX\t%d\n", \
434 # shl(FEEDEQ_GAIN_MAX, FEEDEQ_GAIN_SHIFT));
436 printf("\n#define FEEDEQ_COEFF_SHIFT\t%d\n", FEEDEQ_COEFF_SHIFT
);
438 #feedeq_calc_preamp(norm, FEEDEQ_GAIN_MAX);
440 #printf("#define FEEDEQ_COEFF_NORM(v)\t(");
441 #if (norm["mul"] == 1)
442 # printf("(v) >> %d", norm["shift"]);
444 # printf("(0x%xLL * (v)) >> %d", norm["mul"], norm["shift"]);
447 #printf("\n#define FEEDEQ_LEVELS\t\t%d\n", FEEDEQ_LEVELS);
448 if (FEEDEQ_ERR_CLIP
!= 0)
449 printf("\n#define FEEDEQ_ERR_CLIP\t\t%d\n", FEEDEQ_ERR_CLIP
);
451 printf(" * volume level mapping (0 - 100):\n");
454 for (i =
0; i
<=
100; i
++) {
455 ind = floor
((i
* FEEDEQ_LEVELS
) / 100);
456 if (ind
>= FEEDEQ_LEVELS
)
457 ind = FEEDEQ_LEVELS
- 1;
458 printf(" *\t%3d -> %3d (%+5.1f dB)\n", \
459 i
, ind
, FEEDEQ_GAIN_MIN
+ \
460 (ind
* (FEEDEQ_GAIN_RECIPROCAL
* FEEDEQ_GAIN_STEP
)));
464 printf("\n/*\n * smallest: %.32f\n * largest: %.32f\n */\n", \
466 printf("\n#endif\t/* !_FEEDER_EQ_GEN_H_ */\n");