0
|
1 /*
|
|
2 * PCM time-domain equalizer
|
|
3 *
|
|
4 * Copyright (C) 2002 Felipe Rivera <liebremx at users sourceforge net>
|
|
5 *
|
|
6 * This program is free software; you can redistribute it and/or modify
|
|
7 * it under the terms of the GNU General Public License as published by
|
|
8 * the Free Software Foundation; either version 2 of the License, or
|
|
9 * (at your option) any later version.
|
|
10 *
|
|
11 * This program is distributed in the hope that it will be useful,
|
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 * GNU General Public License for more details.
|
|
15 *
|
|
16 * You should have received a copy of the GNU General Public License
|
|
17 * along with this program; if not, write to the Free Software
|
|
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
19 *
|
|
20 * $Id: iir.c,v 1.5 2004/06/20 18:48:54 mderezynski Exp $
|
|
21 */
|
|
22
|
|
23 #include "equalizer.h"
|
|
24 #include "main.h"
|
|
25 #include <math.h>
|
|
26 #include <string.h>
|
|
27 #include "output.h"
|
|
28
|
|
29 #include "iir.h"
|
|
30
|
|
31 // Fixed Point Fractional bits
|
|
32 #define FP_FRBITS 28
|
|
33
|
|
34 // Conversions
|
|
35 #define EQ_REAL(x) ((gint)((x) * (1 << FP_FRBITS)))
|
|
36
|
|
37 /* Floating point */
|
|
38 typedef struct {
|
|
39 float beta;
|
|
40 float alpha;
|
|
41 float gamma;
|
|
42 } sIIRCoefficients;
|
|
43
|
|
44 /* Coefficient history for the IIR filter */
|
|
45 typedef struct {
|
|
46 float x[3]; /* x[n], x[n-1], x[n-2] */
|
|
47 float y[3]; /* y[n], y[n-1], y[n-2] */
|
|
48 } sXYData;
|
|
49
|
|
50 /* BETA, ALPHA, GAMMA */
|
|
51 static sIIRCoefficients iir_cforiginal10[] = {
|
|
52 {(9.9421504945e-01), (2.8924752745e-03), (1.9941421835e+00)}, /* 60.0 Hz */
|
|
53 {(9.8335039428e-01), (8.3248028618e-03), (1.9827686547e+00)}, /* 170.0 Hz */
|
|
54 {(9.6958094144e-01), (1.5209529281e-02), (1.9676601546e+00)}, /* 310.0 Hz */
|
|
55 {(9.4163923306e-01), (2.9180383468e-02), (1.9345490229e+00)}, /* 600.0 Hz */
|
|
56 {(9.0450844499e-01), (4.7745777504e-02), (1.8852109613e+00)}, /* 1000.0 Hz */
|
|
57 {(7.3940088234e-01), (1.3029955883e-01), (1.5829158753e+00)}, /* 3000.0 Hz */
|
|
58 {(5.4697667908e-01), (2.2651166046e-01), (1.0153238114e+00)}, /* 6000.0 Hz */
|
|
59 {(3.1023210589e-01), (3.4488394706e-01), (-1.8142472036e-01)}, /* 12000.0 Hz */
|
|
60 {(2.6718639778e-01), (3.6640680111e-01), (-5.2117742267e-01)}, /* 14000.0 Hz */
|
|
61 {(2.4201241845e-01), (3.7899379077e-01), (-8.0847117831e-01)}, /* 16000.0 Hz */
|
|
62 };
|
|
63
|
|
64 /* History for two filters */
|
|
65 static sXYData data_history[EQ_MAX_BANDS][EQ_CHANNELS];
|
|
66 static sXYData data_history2[EQ_MAX_BANDS][EQ_CHANNELS];
|
|
67
|
|
68 /* Coefficients */
|
|
69 static sIIRCoefficients *iir_cf;
|
|
70
|
|
71 /* Gain for each band
|
|
72 * values should be between -0.2 and 1.0 */
|
|
73 float gain[10];
|
|
74 float preamp;
|
|
75
|
|
76 int round_trick(float floatvalue_to_round);
|
|
77
|
|
78 /* Init the filter */
|
|
79 void
|
|
80 init_iir()
|
|
81 {
|
|
82 iir_cf = iir_cforiginal10;
|
|
83
|
|
84 /* Zero the history arrays */
|
|
85 memset(data_history, 0, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
|
|
86 memset(data_history2, 0, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
|
|
87
|
|
88 output_set_eq(cfg.equalizer_active, cfg.equalizer_preamp,
|
|
89 cfg.equalizer_bands);
|
|
90 }
|
|
91
|
|
92 int
|
|
93 iir(gpointer * d, gint length)
|
|
94 {
|
|
95 gint16 *data = (gint16 *) * d;
|
|
96 /* Indexes for the history arrays
|
|
97 * These have to be kept between calls to this function
|
|
98 * hence they are static */
|
|
99 static gint i = 0, j = 2, k = 1;
|
|
100
|
|
101 gint index, band, channel;
|
|
102 gint tempgint, halflength;
|
|
103 float out[EQ_CHANNELS], pcm[EQ_CHANNELS];
|
|
104
|
|
105 /**
|
|
106 * IIR filter equation is
|
|
107 * y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2])
|
|
108 *
|
|
109 * NOTE: The 2 factor was introduced in the coefficients to save
|
|
110 * a multiplication
|
|
111 *
|
|
112 * This algorithm cascades two filters to get nice filtering
|
|
113 * at the expense of extra CPU cycles
|
|
114 */
|
|
115 /* 16bit, 2 bytes per sample, so divide by two the length of
|
|
116 * the buffer (length is in bytes)
|
|
117 */
|
|
118 halflength = (length >> 1);
|
|
119 for (index = 0; index < halflength; index += 2) {
|
|
120 /* For each channel */
|
|
121 for (channel = 0; channel < EQ_CHANNELS; channel++) {
|
|
122 /* No need to scale when processing the PCM with the filter */
|
|
123 pcm[channel] = data[index + channel];
|
|
124 /* Preamp gain */
|
|
125 pcm[channel] *= preamp;
|
|
126
|
|
127 out[channel] = 0;
|
|
128 /* For each band */
|
|
129 for (band = 0; band < 10; band++) {
|
|
130 /* Store Xi(n) */
|
|
131 data_history[band][channel].x[i] = pcm[channel];
|
|
132 /* Calculate and store Yi(n) */
|
|
133 data_history[band][channel].y[i] =
|
|
134 (iir_cf[band].alpha * (data_history[band][channel].x[i]
|
|
135 - data_history[band][channel].x[k])
|
|
136 + iir_cf[band].gamma * data_history[band][channel].y[j]
|
|
137 - iir_cf[band].beta * data_history[band][channel].y[k]
|
|
138 );
|
|
139 /*
|
|
140 * The multiplication by 2.0 was 'moved' into the coefficients to save
|
|
141 * CPU cycles here */
|
|
142 /* Apply the gain */
|
|
143 out[channel] += data_history[band][channel].y[i] * gain[band]; // * 2.0;
|
|
144 } /* For each band */
|
|
145
|
|
146 if (cfg.eq_extra_filtering) {
|
|
147 /* Filter the sample again */
|
|
148 for (band = 0; band < 10; band++) {
|
|
149 /* Store Xi(n) */
|
|
150 data_history2[band][channel].x[i] = out[channel];
|
|
151 /* Calculate and store Yi(n) */
|
|
152 data_history2[band][channel].y[i] =
|
|
153 (iir_cf[band].alpha *
|
|
154 (data_history2[band][channel].x[i]
|
|
155 - data_history2[band][channel].x[k])
|
|
156 +
|
|
157 iir_cf[band].gamma *
|
|
158 data_history2[band][channel].y[j]
|
|
159 -
|
|
160 iir_cf[band].beta * data_history2[band][channel].y[k]
|
|
161 );
|
|
162 /* Apply the gain */
|
|
163 out[channel] +=
|
|
164 data_history2[band][channel].y[i] * gain[band];
|
|
165 } /* For each band */
|
|
166 }
|
|
167
|
|
168 /* Volume stuff
|
|
169 Scale down original PCM sample and add it to the filters
|
|
170 output. This substitutes the multiplication by 0.25
|
|
171 */
|
|
172
|
|
173 out[channel] += (data[index + channel] >> 2);
|
|
174
|
|
175 //printf("out[channel] = %f\n", out[channel]);
|
|
176 /* Round and convert to integer */
|
|
177 #if 0
|
|
178 #ifdef PPC
|
|
179 tempgint = round_ppc(out[channel]);
|
|
180 #else
|
|
181 # ifdef X86
|
|
182 tempgint = round_trick(out[channel]);
|
|
183 # else
|
|
184 tempgint = (int) lroundf(out[channel]);
|
|
185 # endif
|
|
186 #endif
|
|
187 #endif
|
|
188 //tempgint = (int) lroundf(out[channel]);
|
|
189 tempgint = (int) out[channel];
|
|
190
|
|
191 //printf("iir: old=%d new=%d\n", data[index+channel], tempgint);
|
|
192 /* Limit the output */
|
|
193 if (tempgint < -32768)
|
|
194 data[index + channel] = -32768;
|
|
195 else if (tempgint > 32767)
|
|
196 data[index + channel] = 32767;
|
|
197 else
|
|
198 data[index + channel] = tempgint;
|
|
199 } /* For each channel */
|
|
200
|
|
201 i++;
|
|
202 j++;
|
|
203 k++;
|
|
204
|
|
205 /* Wrap around the indexes */
|
|
206 if (i == 3)
|
|
207 i = 0;
|
|
208 else if (j == 3)
|
|
209 j = 0;
|
|
210 else
|
|
211 k = 0;
|
|
212
|
|
213
|
|
214 } /* For each pair of samples */
|
|
215
|
|
216 return length;
|
|
217 }
|