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: 2009-02-25 19:13:51 +0200 (Wed, 25 Feb 2009) $ |
15 |
// File revision : $Revision: 4 $ |
16 |
// |
17 |
// $Id: FIRFilter.cpp 67 2009-02-25 17:13:51Z 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 <stdexcept> |
47 |
#include "FIRFilter.h" |
48 |
#include "cpu_detect.h" |
49 |
|
50 |
using namespace soundtouch; |
51 |
|
52 |
/***************************************************************************** |
53 |
* |
54 |
* Implementation of the class 'FIRFilter' |
55 |
* |
56 |
*****************************************************************************/ |
57 |
|
58 |
FIRFilter::FIRFilter() |
59 |
{ |
60 |
resultDivFactor = 0; |
61 |
resultDivider = 0; |
62 |
length = 0; |
63 |
lengthDiv8 = 0; |
64 |
filterCoeffs = NULL; |
65 |
} |
66 |
|
67 |
|
68 |
FIRFilter::~FIRFilter() |
69 |
{ |
70 |
delete[] filterCoeffs; |
71 |
} |
72 |
|
73 |
// Usual C-version of the filter routine for stereo sound |
74 |
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const |
75 |
{ |
76 |
uint i, j, end; |
77 |
LONG_SAMPLETYPE suml, sumr; |
78 |
#ifdef FLOAT_SAMPLES |
79 |
// when using floating point samples, use a scaler instead of a divider |
80 |
// because division is much slower operation than multiplying. |
81 |
double dScaler = 1.0 / (double)resultDivider; |
82 |
#endif |
83 |
|
84 |
assert(length != 0); |
85 |
assert(src != NULL); |
86 |
assert(dest != NULL); |
87 |
assert(filterCoeffs != NULL); |
88 |
|
89 |
end = 2 * (numSamples - length); |
90 |
|
91 |
for (j = 0; j < end; j += 2) |
92 |
{ |
93 |
const SAMPLETYPE *ptr; |
94 |
|
95 |
suml = sumr = 0; |
96 |
ptr = src + j; |
97 |
|
98 |
for (i = 0; i < length; i += 4) |
99 |
{ |
100 |
// loop is unrolled by factor of 4 here for efficiency |
101 |
suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + |
102 |
ptr[2 * i + 2] * filterCoeffs[i + 1] + |
103 |
ptr[2 * i + 4] * filterCoeffs[i + 2] + |
104 |
ptr[2 * i + 6] * filterCoeffs[i + 3]; |
105 |
sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + |
106 |
ptr[2 * i + 3] * filterCoeffs[i + 1] + |
107 |
ptr[2 * i + 5] * filterCoeffs[i + 2] + |
108 |
ptr[2 * i + 7] * filterCoeffs[i + 3]; |
109 |
} |
110 |
|
111 |
#ifdef INTEGER_SAMPLES |
112 |
suml >>= resultDivFactor; |
113 |
sumr >>= resultDivFactor; |
114 |
// saturate to 16 bit integer limits |
115 |
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; |
116 |
// saturate to 16 bit integer limits |
117 |
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; |
118 |
#else |
119 |
suml *= dScaler; |
120 |
sumr *= dScaler; |
121 |
#endif // INTEGER_SAMPLES |
122 |
dest[j] = (SAMPLETYPE)suml; |
123 |
dest[j + 1] = (SAMPLETYPE)sumr; |
124 |
} |
125 |
return numSamples - length; |
126 |
} |
127 |
|
128 |
|
129 |
|
130 |
|
131 |
// Usual C-version of the filter routine for mono sound |
132 |
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const |
133 |
{ |
134 |
uint i, j, end; |
135 |
LONG_SAMPLETYPE sum; |
136 |
#ifdef FLOAT_SAMPLES |
137 |
// when using floating point samples, use a scaler instead of a divider |
138 |
// because division is much slower operation than multiplying. |
139 |
double dScaler = 1.0 / (double)resultDivider; |
140 |
#endif |
141 |
|
142 |
|
143 |
assert(length != 0); |
144 |
|
145 |
end = numSamples - length; |
146 |
for (j = 0; j < end; j ++) |
147 |
{ |
148 |
sum = 0; |
149 |
for (i = 0; i < length; i += 4) |
150 |
{ |
151 |
// loop is unrolled by factor of 4 here for efficiency |
152 |
sum += src[i + 0] * filterCoeffs[i + 0] + |
153 |
src[i + 1] * filterCoeffs[i + 1] + |
154 |
src[i + 2] * filterCoeffs[i + 2] + |
155 |
src[i + 3] * filterCoeffs[i + 3]; |
156 |
} |
157 |
#ifdef INTEGER_SAMPLES |
158 |
sum >>= resultDivFactor; |
159 |
// saturate to 16 bit integer limits |
160 |
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; |
161 |
#else |
162 |
sum *= dScaler; |
163 |
#endif // INTEGER_SAMPLES |
164 |
dest[j] = (SAMPLETYPE)sum; |
165 |
src ++; |
166 |
} |
167 |
return end; |
168 |
} |
169 |
|
170 |
|
171 |
// Set filter coeffiecients and length. |
172 |
// |
173 |
// Throws an exception if filter length isn't divisible by 8 |
174 |
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) |
175 |
{ |
176 |
assert(newLength > 0); |
177 |
if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); |
178 |
|
179 |
lengthDiv8 = newLength / 8; |
180 |
length = lengthDiv8 * 8; |
181 |
assert(length == newLength); |
182 |
|
183 |
resultDivFactor = uResultDivFactor; |
184 |
resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); |
185 |
|
186 |
delete[] filterCoeffs; |
187 |
filterCoeffs = new SAMPLETYPE[length]; |
188 |
memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE)); |
189 |
} |
190 |
|
191 |
|
192 |
uint FIRFilter::getLength() const |
193 |
{ |
194 |
return length; |
195 |
} |
196 |
|
197 |
|
198 |
|
199 |
// Applies the filter to the given sequence of samples. |
200 |
// |
201 |
// Note : The amount of outputted samples is by value of 'filter_length' |
202 |
// smaller than the amount of input samples. |
203 |
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const |
204 |
{ |
205 |
assert(numChannels == 1 || numChannels == 2); |
206 |
|
207 |
assert(length > 0); |
208 |
assert(lengthDiv8 * 8 == length); |
209 |
if (numSamples < length) return 0; |
210 |
if (numChannels == 2) |
211 |
{ |
212 |
return evaluateFilterStereo(dest, src, numSamples); |
213 |
} else { |
214 |
return evaluateFilterMono(dest, src, numSamples); |
215 |
} |
216 |
} |
217 |
|
218 |
|
219 |
|
220 |
// Operator 'new' is overloaded so that it automatically creates a suitable instance |
221 |
// depending on if we've a MMX-capable CPU available or not. |
222 |
void * FIRFilter::operator new(size_t s) |
223 |
{ |
224 |
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! |
225 |
throw std::runtime_error("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); |
226 |
return NULL; |
227 |
} |
228 |
|
229 |
|
230 |
FIRFilter * FIRFilter::newInstance() |
231 |
{ |
232 |
uint uExtensions; |
233 |
|
234 |
uExtensions = detectCPUextensions(); |
235 |
|
236 |
// Check if MMX/SSE/3DNow! instruction set extensions supported by CPU |
237 |
|
238 |
#ifdef ALLOW_MMX |
239 |
// MMX routines available only with integer sample types |
240 |
if (uExtensions & SUPPORT_MMX) |
241 |
{ |
242 |
return ::new FIRFilterMMX; |
243 |
} |
244 |
else |
245 |
#endif // ALLOW_MMX |
246 |
|
247 |
#ifdef ALLOW_SSE |
248 |
if (uExtensions & SUPPORT_SSE) |
249 |
{ |
250 |
// SSE support |
251 |
return ::new FIRFilterSSE; |
252 |
} |
253 |
else |
254 |
#endif // ALLOW_SSE |
255 |
|
256 |
#ifdef ALLOW_3DNOW |
257 |
if (uExtensions & SUPPORT_3DNOW) |
258 |
{ |
259 |
// 3DNow! support |
260 |
return ::new FIRFilter3DNow; |
261 |
} |
262 |
else |
263 |
#endif // ALLOW_3DNOW |
264 |
|
265 |
{ |
266 |
// ISA optimizations not supported, use plain C version |
267 |
return ::new FIRFilter; |
268 |
} |
269 |
} |