media/libsoundtouch/src/FIRFilter.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial