media/libsoundtouch/src/FIRFilter.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:0b05f88ef0ef
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 }

mercurial