1#!/usr/bin/awk -f 2# 3# Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org> 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 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. 14# 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 25# SUCH DAMAGE. 26# 27# $FreeBSD: head/sys/tools/sound/feeder_eq_mkfilter.awk 193889 2009-06-10 06:49:45Z ariff $ 28# 29 30# 31# Biquad coefficients generator for Parametric Software Equalizer. Not as ugly 32# as 'feeder_rate_mkfilter.awk' 33# 34# Based on: 35# 36# "Cookbook formulae for audio EQ biquad filter coefficients" 37# by Robert Bristow-Johnson <rbj@audioimagination.com> 38# 39# - http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt 40# 41 42 43 44# 45# Some basic Math functions. 46# 47function abs(x) 48{ 49 return (((x < 0) ? -x : x) + 0); 50} 51 52function fabs(x) 53{ 54 return (((x < 0.0) ? -x : x) + 0.0); 55} 56 57function floor(x, r) 58{ 59 r = int(x); 60 if (r > x) 61 r--; 62 return (r + 0); 63} 64 65function pow(x, y) 66{ 67 return (exp(1.0 * y * log(1.0 * x))); 68} 69 70# 71# What the hell... 72# 73function shl(x, y) 74{ 75 while (y > 0) { 76 x *= 2; 77 y--; 78 } 79 return (x); 80} 81 82function feedeq_w0(fc, rate) 83{ 84 return ((2.0 * M_PI * fc) / (1.0 * rate)); 85} 86 87function feedeq_A(gain, A) 88{ 89 if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ || FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) 90 A = pow(10, gain / 40.0); 91 else 92 A = sqrt(pow(10, gain / 20.0)); 93 94 return (A); 95} 96 97function feedeq_alpha(w0, A, QS) 98{ 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); 104 else 105 alpha = 0.0; 106 107 return (alpha); 108} 109 110function feedeq_fx_floor(v, r) 111{ 112 if (fabs(v) < fabs(smallest)) 113 smallest = v; 114 if (fabs(v) > fabs(largest)) 115 largest = v; 116 117 r = floor((v * FEEDEQ_COEFF_ONE) + 0.5); 118 119 if (r < INT32_MIN || r > INT32_MAX) 120 printf("\n#error overflow v=%f, " \ 121 "please reduce FEEDEQ_COEFF_SHIFT\n", v); 122 123 return (r); 124} 125 126function feedeq_gen_biquad_coeffs(coeffs, rate, gain, \ 127 w0, A, alpha, a0, a1, a2, b0, b1, b2) 128{ 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); 132 133 if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ) { 134 b0 = 1.0 + (alpha * A); 135 b1 = -2.0 * cos(w0); 136 b2 = 1.0 - (alpha * A); 137 a0 = 1.0 + (alpha / A); 138 a1 = -2.0 * cos(w0); 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 ); 147 } else 148 b0 = b1 = b2 = a0 = a1 = a2 = 0.0; 149 150 b0 /= a0; 151 b1 /= a0; 152 b2 /= a0; 153 a1 /= a0; 154 a2 /= a0; 155 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); 162 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); 166 167 if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ) { 168 b0 = 1.0 + (alpha * A); 169 b1 = -2.0 * cos(w0); 170 b2 = 1.0 - (alpha * A); 171 a0 = 1.0 + (alpha / A); 172 a1 = -2.0 * cos(w0); 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 ); 181 } else 182 b0 = b1 = b2 = a0 = a1 = a2 = 0.0; 183 184 b0 /= a0; 185 b1 /= a0; 186 b2 /= a0; 187 a1 /= a0; 188 a2 /= a0; 189 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); 196} 197 198function feedeq_gen_freq_coeffs(frq, g, i, v) 199{ 200 coeffs[0] = 0; 201 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); 207 } 208 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) { 214 printf(" {{ "); 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) ? " " : ", "); 220 } 221 printf("},\n { "); 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) ? " " : ", "); 227 } 228 printf("}}%s\n", \ 229 (g < (FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV)) ? "," : ""); 230 } 231 printf("};\n"); 232} 233 234function feedeq_calc_preamp(norm, gain, shift, mul, bit, attn) 235{ 236 shift = FEEDEQ_PREAMP_SHIFT; 237 238 if (floor(FEEDEQ_PREAMP_BITDB) == 6 && \ 239 (1.0 * floor(gain)) == gain && (floor(gain) % 6) == 0) { 240 mul = 1; 241 shift = floor(floor(gain) / 6); 242 } else { 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); 246 } 247 248 while ((mul % 2) == 0 && shift > 0) { 249 mul = floor(mul / 2); 250 shift--; 251 } 252 253 norm["mul"] = mul; 254 norm["shift"] = shift; 255} 256 257BEGIN { 258 M_PI = atan2(0.0, -1.0); 259 260 INT32_MAX = 1 + ((shl(1, 30) - 1) * 2); 261 INT32_MIN = -1 - INT32_MAX; 262 263 FEEDEQ_TYPE_PEQ = 0; 264 FEEDEQ_TYPE_SHELF = 1; 265 266 FEEDEQ_TYPE = FEEDEQ_TYPE_PEQ; 267 268 FEEDEQ_COEFF_SHIFT = 24; 269 FEEDEQ_COEFF_ONE = shl(1, FEEDEQ_COEFF_SHIFT); 270 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)); 274 275 FEEDEQ_GAIN_DIV = 10; 276 i = 0; 277 j = 1; 278 while (j < FEEDEQ_GAIN_DIV) { 279 j *= 2; 280 i++; 281 } 282 FEEDEQ_GAIN_SHIFT = i; 283 FEEDEQ_GAIN_FMASK = shl(1, FEEDEQ_GAIN_SHIFT) - 1; 284 285 FEEDEQ_GAIN_RECIPROCAL = 1.0 / FEEDEQ_GAIN_DIV; 286 287 if (ARGC == 2) { 288 i = 1; 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; 295 } 296 i++; 297 } 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]); 309 if (j < 2) 310 j = 1; 311 else if (j < 5) 312 j = 2; 313 else if (j < 10) 314 j = 5; 315 else 316 j = 10; 317 if (j > FEEDEQ_GAIN_DIV || (FEEDEQ_GAIN_DIV % j) != 0) 318 j = FEEDEQ_GAIN_DIV; 319 FEEDEQ_GAIN_STEP = j; 320 } else 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]); 325 } else { 326 FEEDEQ_TREBLE_SFREQ = 16000.0; 327 FEEDEQ_TREBLE_SLOPE = 0.25; 328 FEEDEQ_BASS_SFREQ = 62.0; 329 FEEDEQ_BASS_SLOPE = 0.25; 330 331 FEEDEQ_GAIN_MIN = -9; 332 FEEDEQ_GAIN_MAX = 9; 333 334 FEEDEQ_GAIN_STEP = FEEDEQ_GAIN_DIV; 335 336 337 allfreq[0] = 44100; 338 allfreq[1] = 48000; 339 allfreq[2] = 88200; 340 allfreq[3] = 96000; 341 allfreq[4] = 176400; 342 allfreq[5] = 192000; 343 } 344 345 FEEDEQ_LEVELS = ((FEEDEQ_GAIN_MAX - FEEDEQ_GAIN_MIN) * \ 346 floor(FEEDEQ_GAIN_DIV / FEEDEQ_GAIN_STEP)) + 1; 347 348 FEEDEQ_ERR_CLIP = 0; 349 350 smallest = 10.000000; 351 largest = 0.000010; 352 353 printf("#ifndef _FEEDER_EQ_GEN_H_\n"); 354 printf("#define _FEEDER_EQ_GEN_H_\n\n"); 355 printf("/*\n"); 356 printf(" * Generated using feeder_eq_mkfilter.awk, heaven, wind and awesome.\n"); 357 printf(" *\n"); 358 printf(" * DO NOT EDIT!\n"); 359 printf(" */\n\n"); 360 printf("/*\n"); 361 printf(" * EQ: %s\n", (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) ? \ 362 "Shelving" : "Peaking EQ"); 363 printf(" */\n"); 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++) { 372 if (i != 0) 373 printf(","); 374 printf("%d", allfreq[i]); 375 } 376 printf("\"\n\n"); 377 printf("struct feed_eq_coeff_tone {\n"); 378 printf("\tint32_t a1, a2;\n"); 379 printf("\tint32_t b0, b1, b2;\n"); 380 printf("};\n\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"); 392 printf("};\n"); 393 for (i = 0; i < length(allfreq); i++) 394 feedeq_gen_freq_coeffs(allfreq[i]); 395 printf("\n"); 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]); 402 } 403 printf("};\n"); 404 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"); 409 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); 420 } 421 printf("};\n"); 422 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); 425 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); 430 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)); 435 436 printf("\n#define FEEDEQ_COEFF_SHIFT\t%d\n", FEEDEQ_COEFF_SHIFT); 437 438 #feedeq_calc_preamp(norm, FEEDEQ_GAIN_MAX); 439 440 #printf("#define FEEDEQ_COEFF_NORM(v)\t("); 441 #if (norm["mul"] == 1) 442 # printf("(v) >> %d", norm["shift"]); 443 #else 444 # printf("(0x%xLL * (v)) >> %d", norm["mul"], norm["shift"]); 445 #printf(")\n"); 446 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); 450 printf("\n/*\n"); 451 printf(" * volume level mapping (0 - 100):\n"); 452 printf(" *\n"); 453 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))); 461 } 462 463 printf(" */\n"); 464 printf("\n/*\n * smallest: %.32f\n * largest: %.32f\n */\n", \ 465 smallest, largest); 466 printf("\n#endif\t/* !_FEEDER_EQ_GEN_H_ */\n"); 467} 468