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 }