diff --git a/Externals/soundtouch/AAFilter.cpp b/Externals/soundtouch/AAFilter.cpp index 010fb511b2..b3bb947bd6 100644 --- a/Externals/soundtouch/AAFilter.cpp +++ b/Externals/soundtouch/AAFilter.cpp @@ -12,10 +12,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-01-11 11:34:24 +0000 (Sun, 11 Jan 2009) $ +// Last changed : $Date: 2014-01-06 08:40:22 +1100 (Mon, 06 Jan 2014) $ // File revision : $Revision: 4 $ // -// $Id: AAFilter.cpp 45 2009-01-11 11:34:24Z oparviai $ +// $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -52,6 +52,30 @@ using namespace soundtouch; #define PI 3.141592655357989 #define TWOPI (2 * PI) +// define this to save AA filter coefficients to a file +// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1 + +#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS + #include + + static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) + { + FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); + if (fptr == NULL) return; + + for (int i = 0; i < len; i ++) + { + double temp = coeffs[i]; + fprintf(fptr, "%lf\n", temp); + } + fclose(fptr); + } + +#else + #define _DEBUG_SAVE_AAFIR_COEFFS(x, y) +#endif + + /***************************************************************************** * * Implementation of the class 'AAFilter' @@ -99,7 +123,7 @@ void AAFilter::calculateCoeffs() { uint i; double cntTemp, temp, tempCoeff,h, w; - double fc2, wc; + double wc; double scaleCoeff, sum; double *work; SAMPLETYPE *coeffs; @@ -112,8 +136,7 @@ void AAFilter::calculateCoeffs() work = new double[length]; coeffs = new SAMPLETYPE[length]; - fc2 = 2.0 * cutoffFreq; - wc = PI * fc2; + wc = 2.0 * PI * cutoffFreq; tempCoeff = TWOPI / (double)length; sum = 0; @@ -124,7 +147,7 @@ void AAFilter::calculateCoeffs() temp = cntTemp * wc; if (temp != 0) { - h = fc2 * sin(temp) / temp; // sinc function + h = sin(temp) / temp; // sinc function } else { @@ -153,17 +176,21 @@ void AAFilter::calculateCoeffs() for (i = 0; i < length; i ++) { - // scale & round to nearest integer temp = work[i] * scaleCoeff; +//#if SOUNDTOUCH_INTEGER_SAMPLES + // scale & round to nearest integer temp += (temp >= 0) ? 0.5 : -0.5; // ensure no overfloods assert(temp >= -32768 && temp <= 32767); +//#endif coeffs[i] = (SAMPLETYPE)temp; } // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 pFIR->setCoefficients(coeffs, length, 14); + _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length); + delete[] work; delete[] coeffs; } @@ -178,6 +205,31 @@ uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples } +/// Applies the filter to the given src & dest pipes, so that processed amount of +/// samples get removed from src, and produced amount added to dest +/// Note : The amount of outputted samples is by value of 'filter length' +/// smaller than the amount of input samples. +uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const +{ + SAMPLETYPE *pdest; + const SAMPLETYPE *psrc; + uint numSrcSamples; + uint result; + int numChannels = src.getChannels(); + + assert(numChannels == dest.getChannels()); + + numSrcSamples = src.numSamples(); + psrc = src.ptrBegin(); + pdest = dest.ptrEnd(numSrcSamples); + result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels); + src.receiveSamples(result); + dest.putSamples(result); + + return result; +} + + uint AAFilter::getLength() const { return pFIR->getLength(); diff --git a/Externals/soundtouch/AAFilter.h b/Externals/soundtouch/AAFilter.h index d8b1cd2c66..3a9e16331b 100644 --- a/Externals/soundtouch/AAFilter.h +++ b/Externals/soundtouch/AAFilter.h @@ -13,10 +13,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2008-02-10 16:26:55 +0000 (Sun, 10 Feb 2008) $ +// Last changed : $Date: 2014-01-08 06:41:23 +1100 (Wed, 08 Jan 2014) $ // File revision : $Revision: 4 $ // -// $Id: AAFilter.h 11 2008-02-10 16:26:55Z oparviai $ +// $Id: AAFilter.h 187 2014-01-07 19:41:23Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -45,6 +45,7 @@ #define AAFilter_H #include "STTypes.h" +#include "FIFOSampleBuffer.h" namespace soundtouch { @@ -84,6 +85,14 @@ public: const SAMPLETYPE *src, uint numSamples, uint numChannels) const; + + /// Applies the filter to the given src & dest pipes, so that processed amount of + /// samples get removed from src, and produced amount added to dest + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(FIFOSampleBuffer &dest, + FIFOSampleBuffer &src) const; + }; } diff --git a/Externals/soundtouch/BPMDetect.cpp b/Externals/soundtouch/BPMDetect.cpp index be2478388f..88a2d9f601 100644 --- a/Externals/soundtouch/BPMDetect.cpp +++ b/Externals/soundtouch/BPMDetect.cpp @@ -26,7 +26,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2012-08-30 19:45:25 +0000 (Thu, 30 Aug 2012) $ +// Last changed : $Date: 2012-08-31 05:45:25 +1000 (Fri, 31 Aug 2012) $ // File revision : $Revision: 4 $ // // $Id: BPMDetect.cpp 149 2012-08-30 19:45:25Z oparviai $ diff --git a/Externals/soundtouch/CMakeLists.txt b/Externals/soundtouch/CMakeLists.txt index a09aac1946..b7a2e5dc05 100644 --- a/Externals/soundtouch/CMakeLists.txt +++ b/Externals/soundtouch/CMakeLists.txt @@ -4,6 +4,9 @@ set(SRCS cpu_detect_x86.cpp FIFOSampleBuffer.cpp FIRFilter.cpp + InterpolateCubic.cpp + InterpolateLinear.cpp + InterpolateShannon.cpp mmx_optimized.cpp PeakFinder.cpp RateTransposer.cpp diff --git a/Externals/soundtouch/FIFOSampleBuffer.cpp b/Externals/soundtouch/FIFOSampleBuffer.cpp index be6060e3c3..7a54d8795a 100644 --- a/Externals/soundtouch/FIFOSampleBuffer.cpp +++ b/Externals/soundtouch/FIFOSampleBuffer.cpp @@ -15,7 +15,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2012-11-08 18:53:01 +0000 (Thu, 08 Nov 2012) $ +// Last changed : $Date: 2012-11-09 05:53:01 +1100 (Fri, 09 Nov 2012) $ // File revision : $Revision: 4 $ // // $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $ @@ -86,6 +86,10 @@ void FIFOSampleBuffer::setChannels(int numChannels) samplesInBuffer = usedBytes / channels; } +int FIFOSampleBuffer::getChannels() +{ + return channels; +} // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and // zeroes this pointer by copying samples from the 'bufferPos' pointer diff --git a/Externals/soundtouch/FIFOSampleBuffer.h b/Externals/soundtouch/FIFOSampleBuffer.h index e44d611eb7..746af0ec11 100644 --- a/Externals/soundtouch/FIFOSampleBuffer.h +++ b/Externals/soundtouch/FIFOSampleBuffer.h @@ -161,6 +161,7 @@ public: /// Sets number of channels, 1 = mono, 2 = stereo. void setChannels(int numChannels); + int getChannels(); /// Returns nonzero if there aren't any samples available for outputting. virtual int isEmpty() const; diff --git a/Externals/soundtouch/FIRFilter.cpp b/Externals/soundtouch/FIRFilter.cpp index 54c808d006..b79b2d08c9 100644 --- a/Externals/soundtouch/FIRFilter.cpp +++ b/Externals/soundtouch/FIRFilter.cpp @@ -11,7 +11,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2013-06-12 15:24:44 +0000 (Wed, 12 Jun 2013) $ +// Last changed : $Date: 2013-06-13 01:24:44 +1000 (Thu, 13 Jun 2013) $ // File revision : $Revision: 4 $ // // $Id: FIRFilter.cpp 171 2013-06-12 15:24:44Z oparviai $ @@ -217,7 +217,6 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin sum[c] = 0; } } - free(sum); return numSamples - length; } diff --git a/Externals/soundtouch/FIRFilter.h b/Externals/soundtouch/FIRFilter.h index a498032fe8..14694cb2eb 100644 --- a/Externals/soundtouch/FIRFilter.h +++ b/Externals/soundtouch/FIRFilter.h @@ -11,7 +11,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2013-06-12 15:24:44 +0000 (Wed, 12 Jun 2013) $ +// Last changed : $Date: 2013-06-13 01:24:44 +1000 (Thu, 13 Jun 2013) $ // File revision : $Revision: 4 $ // // $Id: FIRFilter.h 171 2013-06-12 15:24:44Z oparviai $ diff --git a/Externals/soundtouch/InterpolateCubic.cpp b/Externals/soundtouch/InterpolateCubic.cpp new file mode 100644 index 0000000000..8aa7374c74 --- /dev/null +++ b/Externals/soundtouch/InterpolateCubic.cpp @@ -0,0 +1,200 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Cubic interpolation routine. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// $Id: InterpolateCubic.cpp 179 2014-01-06 18:41:42Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "InterpolateCubic.h" +#include "STTypes.h" + +using namespace soundtouch; + +// cubic interpolation coefficients +static const float _coeffs[]= +{ -0.5f, 1.0f, -0.5f, 0.0f, + 1.5f, -2.5f, 0.0f, 1.0f, + -1.5f, 2.0f, 0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f}; + + +InterpolateCubic::InterpolateCubic() +{ + fract = 0; +} + + +void InterpolateCubic::resetRegisters() +{ + fract = 0; +} + + +/// Transpose mono audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 4; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + float out; + const float x3 = 1.0f; + const float x2 = (float)fract; // x + const float x1 = x2*x2; // x^2 + const float x0 = x1*x2; // x^3 + float y0, y1, y2, y3; + + assert(fract < 1.0); + + y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; + y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; + y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; + y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; + + out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3]; + + pdest[i] = (SAMPLETYPE)out; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose stereo audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 4; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + const float x3 = 1.0f; + const float x2 = (float)fract; // x + const float x1 = x2*x2; // x^2 + const float x0 = x1*x2; // x^3 + float y0, y1, y2, y3; + float out0, out1; + + assert(fract < 1.0); + + y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; + y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; + y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; + y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; + + out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6]; + out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7]; + + pdest[2*i] = (SAMPLETYPE)out0; + pdest[2*i+1] = (SAMPLETYPE)out1; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += 2*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose multi-channel audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 4; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + const float x3 = 1.0f; + const float x2 = (float)fract; // x + const float x1 = x2*x2; // x^2 + const float x0 = x1*x2; // x^3 + float y0, y1, y2, y3; + + assert(fract < 1.0); + + y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; + y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; + y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; + y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; + + for (int c = 0; c < numChannels; c ++) + { + float out; + out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels]; + pdest[0] = (SAMPLETYPE)out; + pdest ++; + } + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += numChannels*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} diff --git a/Externals/soundtouch/InterpolateCubic.h b/Externals/soundtouch/InterpolateCubic.h new file mode 100644 index 0000000000..e0e302b233 --- /dev/null +++ b/Externals/soundtouch/InterpolateCubic.h @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Cubic interpolation routine. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// $Id: InterpolateCubic.h 179 2014-01-06 18:41:42Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _InterpolateCubic_H_ +#define _InterpolateCubic_H_ + +#include "RateTransposer.h" +#include "STTypes.h" + +namespace soundtouch +{ + +class InterpolateCubic : public TransposerBase +{ +protected: + virtual void resetRegisters(); + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeMulti(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + + float fract; + +public: + InterpolateCubic(); +}; + +} + +#endif diff --git a/Externals/soundtouch/InterpolateLinear.cpp b/Externals/soundtouch/InterpolateLinear.cpp new file mode 100644 index 0000000000..ae26e69a1e --- /dev/null +++ b/Externals/soundtouch/InterpolateLinear.cpp @@ -0,0 +1,299 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Linear interpolation algorithm. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// $Id: InterpolateLinear.cpp 180 2014-01-06 19:16:02Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "InterpolateLinear.h" + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// InterpolateLinearInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + + +// Constructor +InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase() +{ + // Notice: use local function calling syntax for sake of clarity, + // to indicate the fact that C++ constructor can't call virtual functions. + resetRegisters(); + setRate(1.0f); +} + + +void InterpolateLinearInteger::resetRegisters() +{ + iFract = 0; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + LONG_SAMPLETYPE temp; + + assert(iFract < SCALE); + + temp = (SCALE - iFract) * src[0] + iFract * src[1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + + iFract += iRate; + + int iWhole = iFract / SCALE; + iFract -= iWhole * SCALE; + srcCount += iWhole; + src += iWhole; + } + srcSamples = srcCount; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + LONG_SAMPLETYPE temp0; + LONG_SAMPLETYPE temp1; + + assert(iFract < SCALE); + + temp0 = (SCALE - iFract) * src[0] + iFract * src[2]; + temp1 = (SCALE - iFract) * src[1] + iFract * src[3]; + dest[0] = (SAMPLETYPE)(temp0 / SCALE); + dest[1] = (SAMPLETYPE)(temp1 / SCALE); + dest += 2; + i++; + + iFract += iRate; + + int iWhole = iFract / SCALE; + iFract -= iWhole * SCALE; + srcCount += iWhole; + src += 2*iWhole; + } + srcSamples = srcCount; + + return i; +} + + +int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + LONG_SAMPLETYPE temp, vol1; + + assert(iFract < SCALE); + vol1 = (SCALE - iFract); + for (int c = 0; c < numChannels; c ++) + { + temp = vol1 * src[c] + iFract * src[c + numChannels]; + dest[0] = (SAMPLETYPE)(temp / SCALE); + dest ++; + } + i++; + + iFract += iRate; + + int iWhole = iFract / SCALE; + iFract -= iWhole * SCALE; + srcCount += iWhole; + src += iWhole * numChannels; + } + srcSamples = srcCount; + + return i; +} + + +// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower +// iRate, larger faster iRates. +void InterpolateLinearInteger::setRate(float newRate) +{ + iRate = (int)(newRate * SCALE + 0.5f); + TransposerBase::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// InterpolateLinearFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + + +// Constructor +InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase() +{ + // Notice: use local function calling syntax for sake of clarity, + // to indicate the fact that C++ constructor can't call virtual functions. + resetRegisters(); + setRate(1.0f); +} + + +void InterpolateLinearFloat::resetRegisters() +{ + fract = 0; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out; + assert(fract < 1.0); + + out = (1.0 - fract) * src[0] + fract * src[1]; + dest[i] = (SAMPLETYPE)out; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + src += whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out0, out1; + assert(fract < 1.0); + + out0 = (1.0 - fract) * src[0] + fract * src[2]; + out1 = (1.0 - fract) * src[1] + fract * src[3]; + dest[2*i] = (SAMPLETYPE)out0; + dest[2*i+1] = (SAMPLETYPE)out1; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + src += 2*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + float temp, vol1; + + vol1 = (1.0f- fract); + for (int c = 0; c < numChannels; c ++) + { + temp = vol1 * src[c] + fract * src[c + numChannels]; + *dest = (SAMPLETYPE)temp; + dest ++; + } + i++; + + fract += rate; + + int iWhole = (int)fract; + fract -= iWhole; + srcCount += iWhole; + src += iWhole * numChannels; + } + srcSamples = srcCount; + + return i; +} diff --git a/Externals/soundtouch/InterpolateLinear.h b/Externals/soundtouch/InterpolateLinear.h new file mode 100644 index 0000000000..b76299f889 --- /dev/null +++ b/Externals/soundtouch/InterpolateLinear.h @@ -0,0 +1,92 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Linear interpolation routine. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// $Id: InterpolateLinear.h 179 2014-01-06 18:41:42Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _InterpolateLinear_H_ +#define _InterpolateLinear_H_ + +#include "RateTransposer.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Linear transposer class that uses integer arithmetics +class InterpolateLinearInteger : public TransposerBase +{ +protected: + int iFract; + int iRate; + + virtual void resetRegisters(); + + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); +public: + InterpolateLinearInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(float newRate); +}; + + +/// Linear transposer class that uses floating point arithmetics +class InterpolateLinearFloat : public TransposerBase +{ +protected: + float fract; + + virtual void resetRegisters(); + + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); + +public: + InterpolateLinearFloat(); +}; + +} + +#endif diff --git a/Externals/soundtouch/InterpolateShannon.cpp b/Externals/soundtouch/InterpolateShannon.cpp new file mode 100644 index 0000000000..1085fd14cb --- /dev/null +++ b/Externals/soundtouch/InterpolateShannon.cpp @@ -0,0 +1,185 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample interpolation routine using 8-tap band-limited Shannon interpolation +/// with kaiser window. +/// +/// Notice. This algorithm is remarkably much heavier than linear or cubic +/// interpolation, and not remarkably better than cubic algorithm. Thus mostly +/// for experimental purposes +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// $Id: InterpolateShannon.cpp 195 2014-04-06 15:57:21Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include "InterpolateShannon.h" +#include "STTypes.h" + +using namespace soundtouch; + + +/// Kaiser window with beta = 2.0 +/// Values scaled down by 5% to avoid overflows +static const double _kaiser8[8] = +{ + 0.41778693317814, + 0.64888025049173, + 0.83508562409944, + 0.93887857733412, + 0.93887857733412, + 0.83508562409944, + 0.64888025049173, + 0.41778693317814 +}; + + +InterpolateShannon::InterpolateShannon() +{ + fract = 0; +} + + +void InterpolateShannon::resetRegisters() +{ + fract = 0; +} + + +#define PI 3.1415926536 +#define sinc(x) (sin(PI * (x)) / (PI * (x))) + +/// Transpose mono audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 8; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out; + assert(fract < 1.0); + + out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0]; + out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1]; + out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2]; + if (fract < 1e-6) + { + out += psrc[3] * _kaiser8[3]; // sinc(0) = 1 + } + else + { + out += psrc[3] * sinc(- fract) * _kaiser8[3]; + } + out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4]; + out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5]; + out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6]; + out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7]; + + pdest[i] = (SAMPLETYPE)out; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose stereo audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 8; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out0, out1, w; + assert(fract < 1.0); + + w = sinc(-3.0 - fract) * _kaiser8[0]; + out0 = psrc[0] * w; out1 = psrc[1] * w; + w = sinc(-2.0 - fract) * _kaiser8[1]; + out0 += psrc[2] * w; out1 += psrc[3] * w; + w = sinc(-1.0 - fract) * _kaiser8[2]; + out0 += psrc[4] * w; out1 += psrc[5] * w; + w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1 + out0 += psrc[6] * w; out1 += psrc[7] * w; + w = sinc( 1.0 - fract) * _kaiser8[4]; + out0 += psrc[8] * w; out1 += psrc[9] * w; + w = sinc( 2.0 - fract) * _kaiser8[5]; + out0 += psrc[10] * w; out1 += psrc[11] * w; + w = sinc( 3.0 - fract) * _kaiser8[6]; + out0 += psrc[12] * w; out1 += psrc[13] * w; + w = sinc( 4.0 - fract) * _kaiser8[7]; + out0 += psrc[14] * w; out1 += psrc[15] * w; + + pdest[2*i] = (SAMPLETYPE)out0; + pdest[2*i+1] = (SAMPLETYPE)out1; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += 2*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose stereo audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + // not implemented + assert(false); + return 0; +} diff --git a/Externals/soundtouch/InterpolateShannon.h b/Externals/soundtouch/InterpolateShannon.h new file mode 100644 index 0000000000..701640f7db --- /dev/null +++ b/Externals/soundtouch/InterpolateShannon.h @@ -0,0 +1,72 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample interpolation routine using 8-tap band-limited Shannon interpolation +/// with kaiser window. +/// +/// Notice. This algorithm is remarkably much heavier than linear or cubic +/// interpolation, and not remarkably better than cubic algorithm. Thus mostly +/// for experimental purposes +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// $Id: InterpolateShannon.h 179 2014-01-06 18:41:42Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _InterpolateShannon_H_ +#define _InterpolateShannon_H_ + +#include "RateTransposer.h" +#include "STTypes.h" + +namespace soundtouch +{ + +class InterpolateShannon : public TransposerBase +{ +protected: + void resetRegisters(); + int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + int transposeMulti(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + + float fract; + +public: + InterpolateShannon(); +}; + +} + +#endif diff --git a/Externals/soundtouch/PeakFinder.cpp b/Externals/soundtouch/PeakFinder.cpp index 0426b4a677..0479910131 100644 --- a/Externals/soundtouch/PeakFinder.cpp +++ b/Externals/soundtouch/PeakFinder.cpp @@ -11,7 +11,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2012-12-28 19:52:47 +0000 (Fri, 28 Dec 2012) $ +// Last changed : $Date: 2012-12-29 06:52:47 +1100 (Sat, 29 Dec 2012) $ // File revision : $Revision: 4 $ // // $Id: PeakFinder.cpp 164 2012-12-28 19:52:47Z oparviai $ diff --git a/Externals/soundtouch/PeakFinder.h b/Externals/soundtouch/PeakFinder.h index e94a554ed3..b00a2a8206 100644 --- a/Externals/soundtouch/PeakFinder.h +++ b/Externals/soundtouch/PeakFinder.h @@ -9,7 +9,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2011-12-30 20:33:46 +0000 (Fri, 30 Dec 2011) $ +// Last changed : $Date: 2011-12-31 07:33:46 +1100 (Sat, 31 Dec 2011) $ // File revision : $Revision: 4 $ // // $Id: PeakFinder.h 132 2011-12-30 20:33:46Z oparviai $ diff --git a/Externals/soundtouch/RateTransposer.cpp b/Externals/soundtouch/RateTransposer.cpp index 4944c4bf4e..5af10082b1 100644 --- a/Externals/soundtouch/RateTransposer.cpp +++ b/Externals/soundtouch/RateTransposer.cpp @@ -10,10 +10,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2013-06-14 17:34:33 +0000 (Fri, 14 Jun 2013) $ +// Last changed : $Date: 2014-04-07 01:57:21 +1000 (Mon, 07 Apr 2014) $ // File revision : $Revision: 4 $ // -// $Id: RateTransposer.cpp 172 2013-06-14 17:34:33Z oparviai $ +// $Id: RateTransposer.cpp 195 2014-04-06 15:57:21Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -43,95 +43,25 @@ #include #include #include "RateTransposer.h" +#include "InterpolateLinear.h" +#include "InterpolateCubic.h" +#include "InterpolateShannon.h" #include "AAFilter.h" using namespace soundtouch; - -/// A linear samplerate transposer class that uses integer arithmetics. -/// for the transposing. -class RateTransposerInteger : public RateTransposer -{ -protected: - int iSlopeCount; - int iRate; - SAMPLETYPE *sPrevSample; - - virtual void resetRegisters(); - - virtual int transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual int transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples); -public: - RateTransposerInteger(); - virtual ~RateTransposerInteger(); - - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower - /// rate, larger faster rates. - virtual void setRate(float newRate); - -}; - - -/// A linear samplerate transposer class that uses floating point arithmetics -/// for the transposing. -class RateTransposerFloat : public RateTransposer -{ -protected: - float fSlopeCount; - SAMPLETYPE *sPrevSample; - - virtual void resetRegisters(); - - virtual int transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual int transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples); - -public: - RateTransposerFloat(); - virtual ~RateTransposerFloat(); -}; - - - - -// Operator 'new' is overloaded so that it automatically creates a suitable instance -// depending on if we've a MMX/SSE/etc-capable CPU available or not. -void * RateTransposer::operator new(size_t s) -{ - ST_THROW_RT_ERROR("Error in RateTransoser::new: don't use \"new TDStretch\" directly, use \"newInstance\" to create a new instance instead!"); - return newInstance(); -} - - -RateTransposer *RateTransposer::newInstance() -{ -#ifdef SOUNDTOUCH_INTEGER_SAMPLES - return ::new RateTransposerInteger; -#else - return ::new RateTransposerFloat; -#endif -} +// Define default interpolation algorithm here +TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC; // Constructor RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) { - numChannels = 2; - bUseAAFilter = TRUE; - fRate = 0; + bUseAAFilter = true; - // Instantiates the anti-alias filter with default tap length - // of 32 - pAAFilter = new AAFilter(32); + // Instantiates the anti-alias filter + pAAFilter = new AAFilter(64); + pTransposer = TransposerBase::newInstance(); } @@ -139,19 +69,20 @@ RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) RateTransposer::~RateTransposer() { delete pAAFilter; + delete pTransposer; } /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable -void RateTransposer::enableAAFilter(BOOL newMode) +void RateTransposer::enableAAFilter(bool newMode) { bUseAAFilter = newMode; } /// Returns nonzero if anti-alias filter is enabled. -BOOL RateTransposer::isAAFilterEnabled() const +bool RateTransposer::isAAFilterEnabled() const { return bUseAAFilter; } @@ -170,7 +101,7 @@ void RateTransposer::setRate(float newRate) { double fCutoff; - fRate = newRate; + pTransposer->setRate(newRate); // design a new anti-alias filter if (newRate > 1.0f) @@ -185,22 +116,6 @@ void RateTransposer::setRate(float newRate) } -// Outputs as many samples of the 'outputBuffer' as possible, and if there's -// any room left, outputs also as many of the incoming samples as possible. -// The goal is to drive the outputBuffer empty. -// -// It's allowed for 'output' and 'input' parameters to point to the same -// memory position. -/* -void RateTransposer::flushStoreBuffer() -{ - if (storeBuffer.isEmpty()) return; - - outputBuffer.moveSamples(storeBuffer); -} -*/ - - // Adds 'nSamples' pcs of samples from the 'samples' memory position into // the input of the object. void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples) @@ -209,70 +124,6 @@ void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples) } - -// Transposes up the sample rate, causing the observed playback 'rate' of the -// sound to decrease -void RateTransposer::upsample(const SAMPLETYPE *src, uint nSamples) -{ - uint count, sizeTemp, num; - - // If the parameter 'uRate' value is smaller than 'SCALE', first transpose - // the samples and then apply the anti-alias filter to remove aliasing. - - // First check that there's enough room in 'storeBuffer' - // (+16 is to reserve some slack in the destination buffer) - sizeTemp = (uint)((float)nSamples / fRate + 16.0f); - - // Transpose the samples, store the result into the end of "storeBuffer" - count = transpose(storeBuffer.ptrEnd(sizeTemp), src, nSamples); - storeBuffer.putSamples(count); - - // Apply the anti-alias filter to samples in "store output", output the - // result to "dest" - num = storeBuffer.numSamples(); - count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), - storeBuffer.ptrBegin(), num, (uint)numChannels); - outputBuffer.putSamples(count); - - // Remove the processed samples from "storeBuffer" - storeBuffer.receiveSamples(count); -} - - -// Transposes down the sample rate, causing the observed playback 'rate' of the -// sound to increase -void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples) -{ - uint count, sizeTemp; - - // If the parameter 'uRate' value is larger than 'SCALE', first apply the - // anti-alias filter to remove high frequencies (prevent them from folding - // over the lover frequencies), then transpose. - - // Add the new samples to the end of the storeBuffer - storeBuffer.putSamples(src, nSamples); - - // Anti-alias filter the samples to prevent folding and output the filtered - // data to tempBuffer. Note : because of the FIR filter length, the - // filtering routine takes in 'filter_length' more samples than it outputs. - assert(tempBuffer.isEmpty()); - sizeTemp = storeBuffer.numSamples(); - - count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), - storeBuffer.ptrBegin(), sizeTemp, (uint)numChannels); - - if (count == 0) return; - - // Remove the filtered samples from 'storeBuffer' - storeBuffer.receiveSamples(count); - - // Transpose the samples (+16 is to reserve some slack in the destination buffer) - sizeTemp = (uint)((float)nSamples / fRate + 16.0f); - count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count); - outputBuffer.putSamples(count); -} - - // Transposes sample rate by applying anti-alias filter to prevent folding. // Returns amount of samples returned in the "dest" buffer. // The maximum amount of samples that can be returned at a time is set by @@ -280,51 +131,45 @@ void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples) void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) { uint count; - uint sizeReq; if (nSamples == 0) return; - assert(pAAFilter); + + // Store samples to input buffer + inputBuffer.putSamples(src, nSamples); // If anti-alias filter is turned off, simply transpose without applying // the filter - if (bUseAAFilter == FALSE) + if (bUseAAFilter == false) { - sizeReq = (uint)((float)nSamples / fRate + 1.0f); - count = transpose(outputBuffer.ptrEnd(sizeReq), src, nSamples); - outputBuffer.putSamples(count); + count = pTransposer->transpose(outputBuffer, inputBuffer); return; } + assert(pAAFilter); + // Transpose with anti-alias filter - if (fRate < 1.0f) + if (pTransposer->rate < 1.0f) { - upsample(src, nSamples); + // If the parameter 'Rate' value is smaller than 1, first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // Transpose the samples, store the result to end of "midBuffer" + pTransposer->transpose(midBuffer, inputBuffer); + + // Apply the anti-alias filter for transposed samples in midBuffer + pAAFilter->evaluate(outputBuffer, midBuffer); } else { - downsample(src, nSamples); - } -} + // If the parameter 'Rate' value is larger than 1, first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. + // Apply the anti-alias filter for samples in inputBuffer + pAAFilter->evaluate(midBuffer, inputBuffer); -// Transposes the sample rate of the given samples using linear interpolation. -// Returns the number of samples returned in the "dest" buffer -inline int RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) -{ -#ifndef USE_MULTICH_ALWAYS - if (numChannels == 1) - { - return transposeMono(dest, src, nSamples); - } - else if (numChannels == 2) - { - return transposeStereo(dest, src, nSamples); - } - else -#endif // USE_MULTICH_ALWAYS - { - assert(numChannels > 0); - return transposeMulti(dest, src, nSamples); + // Transpose the AA-filtered samples in "midBuffer" + pTransposer->transpose(outputBuffer, midBuffer); } } @@ -333,17 +178,13 @@ inline int RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, ui void RateTransposer::setChannels(int nChannels) { assert(nChannels > 0); - if (numChannels == nChannels) return; -// assert(nChannels == 1 || nChannels == 2); - numChannels = nChannels; + if (pTransposer->numChannels == nChannels) return; + pTransposer->setChannels(nChannels); - storeBuffer.setChannels(numChannels); - tempBuffer.setChannels(numChannels); - outputBuffer.setChannels(numChannels); - - // Inits the linear interpolation registers - resetRegisters(); + inputBuffer.setChannels(nChannels); + midBuffer.setChannels(nChannels); + outputBuffer.setChannels(nChannels); } @@ -351,7 +192,8 @@ void RateTransposer::setChannels(int nChannels) void RateTransposer::clear() { outputBuffer.clear(); - storeBuffer.clear(); + midBuffer.clear(); + inputBuffer.clear(); } @@ -362,387 +204,99 @@ int RateTransposer::isEmpty() const res = FIFOProcessor::isEmpty(); if (res == 0) return 0; - return storeBuffer.isEmpty(); + return inputBuffer.isEmpty(); } ////////////////////////////////////////////////////////////////////////////// // -// RateTransposerInteger - integer arithmetic implementation +// TransposerBase - Base class for interpolation // -/// fixed-point interpolation routine precision -#define SCALE 65536 - -// Constructor -RateTransposerInteger::RateTransposerInteger() : RateTransposer() +// static function to set interpolation algorithm +void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a) { - // Notice: use local function calling syntax for sake of clarity, - // to indicate the fact that C++ constructor can't call virtual functions. - sPrevSample=0; - RateTransposerInteger::resetRegisters(); - RateTransposerInteger::setRate(1.0f); -} - - -RateTransposerInteger::~RateTransposerInteger() -{ - if (sPrevSample) delete[] sPrevSample; -} - - -void RateTransposerInteger::resetRegisters() -{ - iSlopeCount = 0; - delete[] sPrevSample; - sPrevSample = new SAMPLETYPE[numChannels]; - memset(sPrevSample, 0, numChannels * sizeof(SAMPLETYPE)); -} - - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -int RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) -{ - int i, remain; - LONG_SAMPLETYPE temp, vol1; - - if (nSamples == 0) return 0; // no samples, no work - - remain = nSamples - 1; - i = 0; - - // Process the last sample saved from the previous call first... - while (iSlopeCount <= SCALE) - { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSample[0] + iSlopeCount * src[0]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += iRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - src ++; - remain --; - if (remain == 0) goto end; - } - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[0] * vol1 + iSlopeCount * src[1]; - dest[i] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += iRate; - } -end: - // Store the last sample for the next round - sPrevSample[0] = src[0]; - - return i; + TransposerBase::algorithm = a; } // Transposes the sample rate of the given samples using linear interpolation. -// 'Stereo' version of the routine. Returns the number of samples returned in -// the "dest" buffer -int RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) +// Returns the number of samples returned in the "dest" buffer +int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) { - int i, remain; - LONG_SAMPLETYPE temp, vol1; + int numSrcSamples = src.numSamples(); + int sizeDemand = (int)((float)numSrcSamples / rate) + 8; + int numOutput; + SAMPLETYPE *psrc = src.ptrBegin(); + SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand); - if (nSamples == 0) return 0; // no samples, no work - - remain = nSamples - 1; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (iSlopeCount <= SCALE) +#ifndef USE_MULTICH_ALWAYS + if (numChannels == 1) { - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = vol1 * sPrevSample[0] + iSlopeCount * src[0]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = vol1 * sPrevSample[1] + iSlopeCount * src[1]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - i++; - iSlopeCount += iRate; + numOutput = transposeMono(pdest, psrc, numSrcSamples); } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) + else if (numChannels == 2) { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - remain --; - src += 2; - if (remain == 0) goto end; - } - vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); - temp = src[0] * vol1 + iSlopeCount * src[2]; - dest[2 * i] = (SAMPLETYPE)(temp / SCALE); - temp = src[1] * vol1 + iSlopeCount * src[3]; - dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE); - - i++; - iSlopeCount += iRate; + numOutput = transposeStereo(pdest, psrc, numSrcSamples); + } + else +#endif // USE_MULTICH_ALWAYS + { + assert(numChannels > 0); + numOutput = transposeMulti(pdest, psrc, numSrcSamples); } -end: - // Store the last sample for the next round - sPrevSample[0] = src[0]; - sPrevSample[1] = src[1]; - - return i; + dest.putSamples(numOutput); + src.receiveSamples(numSrcSamples); + return numOutput; } -int RateTransposerInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) +TransposerBase::TransposerBase() { - int i, remaining; - LONG_SAMPLETYPE temp, vol1; - - if (nSamples == 0) return 0; // no samples, no work - - remaining = nSamples - 1; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (iSlopeCount <= SCALE) - { - for (int c = 0; c < numChannels; c ++) - { - vol1 = (SCALE - iSlopeCount); - temp = vol1 * sPrevSample[c] + iSlopeCount * src[c]; - *dest = (SAMPLETYPE)(temp / SCALE); - dest ++; - } - i++; - - iSlopeCount += iRate; - } - // now always (iSlopeCount > SCALE) - iSlopeCount -= SCALE; - - while (1) - { - while (iSlopeCount > SCALE) - { - iSlopeCount -= SCALE; - src += numChannels; - remaining --; - if (remaining == 0) goto end; - } - - for (int c = 0; c < numChannels; c ++) - { - vol1 = (SCALE - iSlopeCount); - temp = src[c] * vol1 + iSlopeCount * src[c + numChannels]; - *dest = (SAMPLETYPE)(temp / SCALE); - dest++; - } - - i++; - iSlopeCount += iRate; - } -end: - // Store the last sample for the next round - memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE)); - - return i; -} - -// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower -// iRate, larger faster iRates. -void RateTransposerInteger::setRate(float newRate) -{ - iRate = (int)(newRate * SCALE + 0.5f); - RateTransposer::setRate(newRate); + numChannels = 0; + rate = 1.0f; } -////////////////////////////////////////////////////////////////////////////// -// -// RateTransposerFloat - floating point arithmetic implementation -// -////////////////////////////////////////////////////////////////////////////// - -// Constructor -RateTransposerFloat::RateTransposerFloat() : RateTransposer() +TransposerBase::~TransposerBase() { - // Notice: use local function calling syntax for sake of clarity, - // to indicate the fact that C++ constructor can't call virtual functions. - sPrevSample = NULL; - RateTransposerFloat::resetRegisters(); - RateTransposerFloat::setRate(1.0f); } -RateTransposerFloat::~RateTransposerFloat() +void TransposerBase::setChannels(int channels) { - delete[] sPrevSample; + numChannels = channels; + resetRegisters(); } -void RateTransposerFloat::resetRegisters() +void TransposerBase::setRate(float newRate) { - fSlopeCount = 0; - delete[] sPrevSample; - sPrevSample = new SAMPLETYPE[numChannels]; - memset(sPrevSample, 0, numChannels * sizeof(SAMPLETYPE)); + rate = newRate; } - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -int RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) +// static factory function +TransposerBase *TransposerBase::newInstance() { - int i, remain; - - remain = 0; - i = 0; - - // Process the last sample saved from the previous call first... - while (fSlopeCount <= 1.0f) +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + // Notice: For integer arithmetics support only linear algorithm (due to simplest calculus) + return ::new InterpolateLinearInteger; +#else + switch (algorithm) { - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[0] + fSlopeCount * src[0]); - i++; - fSlopeCount += fRate; - } - fSlopeCount -= 1.0f; + case LINEAR: + return new InterpolateLinearFloat; - if (nSamples > 1) - { - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - src ++; - remain --; - if (remain == 0) goto end; - } - dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[0] + fSlopeCount * src[1]); - i++; - fSlopeCount += fRate; - } - } -end: - // Store the last sample for the next round - sPrevSample[0] = src[0]; + case CUBIC: + return new InterpolateCubic; - return i; -} - - -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in -// the "dest" buffer -int RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) -{ - int i, remain; - - if (nSamples == 0) return 0; // no samples, no work - - remain = nSamples - 1; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (fSlopeCount <= 1.0f) - { - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[0] + fSlopeCount * src[0]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[1] + fSlopeCount * src[1]); - i++; - fSlopeCount += fRate; - } - // now always (iSlopeCount > 1.0f) - fSlopeCount -= 1.0f; - - if (nSamples > 1) - { - while (1) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - remain --; - src += 2; - if (remain == 0) goto end; - } - - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[0] - + fSlopeCount * src[2]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[1] - + fSlopeCount * src[3]); - - i++; - fSlopeCount += fRate; - } - } -end: - // Store the last sample for the next round - sPrevSample[0] = src[0]; - sPrevSample[1] = src[1]; - - return i; -} - -int RateTransposerFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) -{ - int i, remaining; - - if (nSamples == 0) return 0; // no samples, no work - - remaining = nSamples - 1; - i = 0; - - // Process the last sample saved from the sPrevSampleLious call first... - while (fSlopeCount <= 1.0f) - { - for (int c = 0; c < numChannels; c ++) - { - *dest = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[c] + fSlopeCount * src[c]); - dest ++; - } - i++; - fSlopeCount += fRate; - } - // now always (iSlopeCount > 1.0f) - fSlopeCount -= 1.0f; - - while (remaining > 0) - { - while (fSlopeCount > 1.0f) - { - fSlopeCount -= 1.0f; - src += numChannels; - remaining --; - if (remaining == 0) goto end; - } - - for (int c = 0; c < numChannels; c ++) - { - *dest = (SAMPLETYPE)((1.0f - fSlopeCount) * src[c] - + fSlopeCount * src[c + numChannels]); - dest++; - } - - i++; - fSlopeCount += fRate; - } - -end: - // Store the last sample for the next round - memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE)); - - return i; + case SHANNON: + return new InterpolateShannon; + + default: + assert(false); + return NULL; + } +#endif } diff --git a/Externals/soundtouch/RateTransposer.h b/Externals/soundtouch/RateTransposer.h index 81cf28ba23..caf97ed540 100644 --- a/Externals/soundtouch/RateTransposer.h +++ b/Externals/soundtouch/RateTransposer.h @@ -14,10 +14,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2013-06-12 15:24:44 +0000 (Wed, 12 Jun 2013) $ +// Last changed : $Date: 2014-04-07 01:57:21 +1000 (Mon, 07 Apr 2014) $ // File revision : $Revision: 4 $ // -// $Id: RateTransposer.h 171 2013-06-12 15:24:44Z oparviai $ +// $Id: RateTransposer.h 195 2014-04-06 15:57:21Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -55,51 +55,71 @@ namespace soundtouch { +/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc) +class TransposerBase +{ +public: + enum ALGORITHM { + LINEAR = 0, + CUBIC, + SHANNON + }; + +protected: + virtual void resetRegisters() = 0; + + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples) = 0; + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples) = 0; + virtual int transposeMulti(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples) = 0; + + static ALGORITHM algorithm; + +public: + float rate; + int numChannels; + + TransposerBase(); + virtual ~TransposerBase(); + + virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src); + virtual void setRate(float newRate); + virtual void setChannels(int channels); + + // static factory function + static TransposerBase *newInstance(); + + // static function to set interpolation algorithm + static void setAlgorithm(ALGORITHM a); +}; + + /// A common linear samplerate transposer class. /// -/// Note: Use function "RateTransposer::newInstance()" to create a new class -/// instance instead of the "new" operator; that function automatically -/// chooses a correct implementation depending on if integer or floating -/// arithmetics are to be used. class RateTransposer : public FIFOProcessor { protected: /// Anti-alias filter object AAFilter *pAAFilter; - - float fRate; - - int numChannels; + TransposerBase *pTransposer; /// Buffer for collecting samples to feed the anti-alias filter between /// two batches - FIFOSampleBuffer storeBuffer; + FIFOSampleBuffer inputBuffer; /// Buffer for keeping samples between transposing & anti-alias filter - FIFOSampleBuffer tempBuffer; + FIFOSampleBuffer midBuffer; /// Output sample buffer FIFOSampleBuffer outputBuffer; - BOOL bUseAAFilter; + bool bUseAAFilter; - virtual void resetRegisters() = 0; - - virtual int transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - virtual int transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples) = 0; - virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) = 0; - inline int transpose(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples); - - void downsample(const SAMPLETYPE *src, - uint numSamples); - void upsample(const SAMPLETYPE *src, - uint numSamples); /// Transposes sample rate by applying anti-alias filter to prevent folding. /// Returns amount of samples returned in the "dest" buffer. @@ -108,34 +128,33 @@ protected: void processSamples(const SAMPLETYPE *src, uint numSamples); - public: RateTransposer(); virtual ~RateTransposer(); /// Operator 'new' is overloaded so that it automatically creates a suitable instance /// depending on if we're to use integer or floating point arithmetics. - static void *operator new(size_t s); +// static void *operator new(size_t s); /// Use this function instead of "new" operator to create a new instance of this class. /// This function automatically chooses a correct implementation, depending on if /// integer ot floating point arithmetics are to be used. - static RateTransposer *newInstance(); +// static RateTransposer *newInstance(); /// Returns the output buffer object FIFOSamplePipe *getOutput() { return &outputBuffer; }; /// Returns the store buffer object - FIFOSamplePipe *getStore() { return &storeBuffer; }; +// FIFOSamplePipe *getStore() { return &storeBuffer; }; /// Return anti-alias filter object AAFilter *getAAFilter(); /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable - void enableAAFilter(BOOL newMode); + void enableAAFilter(bool newMode); /// Returns nonzero if anti-alias filter is enabled. - BOOL isAAFilterEnabled() const; + bool isAAFilterEnabled() const; /// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// rate, larger faster rates. diff --git a/Externals/soundtouch/SoundTouch.cpp b/Externals/soundtouch/SoundTouch.cpp index 7c35d86697..94a2b23956 100644 --- a/Externals/soundtouch/SoundTouch.cpp +++ b/Externals/soundtouch/SoundTouch.cpp @@ -41,10 +41,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2013-06-12 15:24:44 +0000 (Wed, 12 Jun 2013) $ +// Last changed : $Date: 2014-04-07 01:57:21 +1000 (Mon, 07 Apr 2014) $ // File revision : $Revision: 4 $ // -// $Id: SoundTouch.cpp 171 2013-06-12 15:24:44Z oparviai $ +// $Id: SoundTouch.cpp 195 2014-04-06 15:57:21Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -97,7 +97,7 @@ SoundTouch::SoundTouch() { // Initialize rate transposer and tempo changer instances - pRateTransposer = RateTransposer::newInstance(); + pRateTransposer = new RateTransposer(); pTDStretch = TDStretch::newInstance(); setOutPipe(pTDStretch); @@ -111,7 +111,7 @@ SoundTouch::SoundTouch() calcEffectiveRateAndTempo(); channels = 0; - bSrateSet = FALSE; + bSrateSet = false; } @@ -255,7 +255,7 @@ void SoundTouch::calcEffectiveRateAndTempo() tempoOut = pTDStretch->getOutput(); tempoOut->moveSamples(*output); // move samples in pitch transposer's store buffer to tempo changer's input - pTDStretch->moveSamples(*pRateTransposer->getStore()); + // deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore()); output = pTDStretch; } @@ -283,7 +283,7 @@ void SoundTouch::calcEffectiveRateAndTempo() // Sets sample rate. void SoundTouch::setSampleRate(uint srate) { - bSrateSet = TRUE; + bSrateSet = true; // set sample rate, leave other tempo changer parameters as they are. pTDStretch->setParameters((int)srate); } @@ -293,7 +293,7 @@ void SoundTouch::setSampleRate(uint srate) // the input of the object. void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) { - if (bSrateSet == FALSE) + if (bSrateSet == false) { ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined"); } @@ -383,13 +383,12 @@ void SoundTouch::flush() pTDStretch->clearInput(); // yet leave the 'tempoChanger' output intouched as that's where the // flushed samples are! - free(buff); } // Changes a setting controlling the processing system behaviour. See the // 'SETTING_...' defines for available setting ID's. -BOOL SoundTouch::setSetting(int settingId, int value) +bool SoundTouch::setSetting(int settingId, int value) { int sampleRate, sequenceMs, seekWindowMs, overlapMs; @@ -400,36 +399,36 @@ BOOL SoundTouch::setSetting(int settingId, int value) { case SETTING_USE_AA_FILTER : // enables / disabless anti-alias filter - pRateTransposer->enableAAFilter((value != 0) ? TRUE : FALSE); - return TRUE; + pRateTransposer->enableAAFilter((value != 0) ? true : false); + return true; case SETTING_AA_FILTER_LENGTH : // sets anti-alias filter length pRateTransposer->getAAFilter()->setLength(value); - return TRUE; + return true; case SETTING_USE_QUICKSEEK : // enables / disables tempo routine quick seeking algorithm - pTDStretch->enableQuickSeek((value != 0) ? TRUE : FALSE); - return TRUE; + pTDStretch->enableQuickSeek((value != 0) ? true : false); + return true; case SETTING_SEQUENCE_MS: // change time-stretch sequence duration parameter pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); - return TRUE; + return true; case SETTING_SEEKWINDOW_MS: // change time-stretch seek window length parameter pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); - return TRUE; + return true; case SETTING_OVERLAP_MS: // change time-stretch overlap length parameter pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); - return TRUE; + return true; default : - return FALSE; + return false; } } diff --git a/Externals/soundtouch/SoundTouch.h b/Externals/soundtouch/SoundTouch.h index d76a7219fd..445334ca33 100644 --- a/Externals/soundtouch/SoundTouch.h +++ b/Externals/soundtouch/SoundTouch.h @@ -79,10 +79,10 @@ namespace soundtouch { /// Soundtouch library version string -#define SOUNDTOUCH_VERSION "1.7.2 (dev)" +#define SOUNDTOUCH_VERSION "1.8.1 (r198)" /// SoundTouch library version id -#define SOUNDTOUCH_VERSION_ID (10702) +#define SOUNDTOUCH_VERSION_ID (10801) // // Available setting IDs for the 'setSetting' & 'get_setting' functions: @@ -248,7 +248,7 @@ public: /// 'SETTING_...' defines for available setting ID's. /// /// \return 'TRUE' if the setting was succesfully changed - BOOL setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. + bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. int value ///< New setting value. ); diff --git a/Externals/soundtouch/SoundTouch.vcxproj b/Externals/soundtouch/SoundTouch.vcxproj index 7d0207d40f..07ad56743f 100644 --- a/Externals/soundtouch/SoundTouch.vcxproj +++ b/Externals/soundtouch/SoundTouch.vcxproj @@ -48,6 +48,9 @@ + + + @@ -62,6 +65,9 @@ + + + @@ -74,4 +80,4 @@ - \ No newline at end of file + diff --git a/Externals/soundtouch/TDStretch.cpp b/Externals/soundtouch/TDStretch.cpp index 292404a91a..5a7acf526e 100644 --- a/Externals/soundtouch/TDStretch.cpp +++ b/Externals/soundtouch/TDStretch.cpp @@ -13,10 +13,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2013-06-14 17:34:33 +0000 (Fri, 14 Jun 2013) $ +// Last changed : $Date: 2014-04-07 01:57:21 +1000 (Mon, 07 Apr 2014) $ // File revision : $Revision: 1.12 $ // -// $Id: TDStretch.cpp 172 2013-06-14 17:34:33Z oparviai $ +// $Id: TDStretch.cpp 195 2014-04-06 15:57:21Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -84,15 +84,15 @@ static const short _scanOffsets[5][24]={ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) { - bQuickSeek = FALSE; + bQuickSeek = false; channels = 2; pMidBuffer = NULL; pMidBufferUnaligned = NULL; overlapLength = 0; - bAutoSeqSetting = TRUE; - bAutoSeekSetting = TRUE; + bAutoSeqSetting = true; + bAutoSeekSetting = true; // outDebt = 0; skipFract = 0; @@ -132,23 +132,23 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS, if (aSequenceMS > 0) { this->sequenceMs = aSequenceMS; - bAutoSeqSetting = FALSE; + bAutoSeqSetting = false; } else if (aSequenceMS == 0) { // if zero, use automatic setting - bAutoSeqSetting = TRUE; + bAutoSeqSetting = true; } if (aSeekWindowMS > 0) { this->seekWindowMs = aSeekWindowMS; - bAutoSeekSetting = FALSE; + bAutoSeekSetting = false; } else if (aSeekWindowMS == 0) { // if zero, use automatic setting - bAutoSeekSetting = TRUE; + bAutoSeekSetting = true; } calcSeqParameters(); @@ -231,14 +231,14 @@ void TDStretch::clear() // Enables/disables the quick position seeking algorithm. Zero to disable, nonzero // to enable -void TDStretch::enableQuickSeek(BOOL enable) +void TDStretch::enableQuickSeek(bool enable) { bQuickSeek = enable; } // Returns nonzero if the quick seeking algorithm is enabled. -BOOL TDStretch::isQuickSeekEnabled() const +bool TDStretch::isQuickSeekEnabled() const { return bQuickSeek; } @@ -293,6 +293,7 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) { int bestOffs; double bestCorr, corr; + double norm; int i; bestCorr = FLT_MIN; @@ -300,11 +301,15 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) // Scans for the best correlation value by testing each possible position // over the permitted range. - for (i = 0; i < seekLength; i ++) + bestCorr = calcCrossCorr(refPos, pMidBuffer, norm); + for (i = 1; i < seekLength; i ++) { // Calculates correlation value for the mixing position corresponding - // to 'i' - corr = calcCrossCorr(refPos + channels * i, pMidBuffer); + // to 'i'. Now call "calcCrossCorrAccumulate" that is otherwise same as + // "calcCrossCorr", but saves time by reusing & updating previously stored + // "norm" value + corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm); + // heuristic rule to slightly favour values close to mid of the range double tmp = (double)(2 * i - seekLength) / (double)seekLength; corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp)); @@ -352,12 +357,13 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) j = 0; while (_scanOffsets[scanCount][j]) { + double norm; tempOffset = corrOffset + _scanOffsets[scanCount][j]; if (tempOffset >= seekLength) break; // Calculates correlation value for the mixing position corresponding // to 'tempOffset' - corr = (double)calcCrossCorr(refPos + channels * tempOffset, pMidBuffer); + corr = (double)calcCrossCorr(refPos + channels * tempOffset, pMidBuffer, norm); // heuristic rule to slightly favour values close to mid of the range double tmp = (double)(2 * tempOffset - seekLength) / seekLength; corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp)); @@ -729,32 +735,72 @@ void TDStretch::calculateOverlapLength(int aoverlapMs) } -double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare) const +double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, double &norm) const { long corr; - long norm; + long lnorm; int i; - corr = norm = 0; + corr = lnorm = 0; // Same routine for stereo and mono. For stereo, unroll loop for better // efficiency and gives slightly better resolution against rounding. // For mono it same routine, just unrolls loop by factor of 4 for (i = 0; i < channels * overlapLength; i += 4) { corr += (mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1] + - mixingPos[i + 2] * compare[i + 2] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; // notice: do intermediate division here to avoid integer overflow + corr += (mixingPos[i + 2] * compare[i + 2] + mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBits; - norm += (mixingPos[i] * mixingPos[i] + - mixingPos[i + 1] * mixingPos[i + 1] + - mixingPos[i + 2] * mixingPos[i + 2] + - mixingPos[i + 3] * mixingPos[i + 3]) >> overlapDividerBits; + lnorm += (mixingPos[i] * mixingPos[i] + + mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBits; // notice: do intermediate division here to avoid integer overflow + lnorm += (mixingPos[i + 2] * mixingPos[i + 2] + + mixingPos[i + 3] * mixingPos[i + 3]) >> overlapDividerBits; } // Normalize result by dividing by sqrt(norm) - this step is easiest // done using floating point operation - if (norm == 0) norm = 1; // to avoid div by zero - return (double)corr / sqrt((double)norm); + norm = (double)lnorm; + return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); +} + + +/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value +double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) const +{ + long corr; + long lnorm; + int i; + + // cancel first normalizer tap from previous round + lnorm = 0; + for (i = 1; i <= channels; i ++) + { + lnorm -= (mixingPos[-i] * mixingPos[-i]) >> overlapDividerBits; + } + + corr = 0; + // Same routine for stereo and mono. For stereo, unroll loop for better + // efficiency and gives slightly better resolution against rounding. + // For mono it same routine, just unrolls loop by factor of 4 + for (i = 0; i < channels * overlapLength; i += 4) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; // notice: do intermediate division here to avoid integer overflow + corr += (mixingPos[i + 2] * compare[i + 2] + + mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBits; + } + + // update normalizer with last samples of this round + for (int j = 0; j < channels; j ++) + { + i --; + lnorm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBits; + } + norm += (double)lnorm; + + // Normalize result by dividing by sqrt(norm) - this step is easiest + // done using floating point operation + return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); } #endif // SOUNDTOUCH_INTEGER_SAMPLES @@ -834,10 +880,10 @@ void TDStretch::calculateOverlapLength(int overlapInMsec) } -double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare) const +/// Calculate cross-correlation +double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, double &norm) const { double corr; - double norm; int i; corr = norm = 0; @@ -859,8 +905,43 @@ double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare) co mixingPos[i + 3] * mixingPos[i + 3]; } - if (norm < 1e-9) norm = 1.0; // to avoid div by zero - return corr / sqrt(norm); + return corr / sqrt((norm < 1e-9 ? 1.0 : norm)); } + +/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value +double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) const +{ + double corr; + int i; + + corr = 0; + + // cancel first normalizer tap from previous round + for (i = 1; i <= channels; i ++) + { + norm -= mixingPos[-i] * mixingPos[-i]; + } + + // Same routine for stereo and mono. For Stereo, unroll by factor of 2. + // For mono it's same routine yet unrollsd by factor of 4. + for (i = 0; i < channels * overlapLength; i += 4) + { + corr += mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1] + + mixingPos[i + 2] * compare[i + 2] + + mixingPos[i + 3] * compare[i + 3]; + } + + // update normalizer with last samples of this round + for (int j = 0; j < channels; j ++) + { + i --; + norm += mixingPos[i] * mixingPos[i]; + } + + return corr / sqrt((norm < 1e-9 ? 1.0 : norm)); +} + + #endif // SOUNDTOUCH_FLOAT_SAMPLES diff --git a/Externals/soundtouch/TDStretch.h b/Externals/soundtouch/TDStretch.h index 43610c9d33..aaadee737e 100644 --- a/Externals/soundtouch/TDStretch.h +++ b/Externals/soundtouch/TDStretch.h @@ -13,10 +13,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2013-06-12 15:24:44 +0000 (Wed, 12 Jun 2013) $ +// Last changed : $Date: 2014-04-07 01:57:21 +1000 (Mon, 07 Apr 2014) $ // File revision : $Revision: 4 $ // -// $Id: TDStretch.h 171 2013-06-12 15:24:44Z oparviai $ +// $Id: TDStretch.h 195 2014-04-06 15:57:21Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -125,21 +125,22 @@ protected: float skipFract; FIFOSampleBuffer outputBuffer; FIFOSampleBuffer inputBuffer; - BOOL bQuickSeek; + bool bQuickSeek; int sampleRate; int sequenceMs; int seekWindowMs; int overlapMs; - BOOL bAutoSeqSetting; - BOOL bAutoSeekSetting; + bool bAutoSeqSetting; + bool bAutoSeekSetting; void acceptNewOverlapLength(int newOverlapLength); virtual void clearCrossCorrState(); void calculateOverlapLength(int overlapMs); - virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm) const; + virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm) const; virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos); virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos); @@ -194,10 +195,10 @@ public: /// Enables/disables the quick position seeking algorithm. Zero to disable, /// nonzero to enable - void enableQuickSeek(BOOL enable); + void enableQuickSeek(bool enable); /// Returns nonzero if the quick seeking algorithm is enabled. - BOOL isQuickSeekEnabled() const; + bool isQuickSeekEnabled() const; /// Sets routine control parameters. These control are certain time constants /// defining how the sound is stretched to the desired duration. @@ -248,7 +249,8 @@ public: class TDStretchMMX : public TDStretch { protected: - double calcCrossCorr(const short *mixingPos, const short *compare) const; + double calcCrossCorr(const short *mixingPos, const short *compare, double &norm) const; + double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) const; virtual void overlapStereo(short *output, const short *input) const; virtual void clearCrossCorrState(); }; @@ -260,7 +262,8 @@ public: class TDStretchSSE : public TDStretch { protected: - double calcCrossCorr(const float *mixingPos, const float *compare) const; + double calcCrossCorr(const float *mixingPos, const float *compare, double &norm) const; + double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) const; }; #endif /// SOUNDTOUCH_ALLOW_SSE diff --git a/Externals/soundtouch/cpu_detect.h b/Externals/soundtouch/cpu_detect.h index dc285e90fd..7322619dd0 100644 --- a/Externals/soundtouch/cpu_detect.h +++ b/Externals/soundtouch/cpu_detect.h @@ -12,7 +12,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2008-02-10 16:26:55 +0000 (Sun, 10 Feb 2008) $ +// Last changed : $Date: 2008-02-11 03:26:55 +1100 (Mon, 11 Feb 2008) $ // File revision : $Revision: 4 $ // // $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $ diff --git a/Externals/soundtouch/cpu_detect_x86.cpp b/Externals/soundtouch/cpu_detect_x86.cpp index 1849497560..35b5f32c55 100644 --- a/Externals/soundtouch/cpu_detect_x86.cpp +++ b/Externals/soundtouch/cpu_detect_x86.cpp @@ -11,10 +11,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2012-11-08 18:44:37 +0000 (Thu, 08 Nov 2012) $ +// Last changed : $Date: 2014-01-08 05:24:28 +1100 (Wed, 08 Jan 2014) $ // File revision : $Revision: 4 $ // -// $Id: cpu_detect_x86.cpp 159 2012-11-08 18:44:37Z oparviai $ +// $Id: cpu_detect_x86.cpp 183 2014-01-07 18:24:28Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -42,22 +42,20 @@ #include "cpu_detect.h" #include "STTypes.h" + #if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) - #if defined(__GNUC__) && defined(__i386__) - // gcc - #include "cpuid.h" - #elif defined(_M_IX86) - // windows non-gcc - #include - #endif - #ifndef bit_MMX - #define bit_MMX (1 << 23) - #define bit_MMX (1 << 23) - #define bit_SSE (1 << 25) - #define bit_SSE2 (1 << 26) - #endif + #if defined(__GNUC__) && defined(__i386__) + // gcc + #include "cpuid.h" + #elif defined(_M_IX86) + // windows non-gcc + #include + #endif + #define bit_MMX (1 << 23) + #define bit_SSE (1 << 25) + #define bit_SSE2 (1 << 26) #endif diff --git a/Externals/soundtouch/mmx_optimized.cpp b/Externals/soundtouch/mmx_optimized.cpp index 9b1fc1a41d..0ff6addc2f 100644 --- a/Externals/soundtouch/mmx_optimized.cpp +++ b/Externals/soundtouch/mmx_optimized.cpp @@ -20,10 +20,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2012-11-08 18:53:01 +0000 (Thu, 08 Nov 2012) $ +// Last changed : $Date: 2014-01-08 05:25:40 +1100 (Wed, 08 Jan 2014) $ // File revision : $Revision: 4 $ // -// $Id: mmx_optimized.cpp 160 2012-11-08 18:53:01Z oparviai $ +// $Id: mmx_optimized.cpp 184 2014-01-07 18:25:40Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -68,7 +68,7 @@ using namespace soundtouch; // Calculates cross correlation of two buffers -double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2) const +double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm) const { const __m64 *pVec1, *pVec2; __m64 shifter; @@ -93,19 +93,19 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2) const // _mm_add_pi32 : 2*32bit add // _m_psrad : 32bit right-shift - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), - _mm_madd_pi16(pVec1[1], pVec2[1])); - temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), - _mm_madd_pi16(pVec1[1], pVec1[1])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter)); + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter)); + temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec1[1]), shifter)); + accu = _mm_add_pi32(accu, temp); + normaccu = _mm_add_pi32(normaccu, temp2); - temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), - _mm_madd_pi16(pVec1[3], pVec2[3])); - temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), - _mm_madd_pi16(pVec1[3], pVec1[3])); - accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter)); - normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter)); + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter)); + temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec1[3]), shifter)); + accu = _mm_add_pi32(accu, temp); + normaccu = _mm_add_pi32(normaccu, temp2); pVec1 += 4; pVec2 += 4; @@ -125,14 +125,81 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2) const // Normalize result by dividing by sqrt(norm) - this step is easiest // done using floating point operation - if (norm == 0) norm = 1; // to avoid div by zero + dnorm = (double)norm; - return (double)corr / sqrt((double)norm); + return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm); // Note: Warning about the missing EMMS instruction is harmless // as it'll be called elsewhere. } +/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value +double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm) const +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr, lnorm; + int i; + + // cancel first normalizer tap from previous round + lnorm = 0; + for (i = 1; i <= channels; i ++) + { + lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBits; + } + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBits); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples + // during each round for improved CPU-level parallellization. + for (i = 0; i < channels * overlapLength / 16; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter)); + accu = _mm_add_pi32(accu, temp); + + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter)); + accu = _mm_add_pi32(accu, temp); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + // update normalizer with last samples of this round + pV1 = (short *)pVec1; + for (int j = 1; j <= channels; j ++) + { + lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBits; + } + dnorm += (double)lnorm; + + // Normalize result by dividing by sqrt(norm) - this step is easiest + // done using floating point operation + return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm); +} + void TDStretchMMX::clearCrossCorrState() { diff --git a/Externals/soundtouch/sse_optimized.cpp b/Externals/soundtouch/sse_optimized.cpp index f77ea02dd3..2c72514154 100644 --- a/Externals/soundtouch/sse_optimized.cpp +++ b/Externals/soundtouch/sse_optimized.cpp @@ -23,10 +23,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2012-11-08 18:53:01 +0000 (Thu, 08 Nov 2012) $ +// Last changed : $Date: 2014-01-08 05:25:40 +1100 (Wed, 08 Jan 2014) $ // File revision : $Revision: 4 $ // -// $Id: sse_optimized.cpp 160 2012-11-08 18:53:01Z oparviai $ +// $Id: sse_optimized.cpp 184 2014-01-07 18:25:40Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -71,7 +71,7 @@ using namespace soundtouch; #include // Calculates cross correlation of two buffers -double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2) const +double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &norm) const { int i; const float *pVec1; @@ -141,11 +141,10 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2) const // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] float *pvNorm = (float*)&vNorm; - double norm = sqrt(pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]); - if (norm < 1e-9) norm = 1.0; // to avoid div by zero + norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]); float *pvSum = (float*)&vSum; - return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / norm; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm); /* This is approximately corresponding routine in C-language yet without normalization: double corr, norm; @@ -182,6 +181,16 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2) const } + +double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm) const +{ + // call usual calcCrossCorr function because SSE does not show big benefit of + // accumulating "norm" value, and also the "norm" rolling algorithm would get + // complicated due to SSE-specific alignment-vs-nonexact correlation rules. + return calcCrossCorr(pV1, pV2, norm); +} + + ////////////////////////////////////////////////////////////////////////////// // // implementation of SSE optimized functions of class 'FIRFilter'