media/libsoundtouch/src/FIRFilter.cpp

changeset 0
6474c204b198
     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 +}

mercurial