comparison audacious/iir_fpu.c @ 430:67cd014f35a2 trunk

[svn] This commit rips out the old equalization engine with a dynamic engine that can be extended all the way up to 128 bands.
author nenolod
date Sat, 14 Jan 2006 16:49:00 -0800
parents
children e01a4c8f616f
comparison
equal deleted inserted replaced
429:e9569b4111b4 430:67cd014f35a2
1 /*
2 * PCM time-domain equalizer
3 *
4 * Copyright (C) 2002-2005 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_fpu.c,v 1.3 2005/11/13 20:02:58 lisanet Exp $
21 */
22
23 #include <glib.h>
24 #include "iir.h"
25 #include "iir_fpu.h"
26
27 static sXYData data_history[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
28 static sXYData data_history2[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
29 float gain[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned));
30 /* random noise */
31 sample_t dither[256];
32 gint di;
33
34 void set_gain(gint index, gint chn, float val)
35 {
36 gain[index][chn] = val;
37 }
38
39 void clean_history()
40 {
41 gint n;
42 /* Zero the history arrays */
43 bzero(data_history, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
44 bzero(data_history2, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS);
45 /* this is only needed if we use fpu code and there's no other place for
46 the moment to init the dither array*/
47 for (n = 0; n < 256; n++) {
48 dither[n] = (rand() % 4) - 2;
49 }
50 di = 0;
51 }
52
53 __inline__ int iir(gpointer * d, gint length, gint nch)
54 {
55 // FTZ_ON;
56 gint16 *data = (gint16 *) * d;
57 /* Indexes for the history arrays
58 * These have to be kept between calls to this function
59 * hence they are static */
60 static gint i = 2, j = 1, k = 0;
61
62 gint index, band, channel;
63 gint tempgint, halflength;
64 sample_t out[EQ_CHANNELS], pcm[EQ_CHANNELS];
65
66 #if 0
67 // Load the correct filter table according to the sampling rate if needed
68 if (srate != rate)
69 {
70 band_count = eqcfg.band_num;
71 rate = srate;
72 iir_cf = get_coeffs(&band_count, rate, eqcfg.use_xmms_original_freqs);
73 clean_history();
74 }
75 #endif
76
77 #ifdef BENCHMARK
78 start_counter();
79 #endif //BENCHMARK
80
81 /**
82 * IIR filter equation is
83 * y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2])
84 *
85 * NOTE: The 2 factor was introduced in the coefficients to save
86 * a multiplication
87 *
88 * This algorithm cascades two filters to get nice filtering
89 * at the expense of extra CPU cycles
90 */
91 /* 16bit, 2 bytes per sample, so divide by two the length of
92 * the buffer (length is in bytes)
93 */
94 halflength = (length >> 1);
95 for (index = 0; index < halflength; index+=nch)
96 {
97 /* For each channel */
98 for (channel = 0; channel < nch; channel++)
99 {
100 pcm[channel] = data[index+channel];
101 /* Preamp gain */
102 pcm[channel] *= preamp[channel];
103
104 /* add random noise */
105 pcm[channel] += dither[di];
106
107 out[channel] = 0.;
108 /* For each band */
109 for (band = 0; band < band_count; band++)
110 {
111 /* Store Xi(n) */
112 data_history[band][channel].x[i] = pcm[channel];
113 /* Calculate and store Yi(n) */
114 data_history[band][channel].y[i] =
115 (
116 /* = alpha * [x(n)-x(n-2)] */
117 iir_cf[band].alpha * ( data_history[band][channel].x[i]
118 - data_history[band][channel].x[k])
119 /* + gamma * y(n-1) */
120 + iir_cf[band].gamma * data_history[band][channel].y[j]
121 /* - beta * y(n-2) */
122 - iir_cf[band].beta * data_history[band][channel].y[k]
123 );
124 /*
125 * The multiplication by 2.0 was 'moved' into the coefficients to save
126 * CPU cycles here */
127 /* Apply the gain */
128 out[channel] += data_history[band][channel].y[i]*gain[band][channel]; // * 2.0;
129 } /* For each band */
130
131 if (cfg.eq_extra_filtering)
132 {
133 /* Filter the sample again */
134 for (band = 0; band < band_count; band++)
135 {
136 /* Store Xi(n) */
137 data_history2[band][channel].x[i] = out[channel];
138 /* Calculate and store Yi(n) */
139 data_history2[band][channel].y[i] =
140 (
141 /* y(n) = alpha * [x(n)-x(n-2)] */
142 iir_cf[band].alpha * (data_history2[band][channel].x[i]
143 - data_history2[band][channel].x[k])
144 /* + gamma * y(n-1) */
145 + iir_cf[band].gamma * data_history2[band][channel].y[j]
146 /* - beta * y(n-2) */
147 - iir_cf[band].beta * data_history2[band][channel].y[k]
148 );
149 /* Apply the gain */
150 out[channel] += data_history2[band][channel].y[i]*gain[band][channel];
151 } /* For each band */
152 }
153
154 /* Volume stuff
155 Scale down original PCM sample and add it to the filters
156 output. This substitutes the multiplication by 0.25
157 Go back to use the floating point multiplication before the
158 conversion to give more dynamic range
159 */
160 out[channel] += pcm[channel]*0.25;
161
162 /* remove random noise */
163 out[channel] -= dither[di]*0.25;
164
165 /* Round and convert to integer */
166 #ifdef ARCH_PPC
167 tempgint = round_ppc(out[channel]);
168 #else
169 #ifdef ARCH_X86
170 tempgint = round_trick(out[channel]);
171 #else
172 tempgint = (int)out[channel];
173 #endif
174 #endif
175
176 /* Limit the output */
177 if (tempgint < -32768)
178 data[index+channel] = -32768;
179 else if (tempgint > 32767)
180 data[index+channel] = 32767;
181 else
182 data[index+channel] = tempgint;
183 } /* For each channel */
184
185 /* Wrap around the indexes */
186 i = (i+1)%3;
187 j = (j+1)%3;
188 k = (k+1)%3;
189 /* random noise index */
190 di = (di + 1) % 256;
191
192 }/* For each pair of samples */
193
194 #ifdef BENCHMARK
195 timex += get_counter();
196 blength += length;
197 if (count++ == 1024)
198 {
199 printf("FLOATING POINT: %f %d\n",timex/1024.0, blength/1024);
200 blength = 0;
201 timex = 0.;
202 count = 0;
203 }
204 #endif // BENCHMARK
205
206 // FTZ_OFF;
207 return length;
208 }