1 ////////////////////////////////////////////////////////////////////////////////
3 /// General FIR digital filter routines with MMX optimization.
5 /// Note : MMX optimized functions reside in a separate, platform-specific file,
6 /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
8 /// Author : Copyright (c) Olli Parviainen
9 /// Author e-mail : oparviai @ iki.fi
10 /// SoundTouch WWW: http://www.iki.fi/oparviai/soundtouch
12 ////////////////////////////////////////////////////////////////////////////////
14 // Last changed : $Date$
15 // File revision : $Revision$
19 ////////////////////////////////////////////////////////////////////////////////
23 // SoundTouch audio processing library
24 // Copyright (c) Olli Parviainen
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.
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.
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
40 ////////////////////////////////////////////////////////////////////////////////
47 #include "FIRFilter.h"
48 #include "cpu_detect.h"
50 using namespace soundtouch
;
52 /*****************************************************************************
54 * Implementation of the class 'FIRFilter'
56 *****************************************************************************/
58 FIRFilter::FIRFilter()
67 FIRFilter::~FIRFilter()
69 delete[] filterCoeffs
;
72 // Usual C-version of the filter routine for stereo sound
73 uint
FIRFilter::evaluateFilterStereo(SAMPLETYPE
*dest
, const SAMPLETYPE
*src
, uint numSamples
) const
76 LONG_SAMPLETYPE suml
, sumr
;
78 // when using floating point samples, use a scaler instead of a divider
79 // because division is much slower operation than multiplying.
80 double dScaler
= 1.0 / (double)resultDivider
;
85 end
= 2 * (numSamples
- length
);
87 for (j
= 0; j
< end
; j
+= 2)
89 const SAMPLETYPE
*ptr
;
94 for (i
= 0; i
< length
; i
+= 4)
96 // loop is unrolled by factor of 4 here for efficiency
97 suml
+= ptr
[2 * i
+ 0] * filterCoeffs
[i
+ 0] +
98 ptr
[2 * i
+ 2] * filterCoeffs
[i
+ 1] +
99 ptr
[2 * i
+ 4] * filterCoeffs
[i
+ 2] +
100 ptr
[2 * i
+ 6] * filterCoeffs
[i
+ 3];
101 sumr
+= ptr
[2 * i
+ 1] * filterCoeffs
[i
+ 0] +
102 ptr
[2 * i
+ 3] * filterCoeffs
[i
+ 1] +
103 ptr
[2 * i
+ 5] * filterCoeffs
[i
+ 2] +
104 ptr
[2 * i
+ 7] * filterCoeffs
[i
+ 3];
107 #ifdef INTEGER_SAMPLES
108 suml
>>= resultDivFactor
;
109 sumr
>>= resultDivFactor
;
110 // saturate to 16 bit integer limits
111 suml
= (suml
< -32768) ? -32768 : (suml
> 32767) ? 32767 : suml
;
112 // saturate to 16 bit integer limits
113 sumr
= (sumr
< -32768) ? -32768 : (sumr
> 32767) ? 32767 : sumr
;
117 #endif // INTEGER_SAMPLES
118 dest
[j
] = (SAMPLETYPE
)suml
;
119 dest
[j
+ 1] = (SAMPLETYPE
)sumr
;
121 return numSamples
- length
;
127 // Usual C-version of the filter routine for mono sound
128 uint
FIRFilter::evaluateFilterMono(SAMPLETYPE
*dest
, const SAMPLETYPE
*src
, uint numSamples
) const
133 // when using floating point samples, use a scaler instead of a divider
134 // because division is much slower operation than multiplying.
135 double dScaler
= 1.0 / (double)resultDivider
;
141 end
= numSamples
- length
;
142 for (j
= 0; j
< end
; j
++)
145 for (i
= 0; i
< length
; i
+= 4)
147 // loop is unrolled by factor of 4 here for efficiency
148 sum
+= src
[i
+ 0] * filterCoeffs
[i
+ 0] +
149 src
[i
+ 1] * filterCoeffs
[i
+ 1] +
150 src
[i
+ 2] * filterCoeffs
[i
+ 2] +
151 src
[i
+ 3] * filterCoeffs
[i
+ 3];
153 #ifdef INTEGER_SAMPLES
154 sum
>>= resultDivFactor
;
155 // saturate to 16 bit integer limits
156 sum
= (sum
< -32768) ? -32768 : (sum
> 32767) ? 32767 : sum
;
159 #endif // INTEGER_SAMPLES
160 dest
[j
] = (SAMPLETYPE
)sum
;
167 // Set filter coeffiecients and length.
169 // Throws an exception if filter length isn't divisible by 8
170 void FIRFilter::setCoefficients(const SAMPLETYPE
*coeffs
, uint newLength
, uint uResultDivFactor
)
172 assert(newLength
> 0);
173 if (newLength
% 8) throw std::runtime_error("FIR filter length not divisible by 8");
175 lengthDiv8
= newLength
/ 8;
176 length
= lengthDiv8
* 8;
177 assert(length
== newLength
);
179 resultDivFactor
= uResultDivFactor
;
180 resultDivider
= (uint
)pow(2, resultDivFactor
);
182 delete[] filterCoeffs
;
183 filterCoeffs
= new SAMPLETYPE
[length
];
184 memcpy(filterCoeffs
, coeffs
, length
* sizeof(SAMPLETYPE
));
188 uint
FIRFilter::getLength() const
195 // Applies the filter to the given sequence of samples.
197 // Note : The amount of outputted samples is by value of 'filter_length'
198 // smaller than the amount of input samples.
199 uint
FIRFilter::evaluate(SAMPLETYPE
*dest
, const SAMPLETYPE
*src
, uint numSamples
, uint numChannels
) const
201 assert(numChannels
== 1 || numChannels
== 2);
204 assert(lengthDiv8
* 8 == length
);
205 if (numSamples
< length
) return 0;
206 assert(resultDivFactor
>= 0);
207 if (numChannels
== 2)
209 return evaluateFilterStereo(dest
, src
, numSamples
);
211 return evaluateFilterMono(dest
, src
, numSamples
);
215 FIRFilter
* FIRFilter::newInstance()
219 uExtensions
= detectCPUextensions();
221 // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU
224 // MMX routines available only with integer sample types
225 if (uExtensions
& SUPPORT_MMX
)
227 return ::new FIRFilterMMX
;
233 if (uExtensions
& SUPPORT_SSE
)
236 return ::new FIRFilterSSE
;
242 if (uExtensions
& SUPPORT_3DNOW
)
245 return ::new FIRFilter3DNow
;
248 #endif // ALLOW_3DNOW
251 // ISA optimizations not supported, use plain C version
252 return ::new FIRFilter
;