tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AAFilter.cpp (6143B)


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