1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/media/libsoundtouch/src/AAFilter.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,236 @@ 1.4 +//////////////////////////////////////////////////////////////////////////////// 1.5 +/// 1.6 +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and 1.7 +/// MMX optimization. 1.8 +/// 1.9 +/// Anti-alias filter is used to prevent folding of high frequencies when 1.10 +/// transposing the sample rate with interpolation. 1.11 +/// 1.12 +/// Author : Copyright (c) Olli Parviainen 1.13 +/// Author e-mail : oparviai 'at' iki.fi 1.14 +/// SoundTouch WWW: http://www.surina.net/soundtouch 1.15 +/// 1.16 +//////////////////////////////////////////////////////////////////////////////// 1.17 +// 1.18 +// Last changed : $Date: 2014-01-05 15:40:22 -0600 (Sun, 05 Jan 2014) $ 1.19 +// File revision : $Revision: 4 $ 1.20 +// 1.21 +// $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $ 1.22 +// 1.23 +//////////////////////////////////////////////////////////////////////////////// 1.24 +// 1.25 +// License : 1.26 +// 1.27 +// SoundTouch audio processing library 1.28 +// Copyright (c) Olli Parviainen 1.29 +// 1.30 +// This library is free software; you can redistribute it and/or 1.31 +// modify it under the terms of the GNU Lesser General Public 1.32 +// License as published by the Free Software Foundation; either 1.33 +// version 2.1 of the License, or (at your option) any later version. 1.34 +// 1.35 +// This library is distributed in the hope that it will be useful, 1.36 +// but WITHOUT ANY WARRANTY; without even the implied warranty of 1.37 +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.38 +// Lesser General Public License for more details. 1.39 +// 1.40 +// You should have received a copy of the GNU Lesser General Public 1.41 +// License along with this library; if not, write to the Free Software 1.42 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.43 +// 1.44 +//////////////////////////////////////////////////////////////////////////////// 1.45 + 1.46 +#include <memory.h> 1.47 +#include <assert.h> 1.48 +#include <math.h> 1.49 +#include <stdlib.h> 1.50 +#include "AAFilter.h" 1.51 +#include "FIRFilter.h" 1.52 + 1.53 +using namespace soundtouch; 1.54 + 1.55 +#define PI 3.141592655357989 1.56 +#define TWOPI (2 * PI) 1.57 + 1.58 +// define this to save AA filter coefficients to a file 1.59 +// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1 1.60 + 1.61 +#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1.62 + #include <stdio.h> 1.63 + 1.64 + static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) 1.65 + { 1.66 + FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); 1.67 + if (fptr == NULL) return; 1.68 + 1.69 + for (int i = 0; i < len; i ++) 1.70 + { 1.71 + double temp = coeffs[i]; 1.72 + fprintf(fptr, "%lf\n", temp); 1.73 + } 1.74 + fclose(fptr); 1.75 + } 1.76 + 1.77 +#else 1.78 + #define _DEBUG_SAVE_AAFIR_COEFFS(x, y) 1.79 +#endif 1.80 + 1.81 + 1.82 +/***************************************************************************** 1.83 + * 1.84 + * Implementation of the class 'AAFilter' 1.85 + * 1.86 + *****************************************************************************/ 1.87 + 1.88 +AAFilter::AAFilter(uint len) 1.89 +{ 1.90 + pFIR = FIRFilter::newInstance(); 1.91 + cutoffFreq = 0.5; 1.92 + setLength(len); 1.93 +} 1.94 + 1.95 + 1.96 + 1.97 +AAFilter::~AAFilter() 1.98 +{ 1.99 + delete pFIR; 1.100 +} 1.101 + 1.102 + 1.103 + 1.104 +// Sets new anti-alias filter cut-off edge frequency, scaled to 1.105 +// sampling frequency (nyquist frequency = 0.5). 1.106 +// The filter will cut frequencies higher than the given frequency. 1.107 +void AAFilter::setCutoffFreq(double newCutoffFreq) 1.108 +{ 1.109 + cutoffFreq = newCutoffFreq; 1.110 + calculateCoeffs(); 1.111 +} 1.112 + 1.113 + 1.114 + 1.115 +// Sets number of FIR filter taps 1.116 +void AAFilter::setLength(uint newLength) 1.117 +{ 1.118 + length = newLength; 1.119 + calculateCoeffs(); 1.120 +} 1.121 + 1.122 + 1.123 + 1.124 +// Calculates coefficients for a low-pass FIR filter using Hamming window 1.125 +void AAFilter::calculateCoeffs() 1.126 +{ 1.127 + uint i; 1.128 + double cntTemp, temp, tempCoeff,h, w; 1.129 + double wc; 1.130 + double scaleCoeff, sum; 1.131 + double *work; 1.132 + SAMPLETYPE *coeffs; 1.133 + 1.134 + assert(length >= 2); 1.135 + assert(length % 4 == 0); 1.136 + assert(cutoffFreq >= 0); 1.137 + assert(cutoffFreq <= 0.5); 1.138 + 1.139 + work = new double[length]; 1.140 + coeffs = new SAMPLETYPE[length]; 1.141 + 1.142 + wc = 2.0 * PI * cutoffFreq; 1.143 + tempCoeff = TWOPI / (double)length; 1.144 + 1.145 + sum = 0; 1.146 + for (i = 0; i < length; i ++) 1.147 + { 1.148 + cntTemp = (double)i - (double)(length / 2); 1.149 + 1.150 + temp = cntTemp * wc; 1.151 + if (temp != 0) 1.152 + { 1.153 + h = sin(temp) / temp; // sinc function 1.154 + } 1.155 + else 1.156 + { 1.157 + h = 1.0; 1.158 + } 1.159 + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window 1.160 + 1.161 + temp = w * h; 1.162 + work[i] = temp; 1.163 + 1.164 + // calc net sum of coefficients 1.165 + sum += temp; 1.166 + } 1.167 + 1.168 + // ensure the sum of coefficients is larger than zero 1.169 + assert(sum > 0); 1.170 + 1.171 + // ensure we've really designed a lowpass filter... 1.172 + assert(work[length/2] > 0); 1.173 + assert(work[length/2 + 1] > -1e-6); 1.174 + assert(work[length/2 - 1] > -1e-6); 1.175 + 1.176 + // Calculate a scaling coefficient in such a way that the result can be 1.177 + // divided by 16384 1.178 + scaleCoeff = 16384.0f / sum; 1.179 + 1.180 + for (i = 0; i < length; i ++) 1.181 + { 1.182 + temp = work[i] * scaleCoeff; 1.183 +//#if SOUNDTOUCH_INTEGER_SAMPLES 1.184 + // scale & round to nearest integer 1.185 + temp += (temp >= 0) ? 0.5 : -0.5; 1.186 + // ensure no overfloods 1.187 + assert(temp >= -32768 && temp <= 32767); 1.188 +//#endif 1.189 + coeffs[i] = (SAMPLETYPE)temp; 1.190 + } 1.191 + 1.192 + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 1.193 + pFIR->setCoefficients(coeffs, length, 14); 1.194 + 1.195 + _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length); 1.196 + 1.197 + delete[] work; 1.198 + delete[] coeffs; 1.199 +} 1.200 + 1.201 + 1.202 +// Applies the filter to the given sequence of samples. 1.203 +// Note : The amount of outputted samples is by value of 'filter length' 1.204 +// smaller than the amount of input samples. 1.205 +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const 1.206 +{ 1.207 + return pFIR->evaluate(dest, src, numSamples, numChannels); 1.208 +} 1.209 + 1.210 + 1.211 +/// Applies the filter to the given src & dest pipes, so that processed amount of 1.212 +/// samples get removed from src, and produced amount added to dest 1.213 +/// Note : The amount of outputted samples is by value of 'filter length' 1.214 +/// smaller than the amount of input samples. 1.215 +uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const 1.216 +{ 1.217 + SAMPLETYPE *pdest; 1.218 + const SAMPLETYPE *psrc; 1.219 + uint numSrcSamples; 1.220 + uint result; 1.221 + int numChannels = src.getChannels(); 1.222 + 1.223 + assert(numChannels == dest.getChannels()); 1.224 + 1.225 + numSrcSamples = src.numSamples(); 1.226 + psrc = src.ptrBegin(); 1.227 + pdest = dest.ptrEnd(numSrcSamples); 1.228 + result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels); 1.229 + src.receiveSamples(result); 1.230 + dest.putSamples(result); 1.231 + 1.232 + return result; 1.233 +} 1.234 + 1.235 + 1.236 +uint AAFilter::getLength() const 1.237 +{ 1.238 + return pFIR->getLength(); 1.239 +}