1193640Sariff#!/usr/bin/awk -f
2193640Sariff#
3193640Sariff# Copyright (c) 2008-2009 Ariff Abdullah <ariff@FreeBSD.org>
4193640Sariff# All rights reserved.
5193640Sariff#
6193640Sariff# Redistribution and use in source and binary forms, with or without
7193640Sariff# modification, are permitted provided that the following conditions
8193640Sariff# are met:
9193640Sariff# 1. Redistributions of source code must retain the above copyright
10193640Sariff#    notice, this list of conditions and the following disclaimer.
11193640Sariff# 2. Redistributions in binary form must reproduce the above copyright
12193640Sariff#    notice, this list of conditions and the following disclaimer in the
13193640Sariff#    documentation and/or other materials provided with the distribution.
14193640Sariff#
15193640Sariff# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16193640Sariff# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17193640Sariff# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18193640Sariff# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19193640Sariff# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20193640Sariff# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21193640Sariff# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22193640Sariff# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23193640Sariff# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24193640Sariff# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25193640Sariff# SUCH DAMAGE.
26193640Sariff#
27193640Sariff# $FreeBSD$
28193640Sariff#
29193640Sariff
30193640Sariff#
31193640Sariff# Biquad coefficients generator for Parametric Software Equalizer. Not as ugly
32193640Sariff# as 'feeder_rate_mkfilter.awk'
33193640Sariff#
34193640Sariff# Based on:
35193640Sariff#
36193640Sariff#  "Cookbook formulae for audio EQ biquad filter coefficients"
37193640Sariff#    by Robert Bristow-Johnson  <rbj@audioimagination.com>
38193640Sariff#
39193640Sariff#    -  http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
40193640Sariff#
41193640Sariff
42193640Sariff
43193640Sariff
44193640Sariff#
45193640Sariff# Some basic Math functions.
46193640Sariff#
47193640Sarifffunction abs(x)
48193640Sariff{
49193640Sariff	return (((x < 0) ? -x : x) + 0);
50193640Sariff}
51193640Sariff
52193640Sarifffunction fabs(x)
53193640Sariff{
54193640Sariff	return (((x < 0.0) ? -x : x) + 0.0);
55193640Sariff}
56193640Sariff
57193640Sarifffunction floor(x, r)
58193640Sariff{
59193640Sariff	r = int(x);
60193640Sariff	if (r > x)
61193640Sariff		r--;
62193640Sariff	return (r + 0);
63193640Sariff}
64193640Sariff
65193640Sarifffunction pow(x, y)
66193640Sariff{
67193640Sariff	return (exp(1.0 * y * log(1.0 * x)));
68193640Sariff}
69193640Sariff
70193640Sariff#
71193640Sariff# What the hell...
72193640Sariff#
73193640Sarifffunction shl(x, y)
74193640Sariff{
75193640Sariff	while (y > 0) {
76193640Sariff		x *= 2;
77193640Sariff		y--;
78193640Sariff	}
79193640Sariff	return (x);
80193640Sariff}
81193640Sariff
82193640Sarifffunction feedeq_w0(fc, rate)
83193640Sariff{
84193640Sariff	return ((2.0 * M_PI * fc) / (1.0 * rate));
85193640Sariff}
86193640Sariff
87193640Sarifffunction feedeq_A(gain, A)
88193640Sariff{
89193640Sariff	if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ || FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF)
90193640Sariff		A = pow(10, gain / 40.0);
91193640Sariff	else
92193640Sariff		A = sqrt(pow(10, gain / 20.0));
93193640Sariff
94193640Sariff	return (A);
95193640Sariff}
96193640Sariff
97193640Sarifffunction feedeq_alpha(w0, A, QS)
98193640Sariff{
99193640Sariff	if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ)
100193640Sariff		alpha = sin(w0) / (2.0 * QS);
101193640Sariff	else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF)
102193640Sariff		alpha = sin(w0) * 0.5 * sqrt(A + ((1.0 / A) *		\
103193640Sariff		    ((1.0 / QS) - 1.0)) + 2.0);
104193640Sariff	else
105193640Sariff		alpha = 0.0;
106193640Sariff
107193640Sariff	return (alpha);
108193640Sariff}
109193640Sariff
110193640Sarifffunction feedeq_fx_floor(v, r)
111193640Sariff{
112193640Sariff	if (fabs(v) < fabs(smallest))
113193640Sariff		smallest = v;
114193640Sariff	if (fabs(v) > fabs(largest))
115193640Sariff		largest = v;
116193640Sariff
117193640Sariff	r = floor((v * FEEDEQ_COEFF_ONE) + 0.5);
118193640Sariff
119193640Sariff	if (r < INT32_MIN || r > INT32_MAX)
120193640Sariff		printf("\n#error overflow v=%f, "			\
121193640Sariff		    "please reduce FEEDEQ_COEFF_SHIFT\n", v);
122193640Sariff
123193640Sariff	return (r);
124193640Sariff}
125193640Sariff
126193640Sarifffunction feedeq_gen_biquad_coeffs(coeffs, rate, gain,			\
127193640Sariff    w0, A, alpha, a0, a1, a2, b0, b1, b2)
128193640Sariff{
129193640Sariff	w0    = feedeq_w0(FEEDEQ_TREBLE_SFREQ, 1.0 * rate);
130193640Sariff	A     = feedeq_A(1.0 * gain);
131193640Sariff	alpha = feedeq_alpha(w0, A, FEEDEQ_TREBLE_SLOPE);
132193640Sariff
133193640Sariff	if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ) {
134193640Sariff		b0 =  1.0 + (alpha * A);
135193640Sariff		b1 = -2.0 * cos(w0);
136193640Sariff		b2 =  1.0 - (alpha * A);
137193640Sariff		a0 =  1.0 + (alpha / A);
138193640Sariff		a1 = -2.0 * cos(w0);
139193640Sariff		a2 =  1.0 - (alpha / A);
140193640Sariff	} else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) {
141193640Sariff		b0 =      A*((A+1.0)+((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha));
142193640Sariff		b1 = -2.0*A*((A-1.0)+((A+1.0)*cos(w0))                    );
143193640Sariff		b2 =      A*((A+1.0)+((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha));
144193640Sariff		a0 =         (A+1.0)-((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha );
145193640Sariff		a1 =  2.0 * ((A-1.0)-((A+1.0)*cos(w0))                    );
146193640Sariff		a2 =         (A+1.0)-((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha );
147193640Sariff	} else
148193640Sariff		b0 = b1 = b2 = a0 = a1 = a2 = 0.0;
149193640Sariff
150193640Sariff	b0 /= a0;
151193640Sariff	b1 /= a0;
152193640Sariff	b2 /= a0;
153193640Sariff	a1 /= a0;
154193640Sariff	a2 /= a0;
155193640Sariff
156193640Sariff	coeffs["treble", gain, 0] = feedeq_fx_floor(a0);
157193640Sariff	coeffs["treble", gain, 1] = feedeq_fx_floor(a1);
158193640Sariff	coeffs["treble", gain, 2] = feedeq_fx_floor(a2);
159193640Sariff	coeffs["treble", gain, 3] = feedeq_fx_floor(b0);
160193640Sariff	coeffs["treble", gain, 4] = feedeq_fx_floor(b1);
161193640Sariff	coeffs["treble", gain, 5] = feedeq_fx_floor(b2);
162193640Sariff
163193640Sariff	w0    = feedeq_w0(FEEDEQ_BASS_SFREQ, 1.0 * rate);
164193640Sariff	A     = feedeq_A(1.0 * gain);
165193640Sariff	alpha = feedeq_alpha(w0, A, FEEDEQ_BASS_SLOPE);
166193640Sariff
167193640Sariff	if (FEEDEQ_TYPE == FEEDEQ_TYPE_PEQ) {
168193640Sariff		b0 =  1.0 + (alpha * A);
169193640Sariff		b1 = -2.0 * cos(w0);
170193640Sariff		b2 =  1.0 - (alpha * A);
171193640Sariff		a0 =  1.0 + (alpha / A);
172193640Sariff		a1 = -2.0 * cos(w0);
173193640Sariff		a2 =  1.0 - (alpha / A);
174193640Sariff	} else if (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) {
175193640Sariff		b0 =      A*((A+1.0)-((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha));
176193640Sariff		b1 =  2.0*A*((A-1.0)-((A+1.0)*cos(w0))                    );
177193640Sariff		b2 =      A*((A+1.0)-((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha));
178193640Sariff		a0 =         (A+1.0)+((A-1.0)*cos(w0))+(2.0*sqrt(A)*alpha );
179193640Sariff		a1 = -2.0 * ((A-1.0)+((A+1.0)*cos(w0))                    );
180193640Sariff		a2 =         (A+1.0)+((A-1.0)*cos(w0))-(2.0*sqrt(A)*alpha );
181193640Sariff	} else
182193640Sariff		b0 = b1 = b2 = a0 = a1 = a2 = 0.0;
183193640Sariff
184193640Sariff	b0 /= a0;
185193640Sariff	b1 /= a0;
186193640Sariff	b2 /= a0;
187193640Sariff	a1 /= a0;
188193640Sariff	a2 /= a0;
189193640Sariff
190193640Sariff	coeffs["bass", gain, 0] = feedeq_fx_floor(a0);
191193640Sariff	coeffs["bass", gain, 1] = feedeq_fx_floor(a1);
192193640Sariff	coeffs["bass", gain, 2] = feedeq_fx_floor(a2);
193193640Sariff	coeffs["bass", gain, 3] = feedeq_fx_floor(b0);
194193640Sariff	coeffs["bass", gain, 4] = feedeq_fx_floor(b1);
195193640Sariff	coeffs["bass", gain, 5] = feedeq_fx_floor(b2);
196193640Sariff}
197193640Sariff
198193640Sarifffunction feedeq_gen_freq_coeffs(frq, g, i, v)
199193640Sariff{
200193640Sariff	coeffs[0] = 0;
201193640Sariff
202193640Sariff	for (g = (FEEDEQ_GAIN_MIN * FEEDEQ_GAIN_DIV);			\
203193640Sariff	    g <= (FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV);			\
204193640Sariff	    g += FEEDEQ_GAIN_STEP) {
205193640Sariff		feedeq_gen_biquad_coeffs(coeffs, frq,			\
206193640Sariff		    g * FEEDEQ_GAIN_RECIPROCAL);
207193640Sariff	}
208193640Sariff
209193640Sariff	printf("\nstatic struct feed_eq_coeff eq_%d[%d] "		\
210193640Sariff	    "= {\n", frq, FEEDEQ_LEVELS);
211193640Sariff	for (g = (FEEDEQ_GAIN_MIN * FEEDEQ_GAIN_DIV);			\
212193640Sariff	    g <= (FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV);			\
213193640Sariff	    g += FEEDEQ_GAIN_STEP) {
214193640Sariff		printf("     {{ ");
215193640Sariff		for (i = 1; i < 6; i++) {
216193640Sariff			v = coeffs["treble", g * FEEDEQ_GAIN_RECIPROCAL, i];
217193640Sariff			printf("%s0x%08x%s",				\
218193640Sariff			    (v < 0) ? "-" : " ", abs(v),		\
219193640Sariff			    (i == 5) ? " " : ", ");
220193640Sariff		}
221193640Sariff		printf("},\n      { ");
222193640Sariff		for (i = 1; i < 6; i++) {
223193640Sariff			v = coeffs["bass", g * FEEDEQ_GAIN_RECIPROCAL, i];
224193640Sariff			printf("%s0x%08x%s",				\
225193640Sariff			    (v < 0) ? "-" : " ", abs(v),		\
226193640Sariff			    (i == 5) ? " " : ", ");
227193640Sariff		}
228193640Sariff		printf("}}%s\n",					\
229193640Sariff		    (g < (FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV)) ? "," : "");
230193640Sariff	}
231193640Sariff	printf("};\n");
232193640Sariff}
233193640Sariff
234193640Sarifffunction feedeq_calc_preamp(norm, gain, shift, mul, bit, attn)
235193640Sariff{
236193640Sariff	shift = FEEDEQ_PREAMP_SHIFT;
237193640Sariff
238193640Sariff	if (floor(FEEDEQ_PREAMP_BITDB) == 6 &&				\
239193640Sariff	    (1.0 * floor(gain)) == gain && (floor(gain) % 6) == 0) {
240193640Sariff		mul = 1;
241193640Sariff		shift = floor(floor(gain) / 6);
242193640Sariff	} else {
243193640Sariff		bit = 32.0 - ((1.0 * gain) / (1.0 * FEEDEQ_PREAMP_BITDB));
244193640Sariff		attn = pow(2.0, bit) / pow(2.0, 32.0);
245193640Sariff		mul = floor((attn * FEEDEQ_PREAMP_ONE) + 0.5);
246193640Sariff	}
247193640Sariff
248193640Sariff	while ((mul % 2) == 0 && shift > 0) {
249193640Sariff		mul = floor(mul / 2);
250193640Sariff		shift--;
251193640Sariff	}
252193640Sariff
253193640Sariff	norm["mul"] = mul;
254193640Sariff	norm["shift"] = shift;
255193640Sariff}
256193640Sariff
257193640SariffBEGIN {
258193640Sariff	M_PI = atan2(0.0, -1.0);
259193640Sariff
260193640Sariff	INT32_MAX = 1 + ((shl(1, 30) - 1) * 2);
261193640Sariff	INT32_MIN = -1 - INT32_MAX;
262193640Sariff
263193640Sariff	FEEDEQ_TYPE_PEQ   = 0;
264193640Sariff	FEEDEQ_TYPE_SHELF = 1;
265193640Sariff
266193640Sariff	FEEDEQ_TYPE       = FEEDEQ_TYPE_PEQ;
267193640Sariff
268193640Sariff	FEEDEQ_COEFF_SHIFT = 24;
269193640Sariff	FEEDEQ_COEFF_ONE   = shl(1, FEEDEQ_COEFF_SHIFT);
270193640Sariff
271193640Sariff	FEEDEQ_PREAMP_SHIFT = 31;
272193640Sariff	FEEDEQ_PREAMP_ONE   = shl(1, FEEDEQ_PREAMP_SHIFT);
273193640Sariff	FEEDEQ_PREAMP_BITDB = 6; # 20.0 * (log(2.0) / log(10.0));
274193640Sariff
275193640Sariff	FEEDEQ_GAIN_DIV   = 10;
276193640Sariff	i = 0;
277193640Sariff	j = 1;
278193640Sariff	while (j < FEEDEQ_GAIN_DIV) {
279193640Sariff		j *= 2;
280193640Sariff		i++;
281193640Sariff	}
282193640Sariff	FEEDEQ_GAIN_SHIFT = i;
283193640Sariff	FEEDEQ_GAIN_FMASK = shl(1, FEEDEQ_GAIN_SHIFT) - 1;
284193640Sariff
285193640Sariff	FEEDEQ_GAIN_RECIPROCAL = 1.0 / FEEDEQ_GAIN_DIV;
286193640Sariff
287193640Sariff	if (ARGC == 2) {
288193640Sariff		i = 1;
289193640Sariff		split(ARGV[1], arg, ":");
290193640Sariff		while (match(arg[i], "^[^0-9]*$")) {
291193640Sariff			if (arg[i] == "PEQ") {
292193640Sariff				FEEDEQ_TYPE = FEEDEQ_TYPE_PEQ;
293193640Sariff			} else if (arg[i] == "SHELF") {
294193640Sariff				FEEDEQ_TYPE = FEEDEQ_TYPE_SHELF;
295193640Sariff			}
296193640Sariff			i++;
297193640Sariff		}
298193640Sariff		split(arg[i++], subarg, ",");
299193640Sariff		FEEDEQ_TREBLE_SFREQ = 1.0 * subarg[1];
300193640Sariff		FEEDEQ_TREBLE_SLOPE = 1.0 * subarg[2];
301193640Sariff		split(arg[i++], subarg, ",");
302193640Sariff		FEEDEQ_BASS_SFREQ = 1.0 * subarg[1];
303193640Sariff		FEEDEQ_BASS_SLOPE = 1.0 * subarg[2];
304193640Sariff		split(arg[i++], subarg, ",");
305193640Sariff		FEEDEQ_GAIN_MIN = floor(1.0 * subarg[1]);
306193640Sariff		FEEDEQ_GAIN_MAX = floor(1.0 * subarg[2]);
307193640Sariff		if (length(subarg) > 2) {
308193640Sariff			j = floor(1.0 * FEEDEQ_GAIN_DIV * subarg[3]);
309193640Sariff			if (j < 2)
310193640Sariff				j = 1;
311193640Sariff			else if (j < 5)
312193640Sariff				j = 2;
313193640Sariff			else if (j < 10)
314193640Sariff				j = 5;
315193640Sariff			else
316193640Sariff				j = 10;
317193640Sariff			if (j > FEEDEQ_GAIN_DIV || (FEEDEQ_GAIN_DIV % j) != 0)
318193640Sariff				j = FEEDEQ_GAIN_DIV;
319193640Sariff			FEEDEQ_GAIN_STEP = j;
320193640Sariff		} else
321193640Sariff			FEEDEQ_GAIN_STEP = FEEDEQ_GAIN_DIV;
322193640Sariff		split(arg[i], subarg, ",");
323193640Sariff		for (i = 1; i <= length(subarg); i++)
324193640Sariff			allfreq[i - 1] = floor(1.0 * subarg[i]);
325193640Sariff	} else {
326193640Sariff		FEEDEQ_TREBLE_SFREQ  = 16000.0;
327193640Sariff		FEEDEQ_TREBLE_SLOPE  = 0.25;
328193640Sariff		FEEDEQ_BASS_SFREQ    = 62.0;
329193640Sariff		FEEDEQ_BASS_SLOPE    = 0.25;
330193640Sariff
331193640Sariff		FEEDEQ_GAIN_MIN  = -9;
332193640Sariff		FEEDEQ_GAIN_MAX  = 9;
333193640Sariff
334193640Sariff		FEEDEQ_GAIN_STEP = FEEDEQ_GAIN_DIV;
335193640Sariff
336193640Sariff
337193640Sariff		allfreq[0] = 44100;
338193640Sariff		allfreq[1] = 48000;
339193640Sariff		allfreq[2] = 88200;
340193640Sariff		allfreq[3] = 96000;
341193640Sariff		allfreq[4] = 176400;
342193640Sariff		allfreq[5] = 192000;
343193640Sariff	}
344193640Sariff
345193640Sariff	FEEDEQ_LEVELS = ((FEEDEQ_GAIN_MAX - FEEDEQ_GAIN_MIN) *		\
346193640Sariff	    floor(FEEDEQ_GAIN_DIV / FEEDEQ_GAIN_STEP)) + 1;
347193640Sariff
348193640Sariff	FEEDEQ_ERR_CLIP = 0;
349193640Sariff
350193640Sariff	smallest = 10.000000;
351193640Sariff	largest  =  0.000010;
352193640Sariff
353193640Sariff	printf("#ifndef _FEEDER_EQ_GEN_H_\n");
354193640Sariff	printf("#define _FEEDER_EQ_GEN_H_\n\n");
355193640Sariff	printf("/*\n");
356193640Sariff	printf(" * Generated using feeder_eq_mkfilter.awk, heaven, wind and awesome.\n");
357193640Sariff	printf(" *\n");
358193640Sariff	printf(" * DO NOT EDIT!\n");
359193640Sariff	printf(" */\n\n");
360193640Sariff	printf("/*\n");
361193640Sariff	printf(" * EQ: %s\n", (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) ?	\
362193640Sariff	    "Shelving" : "Peaking EQ");
363193640Sariff	printf(" */\n");
364193640Sariff	printf("#define FEEDER_EQ_PRESETS\t\"");
365193640Sariff	printf("%s:%d,%.4f,%d,%.4f:%d,%d,%.1f:",			\
366193640Sariff	    (FEEDEQ_TYPE == FEEDEQ_TYPE_SHELF) ? "SHELF" : "PEQ",	\
367193640Sariff	    FEEDEQ_TREBLE_SFREQ, FEEDEQ_TREBLE_SLOPE,			\
368193640Sariff	    FEEDEQ_BASS_SFREQ, FEEDEQ_BASS_SLOPE,			\
369193640Sariff	    FEEDEQ_GAIN_MIN, FEEDEQ_GAIN_MAX,				\
370193640Sariff	    FEEDEQ_GAIN_STEP * FEEDEQ_GAIN_RECIPROCAL);
371193640Sariff	for (i = 0; i < length(allfreq); i++) {
372193640Sariff		if (i != 0)
373193640Sariff			printf(",");
374193640Sariff		printf("%d", allfreq[i]);
375193640Sariff	}
376193640Sariff	printf("\"\n\n");
377193640Sariff	printf("struct feed_eq_coeff_tone {\n");
378193640Sariff	printf("\tint32_t a1, a2;\n");
379193640Sariff	printf("\tint32_t b0, b1, b2;\n");
380193640Sariff	printf("};\n\n");
381193640Sariff	printf("struct feed_eq_coeff {\n");
382193640Sariff	#printf("\tstruct {\n");
383193640Sariff	#printf("\t\tint32_t a1, a2;\n");
384193640Sariff	#printf("\t\tint32_t b0, b1, b2;\n");
385193640Sariff	#printf("\t} treble, bass;\n");
386193640Sariff	printf("\tstruct feed_eq_coeff_tone treble;\n");
387193640Sariff	printf("\tstruct feed_eq_coeff_tone bass;\n");
388193640Sariff	#printf("\tstruct {\n");
389193640Sariff	#printf("\t\tint32_t a1, a2;\n");
390193640Sariff	#printf("\t\tint32_t b0, b1, b2;\n");
391193640Sariff	#printf("\t} bass;\n");
392193640Sariff	printf("};\n");
393193640Sariff	for (i = 0; i < length(allfreq); i++)
394193640Sariff		feedeq_gen_freq_coeffs(allfreq[i]);
395193640Sariff	printf("\n");
396193640Sariff	printf("static const struct {\n");
397193640Sariff	printf("\tuint32_t rate;\n");
398193640Sariff	printf("\tstruct feed_eq_coeff *coeff;\n");
399193640Sariff	printf("} feed_eq_tab[] = {\n");
400193640Sariff	for (i = 0; i < length(allfreq); i++) {
401193640Sariff		printf("\t{ %6d, eq_%-6d },\n", allfreq[i], allfreq[i]);
402193640Sariff	}
403193640Sariff	printf("};\n");
404193640Sariff
405193640Sariff	printf("\n#define FEEDEQ_RATE_MIN\t\t%d\n", allfreq[0]);
406193640Sariff	printf("#define FEEDEQ_RATE_MAX\t\t%d\n", allfreq[length(allfreq) - 1]);
407193640Sariff	printf("\n#define FEEDEQ_TAB_SIZE\t\t\t\t\t\t\t\\\n");
408193640Sariff	printf("\t((int32_t)(sizeof(feed_eq_tab) / sizeof(feed_eq_tab[0])))\n");
409193640Sariff
410193640Sariff	printf("\nstatic const struct {\n");
411193640Sariff	printf("\tint32_t mul, shift;\n");
412193640Sariff	printf("} feed_eq_preamp[] = {\n");
413193640Sariff	for (i = (FEEDEQ_GAIN_MAX * 2 * FEEDEQ_GAIN_DIV); i >= 0;	\
414193640Sariff	    i -= FEEDEQ_GAIN_STEP) {
415193640Sariff		feedeq_calc_preamp(norm, i * FEEDEQ_GAIN_RECIPROCAL);
416193640Sariff		dbgain = ((FEEDEQ_GAIN_MAX * FEEDEQ_GAIN_DIV) - i) *	\
417193640Sariff		    FEEDEQ_GAIN_RECIPROCAL;
418193640Sariff		printf("\t{ 0x%08x, 0x%08x },\t/* %+5.1f dB */\n",	\
419193640Sariff		    norm["mul"], norm["shift"], dbgain);
420193640Sariff	}
421193640Sariff	printf("};\n");
422193640Sariff
423193640Sariff	printf("\n#define FEEDEQ_GAIN_MIN\t\t%d", FEEDEQ_GAIN_MIN);
424193640Sariff	printf("\n#define FEEDEQ_GAIN_MAX\t\t%d\n", FEEDEQ_GAIN_MAX);
425193640Sariff
426193640Sariff	printf("\n#define FEEDEQ_GAIN_SHIFT\t%d\n", FEEDEQ_GAIN_SHIFT);
427193640Sariff	printf("#define FEEDEQ_GAIN_DIV\t\t%d\n", FEEDEQ_GAIN_DIV);
428193640Sariff	printf("#define FEEDEQ_GAIN_FMASK\t0x%08x\n", FEEDEQ_GAIN_FMASK);
429193640Sariff	printf("#define FEEDEQ_GAIN_STEP\t%d\n", FEEDEQ_GAIN_STEP);
430193640Sariff
431193640Sariff	#printf("\n#define FEEDEQ_PREAMP_MIN\t-%d\n",			\
432193640Sariff	#    shl(FEEDEQ_GAIN_MAX, FEEDEQ_GAIN_SHIFT));
433193640Sariff	#printf("#define FEEDEQ_PREAMP_MAX\t%d\n",			\
434193640Sariff	#    shl(FEEDEQ_GAIN_MAX, FEEDEQ_GAIN_SHIFT));
435193640Sariff
436193640Sariff	printf("\n#define FEEDEQ_COEFF_SHIFT\t%d\n", FEEDEQ_COEFF_SHIFT);
437193640Sariff
438193640Sariff	#feedeq_calc_preamp(norm, FEEDEQ_GAIN_MAX);
439193640Sariff
440193640Sariff	#printf("#define FEEDEQ_COEFF_NORM(v)\t(");
441193640Sariff	#if (norm["mul"] == 1)
442193640Sariff	#	printf("(v) >> %d", norm["shift"]);
443193640Sariff	#else
444193640Sariff	#	printf("(0x%xLL * (v)) >> %d", norm["mul"], norm["shift"]);
445193640Sariff	#printf(")\n");
446193640Sariff
447193640Sariff	#printf("\n#define FEEDEQ_LEVELS\t\t%d\n", FEEDEQ_LEVELS);
448193640Sariff	if (FEEDEQ_ERR_CLIP != 0)
449193640Sariff		printf("\n#define FEEDEQ_ERR_CLIP\t\t%d\n", FEEDEQ_ERR_CLIP);
450193640Sariff	printf("\n/*\n");
451193640Sariff	printf(" * volume level mapping (0 - 100):\n");
452193640Sariff	printf(" *\n");
453193640Sariff
454193640Sariff	for (i = 0; i <= 100; i++) {
455193640Sariff		ind = floor((i * FEEDEQ_LEVELS) / 100);
456193640Sariff		if (ind >= FEEDEQ_LEVELS)
457193640Sariff			ind = FEEDEQ_LEVELS - 1;
458193640Sariff		printf(" *\t%3d  ->  %3d (%+5.1f dB)\n",		\
459193640Sariff		    i, ind, FEEDEQ_GAIN_MIN +				\
460193640Sariff		    (ind * (FEEDEQ_GAIN_RECIPROCAL * FEEDEQ_GAIN_STEP)));
461193640Sariff	}
462193640Sariff
463193640Sariff	printf(" */\n");
464193640Sariff	printf("\n/*\n * smallest: %.32f\n *  largest: %.32f\n */\n",	\
465193640Sariff	    smallest, largest);
466193640Sariff	printf("\n#endif\t/* !_FEEDER_EQ_GEN_H_ */\n");
467193640Sariff}
468