]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/tools/sound/feeder_eq_mkfilter.awk
r272552 applied the patch from ipfilter upstream fil.c r1.129 to fix
[FreeBSD/FreeBSD.git] / sys / tools / sound / feeder_eq_mkfilter.awk
1 #!/usr/bin/awk -f
2 #
3 # SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 #
5 # Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org>
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions
10 # are met:
11 # 1. Redistributions of source code must retain the above copyright
12 #    notice, this list of conditions and the following disclaimer.
13 # 2. Redistributions in binary form must reproduce the above copyright
14 #    notice, this list of conditions and the following disclaimer in the
15 #    documentation and/or other materials provided with the distribution.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 # ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 # SUCH DAMAGE.
28 #
29 # $FreeBSD$
30 #
31
32 #
33 # Biquad coefficients generator for Parametric Software Equalizer. Not as ugly
34 # as 'feeder_rate_mkfilter.awk'
35 #
36 # Based on:
37 #
38 #  "Cookbook formulae for audio EQ biquad filter coefficients"
39 #    by Robert Bristow-Johnson  <rbj@audioimagination.com>
40 #
41 #    -  http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
42 #
43
44
45
46 #
47 # Some basic Math functions.
48 #
49 function abs(x)
50 {
51         return (((x < 0) ? -x : x) + 0);
52 }
53
54 function fabs(x)
55 {
56         return (((x < 0.0) ? -x : x) + 0.0);
57 }
58
59 function floor(x, r)
60 {
61         r = int(x);
62         if (r > x)
63                 r--;
64         return (r + 0);
65 }
66
67 function pow(x, y)
68 {
69         return (exp(1.0 * y * log(1.0 * x)));
70 }
71
72 #
73 # What the hell...
74 #
75 function shl(x, y)
76 {
77         while (y > 0) {
78                 x *= 2;
79                 y--;
80         }
81         return (x);
82 }
83
84 function feedeq_w0(fc, rate)
85 {
86         return ((2.0 * M_PI * fc) / (1.0 * rate));
87 }
88
89 function feedeq_A(gain, A)
90 {
91         if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ || FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF)
92                 A = pow(10, gain / 40.0);
93         else
94                 A = sqrt(pow(10, gain / 20.0));
95
96         return (A);
97 }
98
99 function feedeq_alpha(w0, A, QS)
100 {
101         if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ)
102                 alpha = sin(w0) / (2.0 * QS);
103         else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF)
104                 alpha = sin(w0) * 0.5 * sqrt(A + ((1.0 / A) *           \
105                     ((1.0 / QS) - 1.0)) + 2.0);
106         else
107                 alpha = 0.0;
108
109         return (alpha);
110 }
111
112 function feedeq_fx_floor(v, r)
113 {
114         if (fabs(v) < fabs(smallest))
115                 smallest = v;
116         if (fabs(v) > fabs(largest))
117                 largest = v;
118
119         r = floor((v * FEEDEQ_COEFF_ONE) + 0.5);
120
121         if (r < INT32_MIN || r > INT32_MAX)
122                 printf("\n#error overflow v=%f, "                       \
123                     "please reduce FEEDEQ_COEFF_SHIFT\n", v);
124
125         return (r);
126 }
127
128 function feedeq_gen_biquad_coeffs(coeffs, rate, gain,                   \
129     w0, A, alpha, a0, a1, a2, b0, b1, b2)
130 {
131         w0    = feedeq_w0(FEEDEQ_TREBLE_SFREQ, 1.0 * rate);
132         A     = feedeq_A(1.0 * gain);
133         alpha = feedeq_alpha(w0, A, FEEDEQ_TREBLE_SLOPE);
134
135         if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ) {
136                 b0 =  1.0 + (alpha * A);
137                 b1 = -2.0 * cos(w0);
138                 b2 =  1.0 - (alpha * A);
139                 a0 =  1.0 + (alpha / A);
140                 a1 = -2.0 * cos(w0);
141                 a2 =  1.0 - (alpha / A);
142         } else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) {
143                 b0 =      A*((A+1.0)+((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha));
144                 b1 = -2.0*A*((A-1.0)+((A+1.0)*cos(w0))                    );
145                 b2 =      A*((A+1.0)+((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha));
146                 a0 =         (A+1.0)-((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha );
147                 a1 =  2.0 * ((A-1.0)-((A+1.0)*cos(w0))                    );
148                 a2 =         (A+1.0)-((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha );
149         } else
150                 b0 = b1 = b2 = a0 = a1 = a2 = 0.0;
151
152         b0 /= a0;
153         b1 /= a0;
154         b2 /= a0;
155         a1 /= a0;
156         a2 /= a0;
157
158         coeffs["treble", gain, 0] = feedeq_fx_floor(a0);
159         coeffs["treble", gain, 1] = feedeq_fx_floor(a1);
160         coeffs["treble", gain, 2] = feedeq_fx_floor(a2);
161         coeffs["treble", gain, 3] = feedeq_fx_floor(b0);
162         coeffs["treble", gain, 4] = feedeq_fx_floor(b1);
163         coeffs["treble", gain, 5] = feedeq_fx_floor(b2);
164
165         w0    = feedeq_w0(FEEDEQ_BASS_SFREQ, 1.0 * rate);
166         A     = feedeq_A(1.0 * gain);
167         alpha = feedeq_alpha(w0, A, FEEDEQ_BASS_SLOPE);
168
169         if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ) {
170                 b0 =  1.0 + (alpha * A);
171                 b1 = -2.0 * cos(w0);
172                 b2 =  1.0 - (alpha * A);
173                 a0 =  1.0 + (alpha / A);
174                 a1 = -2.0 * cos(w0);
175                 a2 =  1.0 - (alpha / A);
176         } else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) {
177                 b0 =      A*((A+1.0)-((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha));
178                 b1 =  2.0*A*((A-1.0)-((A+1.0)*cos(w0))                    );
179                 b2 =      A*((A+1.0)-((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha));
180                 a0 =         (A+1.0)+((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha );
181                 a1 = -2.0 * ((A-1.0)+((A+1.0)*cos(w0))                    );
182                 a2 =         (A+1.0)+((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha );
183         } else
184                 b0 = b1 = b2 = a0 = a1 = a2 = 0.0;
185
186         b0 /= a0;
187         b1 /= a0;
188         b2 /= a0;
189         a1 /= a0;
190         a2 /= a0;
191
192         coeffs["bass", gain, 0] = feedeq_fx_floor(a0);
193         coeffs["bass", gain, 1] = feedeq_fx_floor(a1);
194         coeffs["bass", gain, 2] = feedeq_fx_floor(a2);
195         coeffs["bass", gain, 3] = feedeq_fx_floor(b0);
196         coeffs["bass", gain, 4] = feedeq_fx_floor(b1);
197         coeffs["bass", gain, 5] = feedeq_fx_floor(b2);
198 }
199
200 function feedeq_gen_freq_coeffs(frq, g, i, v)
201 {
202         coeffs[0] = 0;
203
204         for (g = (FEEDEQ_GAIN_MIN * FEEDEQ_GAIN_DIV);                   \
205             g <= (FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV);                   \
206             g += FEEDEQ_GAIN_STEP) {
207                 feedeq_gen_biquad_coeffs(coeffs, frq,                   \
208                     g * FEEDEQ_GAIN_RECIPROCAL);
209         }
210
211         printf("\nstatic struct feed_eq_coeff eq_%d[%d] "               \
212             "= {\n", frq, FEEDEQ_LEVELS);
213         for (g = (FEEDEQ_GAIN_MIN * FEEDEQ_GAIN_DIV);                   \
214             g <= (FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV);                   \
215             g += FEEDEQ_GAIN_STEP) {
216                 printf("     {{ ");
217                 for (i = 1; i < 6; i++) {
218                         v = coeffs["treble", g * FEEDEQ_GAIN_RECIPROCAL, i];
219                         printf("%s0x%08x%s",                            \
220                             (v < 0) ? "-" : " ", abs(v),                \
221                             (i == 5) ? " " : ", ");
222                 }
223                 printf("},\n      { ");
224                 for (i = 1; i < 6; i++) {
225                         v = coeffs["bass", g * FEEDEQ_GAIN_RECIPROCAL, i];
226                         printf("%s0x%08x%s",                            \
227                             (v < 0) ? "-" : " ", abs(v),                \
228                             (i == 5) ? " " : ", ");
229                 }
230                 printf("}}%s\n",                                        \
231                     (g < (FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV)) ? "," : "");
232         }
233         printf("};\n");
234 }
235
236 function feedeq_calc_preamp(norm, gain, shift, mul, bit, attn)
237 {
238         shift = FEEDEQ_PREAMP_SHIFT;
239
240         if (floor(FEEDEQ_PREAMP_BITDB) == 6 &&                          \
241             (1.0 * floor(gain)) == gain && (floor(gain) % 6) == 0) {
242                 mul = 1;
243                 shift = floor(floor(gain) / 6);
244         } else {
245                 bit = 32.0 - ((1.0 * gain) / (1.0 * FEEDEQ_PREAMP_BITDB));
246                 attn = pow(2.0, bit) / pow(2.0, 32.0);
247                 mul = floor((attn * FEEDEQ_PREAMP_ONE) + 0.5);
248         }
249
250         while ((mul % 2) == 0 && shift > 0) {
251                 mul = floor(mul / 2);
252                 shift--;
253         }
254
255         norm["mul"] = mul;
256         norm["shift"] = shift;
257 }
258
259 BEGIN {
260         M_PI = atan2(0.0, -1.0);
261
262         INT32_MAX = 1 + ((shl(1, 30) - 1) * 2);
263         INT32_MIN = -1 - INT32_MAX;
264
265         FEEDEQ_TYPE_PEQ   = 0;
266         FEEDEQ_TYPE_SHELF = 1;
267
268         FEEDEQ_TYPE       = FEEDEQ_TYPE_PEQ;
269
270         FEEDEQ_COEFF_SHIFT = 24;
271         FEEDEQ_COEFF_ONE   = shl(1, FEEDEQ_COEFF_SHIFT);
272
273         FEEDEQ_PREAMP_SHIFT = 31;
274         FEEDEQ_PREAMP_ONE   = shl(1, FEEDEQ_PREAMP_SHIFT);
275         FEEDEQ_PREAMP_BITDB = 6; # 20.0 * (log(2.0) / log(10.0));
276
277         FEEDEQ_GAIN_DIV   = 10;
278         i = 0;
279         j = 1;
280         while (j < FEEDEQ_GAIN_DIV) {
281                 j *= 2;
282                 i++;
283         }
284         FEEDEQ_GAIN_SHIFT = i;
285         FEEDEQ_GAIN_FMASK = shl(1, FEEDEQ_GAIN_SHIFT) - 1;
286
287         FEEDEQ_GAIN_RECIPROCAL = 1.0 / FEEDEQ_GAIN_DIV;
288
289         if (ARGC == 2) {
290                 i = 1;
291                 split(ARGV[1], arg, ":");
292                 while (match(arg[i], "^[^0-9]*$")) {
293                         if (arg[i] == "PEQ") {
294                                 FEEDEQ_TYPE = FEEDEQ_TYPE_PEQ;
295                         } else if (arg[i] == "SHELF") {
296                                 FEEDEQ_TYPE = FEEDEQ_TYPE_SHELF;
297                         }
298                         i++;
299                 }
300                 split(arg[i++], subarg, ",");
301                 FEEDEQ_TREBLE_SFREQ = 1.0 * subarg[1];
302                 FEEDEQ_TREBLE_SLOPE = 1.0 * subarg[2];
303                 split(arg[i++], subarg, ",");
304                 FEEDEQ_BASS_SFREQ = 1.0 * subarg[1];
305                 FEEDEQ_BASS_SLOPE = 1.0 * subarg[2];
306                 split(arg[i++], subarg, ",");
307                 FEEDEQ_GAIN_MIN = floor(1.0 * subarg[1]);
308                 FEEDEQ_GAIN_MAX = floor(1.0 * subarg[2]);
309                 if (length(subarg) > 2) {
310                         j = floor(1.0 * FEEDEQ_GAIN_DIV * subarg[3]);
311                         if (j < 2)
312                                 j = 1;
313                         else if (j < 5)
314                                 j = 2;
315                         else if (j < 10)
316                                 j = 5;
317                         else
318                                 j = 10;
319                         if (j > FEEDEQ_GAIN_DIV || (FEEDEQ_GAIN_DIV % j) != 0)
320                                 j = FEEDEQ_GAIN_DIV;
321                         FEEDEQ_GAIN_STEP = j;
322                 } else
323                         FEEDEQ_GAIN_STEP = FEEDEQ_GAIN_DIV;
324                 split(arg[i], subarg, ",");
325                 for (i = 1; i <= length(subarg); i++)
326                         allfreq[i - 1] = floor(1.0 * subarg[i]);
327         } else {
328                 FEEDEQ_TREBLE_SFREQ  = 16000.0;
329                 FEEDEQ_TREBLE_SLOPE  = 0.25;
330                 FEEDEQ_BASS_SFREQ    = 62.0;
331                 FEEDEQ_BASS_SLOPE    = 0.25;
332
333                 FEEDEQ_GAIN_MIN  = -9;
334                 FEEDEQ_GAIN_MAX  = 9;
335
336                 FEEDEQ_GAIN_STEP = FEEDEQ_GAIN_DIV;
337
338
339                 allfreq[0] = 44100;
340                 allfreq[1] = 48000;
341                 allfreq[2] = 88200;
342                 allfreq[3] = 96000;
343                 allfreq[4] = 176400;
344                 allfreq[5] = 192000;
345         }
346
347         FEEDEQ_LEVELS = ((FEEDEQ_GAIN_MAX - FEEDEQ_GAIN_MIN) *          \
348             floor(FEEDEQ_GAIN_DIV / FEEDEQ_GAIN_STEP)) + 1;
349
350         FEEDEQ_ERR_CLIP = 0;
351
352         smallest = 10.000000;
353         largest  =  0.000010;
354
355         printf("#ifndef _FEEDER_EQ_GEN_H_\n");
356         printf("#define _FEEDER_EQ_GEN_H_\n\n");
357         printf("/*\n");
358         printf(" * Generated using feeder_eq_mkfilter.awk, heaven, wind and awesome.\n");
359         printf(" *\n");
360         printf(" * DO NOT EDIT!\n");
361         printf(" */\n\n");
362         printf("/*\n");
363         printf(" * EQ: %s\n", (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) ?      \
364             "Shelving" : "Peaking EQ");
365         printf(" */\n");
366         printf("#define FEEDER_EQ_PRESETS\t\"");
367         printf("%s:%d,%.4f,%d,%.4f:%d,%d,%.1f:",                        \
368             (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) ? "SHELF" : "PEQ",       \
369             FEEDEQ_TREBLE_SFREQ, FEEDEQ_TREBLE_SLOPE,                   \
370             FEEDEQ_BASS_SFREQ, FEEDEQ_BASS_SLOPE,                       \
371             FEEDEQ_GAIN_MIN, FEEDEQ_GAIN_MAX,                           \
372             FEEDEQ_GAIN_STEP * FEEDEQ_GAIN_RECIPROCAL);
373         for (i = 0; i < length(allfreq); i++) {
374                 if (i != 0)
375                         printf(",");
376                 printf("%d", allfreq[i]);
377         }
378         printf("\"\n\n");
379         printf("struct feed_eq_coeff_tone {\n");
380         printf("\tint32_t a1, a2;\n");
381         printf("\tint32_t b0, b1, b2;\n");
382         printf("};\n\n");
383         printf("struct feed_eq_coeff {\n");
384         #printf("\tstruct {\n");
385         #printf("\t\tint32_t a1, a2;\n");
386         #printf("\t\tint32_t b0, b1, b2;\n");
387         #printf("\t} treble, bass;\n");
388         printf("\tstruct feed_eq_coeff_tone treble;\n");
389         printf("\tstruct feed_eq_coeff_tone bass;\n");
390         #printf("\tstruct {\n");
391         #printf("\t\tint32_t a1, a2;\n");
392         #printf("\t\tint32_t b0, b1, b2;\n");
393         #printf("\t} bass;\n");
394         printf("};\n");
395         for (i = 0; i < length(allfreq); i++)
396                 feedeq_gen_freq_coeffs(allfreq[i]);
397         printf("\n");
398         printf("static const struct {\n");
399         printf("\tuint32_t rate;\n");
400         printf("\tstruct feed_eq_coeff *coeff;\n");
401         printf("} feed_eq_tab[] = {\n");
402         for (i = 0; i < length(allfreq); i++) {
403                 printf("\t{ %6d, eq_%-6d },\n", allfreq[i], allfreq[i]);
404         }
405         printf("};\n");
406
407         printf("\n#define FEEDEQ_RATE_MIN\t\t%d\n", allfreq[0]);
408         printf("#define FEEDEQ_RATE_MAX\t\t%d\n", allfreq[length(allfreq) - 1]);
409         printf("\n#define FEEDEQ_TAB_SIZE\t\t\t\t\t\t\t\\\n");
410         printf("\t((int32_t)(sizeof(feed_eq_tab) / sizeof(feed_eq_tab[0])))\n");
411
412         printf("\nstatic const struct {\n");
413         printf("\tint32_t mul, shift;\n");
414         printf("} feed_eq_preamp[] = {\n");
415         for (i = (FEEDEQ_GAIN_MAX * 2 * FEEDEQ_GAIN_DIV); i >= 0;       \
416             i -= FEEDEQ_GAIN_STEP) {
417                 feedeq_calc_preamp(norm, i * FEEDEQ_GAIN_RECIPROCAL);
418                 dbgain = ((FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV) - i) *    \
419                     FEEDEQ_GAIN_RECIPROCAL;
420                 printf("\t{ 0x%08x, 0x%08x },\t/* %+5.1f dB */\n",      \
421                     norm["mul"], norm["shift"], dbgain);
422         }
423         printf("};\n");
424
425         printf("\n#define FEEDEQ_GAIN_MIN\t\t%d", FEEDEQ_GAIN_MIN);
426         printf("\n#define FEEDEQ_GAIN_MAX\t\t%d\n", FEEDEQ_GAIN_MAX);
427
428         printf("\n#define FEEDEQ_GAIN_SHIFT\t%d\n", FEEDEQ_GAIN_SHIFT);
429         printf("#define FEEDEQ_GAIN_DIV\t\t%d\n", FEEDEQ_GAIN_DIV);
430         printf("#define FEEDEQ_GAIN_FMASK\t0x%08x\n", FEEDEQ_GAIN_FMASK);
431         printf("#define FEEDEQ_GAIN_STEP\t%d\n", FEEDEQ_GAIN_STEP);
432
433         #printf("\n#define FEEDEQ_PREAMP_MIN\t-%d\n",                   \
434         #    shl(FEEDEQ_GAIN_MAX, FEEDEQ_GAIN_SHIFT));
435         #printf("#define FEEDEQ_PREAMP_MAX\t%d\n",                      \
436         #    shl(FEEDEQ_GAIN_MAX, FEEDEQ_GAIN_SHIFT));
437
438         printf("\n#define FEEDEQ_COEFF_SHIFT\t%d\n", FEEDEQ_COEFF_SHIFT);
439
440         #feedeq_calc_preamp(norm, FEEDEQ_GAIN_MAX);
441
442         #printf("#define FEEDEQ_COEFF_NORM(v)\t(");
443         #if (norm["mul"] == 1)
444         #       printf("(v) >> %d", norm["shift"]);
445         #else
446         #       printf("(0x%xLL * (v)) >> %d", norm["mul"], norm["shift"]);
447         #printf(")\n");
448
449         #printf("\n#define FEEDEQ_LEVELS\t\t%d\n", FEEDEQ_LEVELS);
450         if (FEEDEQ_ERR_CLIP != 0)
451                 printf("\n#define FEEDEQ_ERR_CLIP\t\t%d\n", FEEDEQ_ERR_CLIP);
452         printf("\n/*\n");
453         printf(" * volume level mapping (0 - 100):\n");
454         printf(" *\n");
455
456         for (i = 0; i <= 100; i++) {
457                 ind = floor((i * FEEDEQ_LEVELS) / 100);
458                 if (ind >= FEEDEQ_LEVELS)
459                         ind = FEEDEQ_LEVELS - 1;
460                 printf(" *\t%3d  ->  %3d (%+5.1f dB)\n",                \
461                     i, ind, FEEDEQ_GAIN_MIN +                           \
462                     (ind * (FEEDEQ_GAIN_RECIPROCAL * FEEDEQ_GAIN_STEP)));
463         }
464
465         printf(" */\n");
466         printf("\n/*\n * smallest: %.32f\n *  largest: %.32f\n */\n",   \
467             smallest, largest);
468         printf("\n#endif\t/* !_FEEDER_EQ_GEN_H_ */\n");
469 }