media/libsoundtouch/src/FIRFilter.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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 ////////////////////////////////////////////////////////////////////////////////
    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"
    49 #ifdef _MSC_VER
    50 #include <malloc.h>
    51 #define alloca _alloca
    52 #endif
    54 using namespace soundtouch;
    56 /*****************************************************************************
    57  *
    58  * Implementation of the class 'FIRFilter'
    59  *
    60  *****************************************************************************/
    62 FIRFilter::FIRFilter()
    63 {
    64     resultDivFactor = 0;
    65     resultDivider = 0;
    66     length = 0;
    67     lengthDiv8 = 0;
    68     filterCoeffs = NULL;
    69 }
    72 FIRFilter::~FIRFilter()
    73 {
    74     delete[] filterCoeffs;
    75 }
    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
    88     assert(length != 0);
    89     assert(src != NULL);
    90     assert(dest != NULL);
    91     assert(filterCoeffs != NULL);
    93     end = 2 * (numSamples - length);
    95     for (j = 0; j < end; j += 2) 
    96     {
    97         const SAMPLETYPE *ptr;
    99         suml = sumr = 0;
   100         ptr = src + j;
   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         }
   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 }
   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
   147     assert(length != 0);
   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 }
   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
   185     assert(length != 0);
   186     assert(src != NULL);
   187     assert(dest != NULL);
   188     assert(filterCoeffs != NULL);
   190     end = numChannels * (numSamples - length);
   192     for (c = 0; c < numChannels; c ++)
   193     {
   194         sum[c] = 0;
   195     }
   197     for (j = 0; j < end; j += numChannels)
   198     {
   199         const SAMPLETYPE *ptr;
   201         ptr = src + j;
   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         }
   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 }
   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");
   237     lengthDiv8 = newLength / 8;
   238     length = lengthDiv8 * 8;
   239     assert(length == newLength);
   241     resultDivFactor = uResultDivFactor;
   242     resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);
   244     delete[] filterCoeffs;
   245     filterCoeffs = new SAMPLETYPE[length];
   246     memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
   247 }
   250 uint FIRFilter::getLength() const
   251 {
   252     return length;
   253 }
   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);
   266     if (numSamples < length) return 0;
   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 }
   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 }
   297 FIRFilter * FIRFilter::newInstance()
   298 {
   299 #if defined(SOUNDTOUCH_ALLOW_MMX) || defined(SOUNDTOUCH_ALLOW_SSE)
   300     uint uExtensions;
   302     uExtensions = detectCPUextensions();
   303 #endif
   305     // Check if MMX/SSE instruction set extensions supported by CPU
   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
   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
   325     {
   326         // ISA optimizations not supported, use plain C version
   327         return ::new FIRFilter;
   328     }
   329 }

mercurial