media/libsoundtouch/src/AAFilter.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 ////////////////////////////////////////////////////////////////////////////////
     2 ///
     3 /// FIR low-pass (anti-alias) filter with filter coefficient design routine and
     4 /// MMX optimization. 
     5 /// 
     6 /// Anti-alias filter is used to prevent folding of high frequencies when 
     7 /// transposing the sample rate with interpolation.
     8 ///
     9 /// Author        : Copyright (c) Olli Parviainen
    10 /// Author e-mail : oparviai 'at' iki.fi
    11 /// SoundTouch WWW: http://www.surina.net/soundtouch
    12 ///
    13 ////////////////////////////////////////////////////////////////////////////////
    14 //
    15 // Last changed  : $Date: 2014-01-05 15:40:22 -0600 (Sun, 05 Jan 2014) $
    16 // File revision : $Revision: 4 $
    17 //
    18 // $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $
    19 //
    20 ////////////////////////////////////////////////////////////////////////////////
    21 //
    22 // License :
    23 //
    24 //  SoundTouch audio processing library
    25 //  Copyright (c) Olli Parviainen
    26 //
    27 //  This library is free software; you can redistribute it and/or
    28 //  modify it under the terms of the GNU Lesser General Public
    29 //  License as published by the Free Software Foundation; either
    30 //  version 2.1 of the License, or (at your option) any later version.
    31 //
    32 //  This library is distributed in the hope that it will be useful,
    33 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
    34 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    35 //  Lesser General Public License for more details.
    36 //
    37 //  You should have received a copy of the GNU Lesser General Public
    38 //  License along with this library; if not, write to the Free Software
    39 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    40 //
    41 ////////////////////////////////////////////////////////////////////////////////
    43 #include <memory.h>
    44 #include <assert.h>
    45 #include <math.h>
    46 #include <stdlib.h>
    47 #include "AAFilter.h"
    48 #include "FIRFilter.h"
    50 using namespace soundtouch;
    52 #define PI        3.141592655357989
    53 #define TWOPI    (2 * PI)
    55 // define this to save AA filter coefficients to a file
    56 // #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS   1
    58 #ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS
    59     #include <stdio.h>
    61     static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)
    62     {
    63         FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");
    64         if (fptr == NULL) return;
    66         for (int i = 0; i < len; i ++)
    67         {
    68             double temp = coeffs[i];
    69             fprintf(fptr, "%lf\n", temp);
    70         }
    71         fclose(fptr);
    72     }
    74 #else
    75     #define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
    76 #endif
    79 /*****************************************************************************
    80  *
    81  * Implementation of the class 'AAFilter'
    82  *
    83  *****************************************************************************/
    85 AAFilter::AAFilter(uint len)
    86 {
    87     pFIR = FIRFilter::newInstance();
    88     cutoffFreq = 0.5;
    89     setLength(len);
    90 }
    94 AAFilter::~AAFilter()
    95 {
    96     delete pFIR;
    97 }
   101 // Sets new anti-alias filter cut-off edge frequency, scaled to
   102 // sampling frequency (nyquist frequency = 0.5).
   103 // The filter will cut frequencies higher than the given frequency.
   104 void AAFilter::setCutoffFreq(double newCutoffFreq)
   105 {
   106     cutoffFreq = newCutoffFreq;
   107     calculateCoeffs();
   108 }
   112 // Sets number of FIR filter taps
   113 void AAFilter::setLength(uint newLength)
   114 {
   115     length = newLength;
   116     calculateCoeffs();
   117 }
   121 // Calculates coefficients for a low-pass FIR filter using Hamming window
   122 void AAFilter::calculateCoeffs()
   123 {
   124     uint i;
   125     double cntTemp, temp, tempCoeff,h, w;
   126     double wc;
   127     double scaleCoeff, sum;
   128     double *work;
   129     SAMPLETYPE *coeffs;
   131     assert(length >= 2);
   132     assert(length % 4 == 0);
   133     assert(cutoffFreq >= 0);
   134     assert(cutoffFreq <= 0.5);
   136     work = new double[length];
   137     coeffs = new SAMPLETYPE[length];
   139     wc = 2.0 * PI * cutoffFreq;
   140     tempCoeff = TWOPI / (double)length;
   142     sum = 0;
   143     for (i = 0; i < length; i ++) 
   144     {
   145         cntTemp = (double)i - (double)(length / 2);
   147         temp = cntTemp * wc;
   148         if (temp != 0) 
   149         {
   150             h = sin(temp) / temp;                     // sinc function
   151         } 
   152         else 
   153         {
   154             h = 1.0;
   155         }
   156         w = 0.54 + 0.46 * cos(tempCoeff * cntTemp);       // hamming window
   158         temp = w * h;
   159         work[i] = temp;
   161         // calc net sum of coefficients 
   162         sum += temp;
   163     }
   165     // ensure the sum of coefficients is larger than zero
   166     assert(sum > 0);
   168     // ensure we've really designed a lowpass filter...
   169     assert(work[length/2] > 0);
   170     assert(work[length/2 + 1] > -1e-6);
   171     assert(work[length/2 - 1] > -1e-6);
   173     // Calculate a scaling coefficient in such a way that the result can be
   174     // divided by 16384
   175     scaleCoeff = 16384.0f / sum;
   177     for (i = 0; i < length; i ++) 
   178     {
   179         temp = work[i] * scaleCoeff;
   180 //#if SOUNDTOUCH_INTEGER_SAMPLES
   181         // scale & round to nearest integer
   182         temp += (temp >= 0) ? 0.5 : -0.5;
   183         // ensure no overfloods
   184         assert(temp >= -32768 && temp <= 32767);
   185 //#endif
   186         coeffs[i] = (SAMPLETYPE)temp;
   187     }
   189     // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
   190     pFIR->setCoefficients(coeffs, length, 14);
   192     _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);
   194     delete[] work;
   195     delete[] coeffs;
   196 }
   199 // Applies the filter to the given sequence of samples. 
   200 // Note : The amount of outputted samples is by value of 'filter length' 
   201 // smaller than the amount of input samples.
   202 uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
   203 {
   204     return pFIR->evaluate(dest, src, numSamples, numChannels);
   205 }
   208 /// Applies the filter to the given src & dest pipes, so that processed amount of
   209 /// samples get removed from src, and produced amount added to dest 
   210 /// Note : The amount of outputted samples is by value of 'filter length' 
   211 /// smaller than the amount of input samples.
   212 uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
   213 {
   214     SAMPLETYPE *pdest;
   215     const SAMPLETYPE *psrc;
   216     uint numSrcSamples;
   217     uint result;
   218     int numChannels = src.getChannels();
   220     assert(numChannels == dest.getChannels());
   222     numSrcSamples = src.numSamples();
   223     psrc = src.ptrBegin();
   224     pdest = dest.ptrEnd(numSrcSamples);
   225     result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);
   226     src.receiveSamples(result);
   227     dest.putSamples(result);
   229     return result;
   230 }
   233 uint AAFilter::getLength() const
   234 {
   235     return pFIR->getLength();
   236 }

mercurial