|
1 //////////////////////////////////////////////////////////////////////////////// |
|
2 /// |
|
3 /// General FIR digital filter routines with MMX optimization. |
|
4 /// |
|
5 /// Note : MMX optimized functions reside in a separate, platform-specific file, |
|
6 /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' |
|
7 /// |
|
8 /// Author : Copyright (c) Olli Parviainen |
|
9 /// Author e-mail : oparviai 'at' iki.fi |
|
10 /// SoundTouch WWW: http://www.surina.net/soundtouch |
|
11 /// |
|
12 //////////////////////////////////////////////////////////////////////////////// |
|
13 // |
|
14 // Last changed : $Date: 2013-06-12 10:24:44 -0500 (Wed, 12 Jun 2013) $ |
|
15 // File revision : $Revision: 4 $ |
|
16 // |
|
17 // $Id: FIRFilter.cpp 171 2013-06-12 15:24:44Z oparviai $ |
|
18 // |
|
19 //////////////////////////////////////////////////////////////////////////////// |
|
20 // |
|
21 // License : |
|
22 // |
|
23 // SoundTouch audio processing library |
|
24 // Copyright (c) Olli Parviainen |
|
25 // |
|
26 // This library is free software; you can redistribute it and/or |
|
27 // modify it under the terms of the GNU Lesser General Public |
|
28 // License as published by the Free Software Foundation; either |
|
29 // version 2.1 of the License, or (at your option) any later version. |
|
30 // |
|
31 // This library is distributed in the hope that it will be useful, |
|
32 // but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
33 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
34 // Lesser General Public License for more details. |
|
35 // |
|
36 // You should have received a copy of the GNU Lesser General Public |
|
37 // License along with this library; if not, write to the Free Software |
|
38 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
39 // |
|
40 //////////////////////////////////////////////////////////////////////////////// |
|
41 |
|
42 #include <memory.h> |
|
43 #include <assert.h> |
|
44 #include <math.h> |
|
45 #include <stdlib.h> |
|
46 #include "FIRFilter.h" |
|
47 #include "cpu_detect.h" |
|
48 |
|
49 #ifdef _MSC_VER |
|
50 #include <malloc.h> |
|
51 #define alloca _alloca |
|
52 #endif |
|
53 |
|
54 using namespace soundtouch; |
|
55 |
|
56 /***************************************************************************** |
|
57 * |
|
58 * Implementation of the class 'FIRFilter' |
|
59 * |
|
60 *****************************************************************************/ |
|
61 |
|
62 FIRFilter::FIRFilter() |
|
63 { |
|
64 resultDivFactor = 0; |
|
65 resultDivider = 0; |
|
66 length = 0; |
|
67 lengthDiv8 = 0; |
|
68 filterCoeffs = NULL; |
|
69 } |
|
70 |
|
71 |
|
72 FIRFilter::~FIRFilter() |
|
73 { |
|
74 delete[] filterCoeffs; |
|
75 } |
|
76 |
|
77 // Usual C-version of the filter routine for stereo sound |
|
78 uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const |
|
79 { |
|
80 uint i, j, end; |
|
81 LONG_SAMPLETYPE suml, sumr; |
|
82 #ifdef SOUNDTOUCH_FLOAT_SAMPLES |
|
83 // when using floating point samples, use a scaler instead of a divider |
|
84 // because division is much slower operation than multiplying. |
|
85 double dScaler = 1.0 / (double)resultDivider; |
|
86 #endif |
|
87 |
|
88 assert(length != 0); |
|
89 assert(src != NULL); |
|
90 assert(dest != NULL); |
|
91 assert(filterCoeffs != NULL); |
|
92 |
|
93 end = 2 * (numSamples - length); |
|
94 |
|
95 for (j = 0; j < end; j += 2) |
|
96 { |
|
97 const SAMPLETYPE *ptr; |
|
98 |
|
99 suml = sumr = 0; |
|
100 ptr = src + j; |
|
101 |
|
102 for (i = 0; i < length; i += 4) |
|
103 { |
|
104 // loop is unrolled by factor of 4 here for efficiency |
|
105 suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + |
|
106 ptr[2 * i + 2] * filterCoeffs[i + 1] + |
|
107 ptr[2 * i + 4] * filterCoeffs[i + 2] + |
|
108 ptr[2 * i + 6] * filterCoeffs[i + 3]; |
|
109 sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + |
|
110 ptr[2 * i + 3] * filterCoeffs[i + 1] + |
|
111 ptr[2 * i + 5] * filterCoeffs[i + 2] + |
|
112 ptr[2 * i + 7] * filterCoeffs[i + 3]; |
|
113 } |
|
114 |
|
115 #ifdef SOUNDTOUCH_INTEGER_SAMPLES |
|
116 suml >>= resultDivFactor; |
|
117 sumr >>= resultDivFactor; |
|
118 // saturate to 16 bit integer limits |
|
119 suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; |
|
120 // saturate to 16 bit integer limits |
|
121 sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; |
|
122 #else |
|
123 suml *= dScaler; |
|
124 sumr *= dScaler; |
|
125 #endif // SOUNDTOUCH_INTEGER_SAMPLES |
|
126 dest[j] = (SAMPLETYPE)suml; |
|
127 dest[j + 1] = (SAMPLETYPE)sumr; |
|
128 } |
|
129 return numSamples - length; |
|
130 } |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 // Usual C-version of the filter routine for mono sound |
|
136 uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const |
|
137 { |
|
138 uint i, j, end; |
|
139 LONG_SAMPLETYPE sum; |
|
140 #ifdef SOUNDTOUCH_FLOAT_SAMPLES |
|
141 // when using floating point samples, use a scaler instead of a divider |
|
142 // because division is much slower operation than multiplying. |
|
143 double dScaler = 1.0 / (double)resultDivider; |
|
144 #endif |
|
145 |
|
146 |
|
147 assert(length != 0); |
|
148 |
|
149 end = numSamples - length; |
|
150 for (j = 0; j < end; j ++) |
|
151 { |
|
152 sum = 0; |
|
153 for (i = 0; i < length; i += 4) |
|
154 { |
|
155 // loop is unrolled by factor of 4 here for efficiency |
|
156 sum += src[i + 0] * filterCoeffs[i + 0] + |
|
157 src[i + 1] * filterCoeffs[i + 1] + |
|
158 src[i + 2] * filterCoeffs[i + 2] + |
|
159 src[i + 3] * filterCoeffs[i + 3]; |
|
160 } |
|
161 #ifdef SOUNDTOUCH_INTEGER_SAMPLES |
|
162 sum >>= resultDivFactor; |
|
163 // saturate to 16 bit integer limits |
|
164 sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; |
|
165 #else |
|
166 sum *= dScaler; |
|
167 #endif // SOUNDTOUCH_INTEGER_SAMPLES |
|
168 dest[j] = (SAMPLETYPE)sum; |
|
169 src ++; |
|
170 } |
|
171 return end; |
|
172 } |
|
173 |
|
174 |
|
175 uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const |
|
176 { |
|
177 uint i, j, end, c; |
|
178 LONG_SAMPLETYPE *sum=(LONG_SAMPLETYPE*)alloca(numChannels*sizeof(*sum)); |
|
179 #ifdef SOUNDTOUCH_FLOAT_SAMPLES |
|
180 // when using floating point samples, use a scaler instead of a divider |
|
181 // because division is much slower operation than multiplying. |
|
182 double dScaler = 1.0 / (double)resultDivider; |
|
183 #endif |
|
184 |
|
185 assert(length != 0); |
|
186 assert(src != NULL); |
|
187 assert(dest != NULL); |
|
188 assert(filterCoeffs != NULL); |
|
189 |
|
190 end = numChannels * (numSamples - length); |
|
191 |
|
192 for (c = 0; c < numChannels; c ++) |
|
193 { |
|
194 sum[c] = 0; |
|
195 } |
|
196 |
|
197 for (j = 0; j < end; j += numChannels) |
|
198 { |
|
199 const SAMPLETYPE *ptr; |
|
200 |
|
201 ptr = src + j; |
|
202 |
|
203 for (i = 0; i < length; i ++) |
|
204 { |
|
205 SAMPLETYPE coef=filterCoeffs[i]; |
|
206 for (c = 0; c < numChannels; c ++) |
|
207 { |
|
208 sum[c] += ptr[0] * coef; |
|
209 ptr ++; |
|
210 } |
|
211 } |
|
212 |
|
213 for (c = 0; c < numChannels; c ++) |
|
214 { |
|
215 #ifdef SOUNDTOUCH_INTEGER_SAMPLES |
|
216 sum[c] >>= resultDivFactor; |
|
217 #else |
|
218 sum[c] *= dScaler; |
|
219 #endif // SOUNDTOUCH_INTEGER_SAMPLES |
|
220 *dest = (SAMPLETYPE)sum[c]; |
|
221 dest++; |
|
222 sum[c] = 0; |
|
223 } |
|
224 } |
|
225 return numSamples - length; |
|
226 } |
|
227 |
|
228 |
|
229 // Set filter coeffiecients and length. |
|
230 // |
|
231 // Throws an exception if filter length isn't divisible by 8 |
|
232 void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) |
|
233 { |
|
234 assert(newLength > 0); |
|
235 if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); |
|
236 |
|
237 lengthDiv8 = newLength / 8; |
|
238 length = lengthDiv8 * 8; |
|
239 assert(length == newLength); |
|
240 |
|
241 resultDivFactor = uResultDivFactor; |
|
242 resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); |
|
243 |
|
244 delete[] filterCoeffs; |
|
245 filterCoeffs = new SAMPLETYPE[length]; |
|
246 memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE)); |
|
247 } |
|
248 |
|
249 |
|
250 uint FIRFilter::getLength() const |
|
251 { |
|
252 return length; |
|
253 } |
|
254 |
|
255 |
|
256 |
|
257 // Applies the filter to the given sequence of samples. |
|
258 // |
|
259 // Note : The amount of outputted samples is by value of 'filter_length' |
|
260 // smaller than the amount of input samples. |
|
261 uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const |
|
262 { |
|
263 assert(length > 0); |
|
264 assert(lengthDiv8 * 8 == length); |
|
265 |
|
266 if (numSamples < length) return 0; |
|
267 |
|
268 #ifndef USE_MULTICH_ALWAYS |
|
269 if (numChannels == 1) |
|
270 { |
|
271 return evaluateFilterMono(dest, src, numSamples); |
|
272 } |
|
273 else if (numChannels == 2) |
|
274 { |
|
275 return evaluateFilterStereo(dest, src, numSamples); |
|
276 } |
|
277 else |
|
278 #endif // USE_MULTICH_ALWAYS |
|
279 { |
|
280 assert(numChannels > 0); |
|
281 return evaluateFilterMulti(dest, src, numSamples, numChannels); |
|
282 } |
|
283 } |
|
284 |
|
285 |
|
286 |
|
287 // Operator 'new' is overloaded so that it automatically creates a suitable instance |
|
288 // depending on if we've a MMX-capable CPU available or not. |
|
289 void * FIRFilter::operator new(size_t s) |
|
290 { |
|
291 // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! |
|
292 ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); |
|
293 return newInstance(); |
|
294 } |
|
295 |
|
296 |
|
297 FIRFilter * FIRFilter::newInstance() |
|
298 { |
|
299 #if defined(SOUNDTOUCH_ALLOW_MMX) || defined(SOUNDTOUCH_ALLOW_SSE) |
|
300 uint uExtensions; |
|
301 |
|
302 uExtensions = detectCPUextensions(); |
|
303 #endif |
|
304 |
|
305 // Check if MMX/SSE instruction set extensions supported by CPU |
|
306 |
|
307 #ifdef SOUNDTOUCH_ALLOW_MMX |
|
308 // MMX routines available only with integer sample types |
|
309 if (uExtensions & SUPPORT_MMX) |
|
310 { |
|
311 return ::new FIRFilterMMX; |
|
312 } |
|
313 else |
|
314 #endif // SOUNDTOUCH_ALLOW_MMX |
|
315 |
|
316 #ifdef SOUNDTOUCH_ALLOW_SSE |
|
317 if (uExtensions & SUPPORT_SSE) |
|
318 { |
|
319 // SSE support |
|
320 return ::new FIRFilterSSE; |
|
321 } |
|
322 else |
|
323 #endif // SOUNDTOUCH_ALLOW_SSE |
|
324 |
|
325 { |
|
326 // ISA optimizations not supported, use plain C version |
|
327 return ::new FIRFilter; |
|
328 } |
|
329 } |