1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libsoundtouch/src/FIRFilter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,329 @@ 1.4 +//////////////////////////////////////////////////////////////////////////////// 1.5 +/// 1.6 +/// General FIR digital filter routines with MMX optimization. 1.7 +/// 1.8 +/// Note : MMX optimized functions reside in a separate, platform-specific file, 1.9 +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' 1.10 +/// 1.11 +/// Author : Copyright (c) Olli Parviainen 1.12 +/// Author e-mail : oparviai 'at' iki.fi 1.13 +/// SoundTouch WWW: http://www.surina.net/soundtouch 1.14 +/// 1.15 +//////////////////////////////////////////////////////////////////////////////// 1.16 +// 1.17 +// Last changed : $Date: 2013-06-12 10:24:44 -0500 (Wed, 12 Jun 2013) $ 1.18 +// File revision : $Revision: 4 $ 1.19 +// 1.20 +// $Id: FIRFilter.cpp 171 2013-06-12 15:24:44Z oparviai $ 1.21 +// 1.22 +//////////////////////////////////////////////////////////////////////////////// 1.23 +// 1.24 +// License : 1.25 +// 1.26 +// SoundTouch audio processing library 1.27 +// Copyright (c) Olli Parviainen 1.28 +// 1.29 +// This library is free software; you can redistribute it and/or 1.30 +// modify it under the terms of the GNU Lesser General Public 1.31 +// License as published by the Free Software Foundation; either 1.32 +// version 2.1 of the License, or (at your option) any later version. 1.33 +// 1.34 +// This library is distributed in the hope that it will be useful, 1.35 +// but WITHOUT ANY WARRANTY; without even the implied warranty of 1.36 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.37 +// Lesser General Public License for more details. 1.38 +// 1.39 +// You should have received a copy of the GNU Lesser General Public 1.40 +// License along with this library; if not, write to the Free Software 1.41 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.42 +// 1.43 +//////////////////////////////////////////////////////////////////////////////// 1.44 + 1.45 +#include <memory.h> 1.46 +#include <assert.h> 1.47 +#include <math.h> 1.48 +#include <stdlib.h> 1.49 +#include "FIRFilter.h" 1.50 +#include "cpu_detect.h" 1.51 + 1.52 +#ifdef _MSC_VER 1.53 +#include <malloc.h> 1.54 +#define alloca _alloca 1.55 +#endif 1.56 + 1.57 +using namespace soundtouch; 1.58 + 1.59 +/***************************************************************************** 1.60 + * 1.61 + * Implementation of the class 'FIRFilter' 1.62 + * 1.63 + *****************************************************************************/ 1.64 + 1.65 +FIRFilter::FIRFilter() 1.66 +{ 1.67 + resultDivFactor = 0; 1.68 + resultDivider = 0; 1.69 + length = 0; 1.70 + lengthDiv8 = 0; 1.71 + filterCoeffs = NULL; 1.72 +} 1.73 + 1.74 + 1.75 +FIRFilter::~FIRFilter() 1.76 +{ 1.77 + delete[] filterCoeffs; 1.78 +} 1.79 + 1.80 +// Usual C-version of the filter routine for stereo sound 1.81 +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const 1.82 +{ 1.83 + uint i, j, end; 1.84 + LONG_SAMPLETYPE suml, sumr; 1.85 +#ifdef SOUNDTOUCH_FLOAT_SAMPLES 1.86 + // when using floating point samples, use a scaler instead of a divider 1.87 + // because division is much slower operation than multiplying. 1.88 + double dScaler = 1.0 / (double)resultDivider; 1.89 +#endif 1.90 + 1.91 + assert(length != 0); 1.92 + assert(src != NULL); 1.93 + assert(dest != NULL); 1.94 + assert(filterCoeffs != NULL); 1.95 + 1.96 + end = 2 * (numSamples - length); 1.97 + 1.98 + for (j = 0; j < end; j += 2) 1.99 + { 1.100 + const SAMPLETYPE *ptr; 1.101 + 1.102 + suml = sumr = 0; 1.103 + ptr = src + j; 1.104 + 1.105 + for (i = 0; i < length; i += 4) 1.106 + { 1.107 + // loop is unrolled by factor of 4 here for efficiency 1.108 + suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + 1.109 + ptr[2 * i + 2] * filterCoeffs[i + 1] + 1.110 + ptr[2 * i + 4] * filterCoeffs[i + 2] + 1.111 + ptr[2 * i + 6] * filterCoeffs[i + 3]; 1.112 + sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] + 1.113 + ptr[2 * i + 3] * filterCoeffs[i + 1] + 1.114 + ptr[2 * i + 5] * filterCoeffs[i + 2] + 1.115 + ptr[2 * i + 7] * filterCoeffs[i + 3]; 1.116 + } 1.117 + 1.118 +#ifdef SOUNDTOUCH_INTEGER_SAMPLES 1.119 + suml >>= resultDivFactor; 1.120 + sumr >>= resultDivFactor; 1.121 + // saturate to 16 bit integer limits 1.122 + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; 1.123 + // saturate to 16 bit integer limits 1.124 + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; 1.125 +#else 1.126 + suml *= dScaler; 1.127 + sumr *= dScaler; 1.128 +#endif // SOUNDTOUCH_INTEGER_SAMPLES 1.129 + dest[j] = (SAMPLETYPE)suml; 1.130 + dest[j + 1] = (SAMPLETYPE)sumr; 1.131 + } 1.132 + return numSamples - length; 1.133 +} 1.134 + 1.135 + 1.136 + 1.137 + 1.138 +// Usual C-version of the filter routine for mono sound 1.139 +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const 1.140 +{ 1.141 + uint i, j, end; 1.142 + LONG_SAMPLETYPE sum; 1.143 +#ifdef SOUNDTOUCH_FLOAT_SAMPLES 1.144 + // when using floating point samples, use a scaler instead of a divider 1.145 + // because division is much slower operation than multiplying. 1.146 + double dScaler = 1.0 / (double)resultDivider; 1.147 +#endif 1.148 + 1.149 + 1.150 + assert(length != 0); 1.151 + 1.152 + end = numSamples - length; 1.153 + for (j = 0; j < end; j ++) 1.154 + { 1.155 + sum = 0; 1.156 + for (i = 0; i < length; i += 4) 1.157 + { 1.158 + // loop is unrolled by factor of 4 here for efficiency 1.159 + sum += src[i + 0] * filterCoeffs[i + 0] + 1.160 + src[i + 1] * filterCoeffs[i + 1] + 1.161 + src[i + 2] * filterCoeffs[i + 2] + 1.162 + src[i + 3] * filterCoeffs[i + 3]; 1.163 + } 1.164 +#ifdef SOUNDTOUCH_INTEGER_SAMPLES 1.165 + sum >>= resultDivFactor; 1.166 + // saturate to 16 bit integer limits 1.167 + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; 1.168 +#else 1.169 + sum *= dScaler; 1.170 +#endif // SOUNDTOUCH_INTEGER_SAMPLES 1.171 + dest[j] = (SAMPLETYPE)sum; 1.172 + src ++; 1.173 + } 1.174 + return end; 1.175 +} 1.176 + 1.177 + 1.178 +uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const 1.179 +{ 1.180 + uint i, j, end, c; 1.181 + LONG_SAMPLETYPE *sum=(LONG_SAMPLETYPE*)alloca(numChannels*sizeof(*sum)); 1.182 +#ifdef SOUNDTOUCH_FLOAT_SAMPLES 1.183 + // when using floating point samples, use a scaler instead of a divider 1.184 + // because division is much slower operation than multiplying. 1.185 + double dScaler = 1.0 / (double)resultDivider; 1.186 +#endif 1.187 + 1.188 + assert(length != 0); 1.189 + assert(src != NULL); 1.190 + assert(dest != NULL); 1.191 + assert(filterCoeffs != NULL); 1.192 + 1.193 + end = numChannels * (numSamples - length); 1.194 + 1.195 + for (c = 0; c < numChannels; c ++) 1.196 + { 1.197 + sum[c] = 0; 1.198 + } 1.199 + 1.200 + for (j = 0; j < end; j += numChannels) 1.201 + { 1.202 + const SAMPLETYPE *ptr; 1.203 + 1.204 + ptr = src + j; 1.205 + 1.206 + for (i = 0; i < length; i ++) 1.207 + { 1.208 + SAMPLETYPE coef=filterCoeffs[i]; 1.209 + for (c = 0; c < numChannels; c ++) 1.210 + { 1.211 + sum[c] += ptr[0] * coef; 1.212 + ptr ++; 1.213 + } 1.214 + } 1.215 + 1.216 + for (c = 0; c < numChannels; c ++) 1.217 + { 1.218 +#ifdef SOUNDTOUCH_INTEGER_SAMPLES 1.219 + sum[c] >>= resultDivFactor; 1.220 +#else 1.221 + sum[c] *= dScaler; 1.222 +#endif // SOUNDTOUCH_INTEGER_SAMPLES 1.223 + *dest = (SAMPLETYPE)sum[c]; 1.224 + dest++; 1.225 + sum[c] = 0; 1.226 + } 1.227 + } 1.228 + return numSamples - length; 1.229 +} 1.230 + 1.231 + 1.232 +// Set filter coeffiecients and length. 1.233 +// 1.234 +// Throws an exception if filter length isn't divisible by 8 1.235 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) 1.236 +{ 1.237 + assert(newLength > 0); 1.238 + if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); 1.239 + 1.240 + lengthDiv8 = newLength / 8; 1.241 + length = lengthDiv8 * 8; 1.242 + assert(length == newLength); 1.243 + 1.244 + resultDivFactor = uResultDivFactor; 1.245 + resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); 1.246 + 1.247 + delete[] filterCoeffs; 1.248 + filterCoeffs = new SAMPLETYPE[length]; 1.249 + memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE)); 1.250 +} 1.251 + 1.252 + 1.253 +uint FIRFilter::getLength() const 1.254 +{ 1.255 + return length; 1.256 +} 1.257 + 1.258 + 1.259 + 1.260 +// Applies the filter to the given sequence of samples. 1.261 +// 1.262 +// Note : The amount of outputted samples is by value of 'filter_length' 1.263 +// smaller than the amount of input samples. 1.264 +uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const 1.265 +{ 1.266 + assert(length > 0); 1.267 + assert(lengthDiv8 * 8 == length); 1.268 + 1.269 + if (numSamples < length) return 0; 1.270 + 1.271 +#ifndef USE_MULTICH_ALWAYS 1.272 + if (numChannels == 1) 1.273 + { 1.274 + return evaluateFilterMono(dest, src, numSamples); 1.275 + } 1.276 + else if (numChannels == 2) 1.277 + { 1.278 + return evaluateFilterStereo(dest, src, numSamples); 1.279 + } 1.280 + else 1.281 +#endif // USE_MULTICH_ALWAYS 1.282 + { 1.283 + assert(numChannels > 0); 1.284 + return evaluateFilterMulti(dest, src, numSamples, numChannels); 1.285 + } 1.286 +} 1.287 + 1.288 + 1.289 + 1.290 +// Operator 'new' is overloaded so that it automatically creates a suitable instance 1.291 +// depending on if we've a MMX-capable CPU available or not. 1.292 +void * FIRFilter::operator new(size_t s) 1.293 +{ 1.294 + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! 1.295 + ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); 1.296 + return newInstance(); 1.297 +} 1.298 + 1.299 + 1.300 +FIRFilter * FIRFilter::newInstance() 1.301 +{ 1.302 +#if defined(SOUNDTOUCH_ALLOW_MMX) || defined(SOUNDTOUCH_ALLOW_SSE) 1.303 + uint uExtensions; 1.304 + 1.305 + uExtensions = detectCPUextensions(); 1.306 +#endif 1.307 + 1.308 + // Check if MMX/SSE instruction set extensions supported by CPU 1.309 + 1.310 +#ifdef SOUNDTOUCH_ALLOW_MMX 1.311 + // MMX routines available only with integer sample types 1.312 + if (uExtensions & SUPPORT_MMX) 1.313 + { 1.314 + return ::new FIRFilterMMX; 1.315 + } 1.316 + else 1.317 +#endif // SOUNDTOUCH_ALLOW_MMX 1.318 + 1.319 +#ifdef SOUNDTOUCH_ALLOW_SSE 1.320 + if (uExtensions & SUPPORT_SSE) 1.321 + { 1.322 + // SSE support 1.323 + return ::new FIRFilterSSE; 1.324 + } 1.325 + else 1.326 +#endif // SOUNDTOUCH_ALLOW_SSE 1.327 + 1.328 + { 1.329 + // ISA optimizations not supported, use plain C version 1.330 + return ::new FIRFilter; 1.331 + } 1.332 +}