diff options
| author | skidau <skidau@gmail.com> | 2014-09-04 22:00:24 +1000 |
|---|---|---|
| committer | skidau <skidau@gmail.com> | 2014-09-04 22:00:24 +1000 |
| commit | e732f27e1af4df6bea2cbf64bf5a9557ee9f28ed (patch) | |
| tree | 7a9c1f529861fd149028b349c7f500d3ae1ccc0b /Externals | |
| parent | 7d39936b4918cd411c85d37a0649dd98b168782c (diff) | |
| parent | ba2bec1c0ab6f29b936048e5d4b57e47ecbad0cb (diff) | |
Merge pull request #953 from skidau/soundtouch-180
Updated SoundTouch library to 1.8.1 [r198]
Diffstat (limited to 'Externals')
27 files changed, 1415 insertions, 696 deletions
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 <stdio.h>
+
+ 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 <stddef.h> +#include <math.h> +#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 <assert.h> +#include <stdlib.h> +#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 <math.h> +#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 <stdlib.h>
#include <stdio.h>
#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;
- storeBuffer.setChannels(numChannels);
- tempBuffer.setChannels(numChannels);
- outputBuffer.setChannels(numChannels);
+ if (pTransposer->numChannels == nChannels) return;
+ pTransposer->setChannels(nChannels);
- // 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()
-{
- // 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)
+// static function to set interpolation algorithm
+void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
{
- 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;
-
- if (nSamples == 0) return 0; // no samples, no work
+ int numSrcSamples = src.numSamples();
+ int sizeDemand = (int)((float)numSrcSamples / rate) + 8;
+ int numOutput;
+ SAMPLETYPE *psrc = src.ptrBegin();
+ SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
- remain = nSamples - 1;
- i = 0;
-
- // Process the last sample saved from the sPrevSampleLious call first...
- while (iSlopeCount <= SCALE)
- {
- 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;
- }
- // now always (iSlopeCount > SCALE)
- iSlopeCount -= SCALE;
-
- while (1)
+#ifndef USE_MULTICH_ALWAYS
+ if (numChannels == 1)
{
- 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 = transposeMono(pdest, psrc, numSrcSamples);
}
-end:
- // Store the last sample for the next round
- sPrevSample[0] = src[0];
- sPrevSample[1] = src[1];
-
- return i;
-}
-
-
-int RateTransposerInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
-{
- 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)
+ else if (numChannels == 2)
{
- 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)
+ numOutput = transposeStereo(pdest, psrc, numSrcSamples);
+ }
+ else
+#endif // USE_MULTICH_ALWAYS
{
- 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;
+ assert(numChannels > 0);
+ numOutput = transposeMulti(pdest, psrc, numSrcSamples);
}
-end:
- // Store the last sample for the next round
- memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE));
-
- return i;
+ dest.putSamples(numOutput);
+ src.receiveSamples(numSrcSamples);
+ return numOutput;
}
-// 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);
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//
-// 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);
+ numChannels = 0;
+ rate = 1.0f;
}
-RateTransposerFloat::~RateTransposerFloat()
+TransposerBase::~TransposerBase()
{
- delete[] sPrevSample;
}
-void RateTransposerFloat::resetRegisters()
+void TransposerBase::setChannels(int channels)
{
- fSlopeCount = 0;
- delete[] sPrevSample;
- sPrevSample = new SAMPLETYPE[numChannels];
- memset(sPrevSample, 0, numChannels * sizeof(SAMPLETYPE));
+ numChannels = channels;
+ resetRegisters();
}
-
-// 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)
+void TransposerBase::setRate(float newRate)
{
- int i, remain;
-
- remain = 0;
- i = 0;
-
- // Process the last sample saved from the previous call first...
- while (fSlopeCount <= 1.0f)
- {
- dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[0] + fSlopeCount * src[0]);
- i++;
- fSlopeCount += fRate;
- }
- fSlopeCount -= 1.0f;
-
- 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];
-
- return i;
+ 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::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
+// static factory function
+TransposerBase *TransposerBase::newInstance()
{
- 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)
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES
+ // Notice: For integer arithmetics support only linear algorithm (due to simplest calculus)
+ return ::new InterpolateLinearInteger;
+#else
+ switch (algorithm)
{
- 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;
+ case LINEAR:
+ return new InterpolateLinearFloat;
- if (nSamples == 0) return 0; // no samples, no work
+ case CUBIC:
+ return new InterpolateCubic;
- 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;
+ case SHANNON:
+ return new InterpolateShannon;
- 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;
+ default:
+ assert(false);
+ return NULL;
}
-
-end:
- // Store the last sample for the next round
- memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE));
-
- return i;
+#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 @@ <ClCompile Include="cpu_detect_x86.cpp" /> <ClCompile Include="FIFOSampleBuffer.cpp" /> <ClCompile Include="FIRFilter.cpp" /> + <ClCompile Include="InterpolateCubic.cpp" /> + <ClCompile Include="InterpolateLinear.cpp" /> + <ClCompile Include="InterpolateShannon.cpp" /> <ClCompile Include="mmx_optimized.cpp" /> <ClCompile Include="PeakFinder.cpp" /> <ClCompile Include="RateTransposer.cpp" /> @@ -62,6 +65,9 @@ <ClInclude Include="FIFOSampleBuffer.h" /> <ClInclude Include="FIFOSamplePipe.h" /> <ClInclude Include="FIRFilter.h" /> + <ClInclude Include="InterpolateCubic.h" /> + <ClInclude Include="InterpolateLinear.h" /> + <ClInclude Include="InterpolateShannon.h" /> <ClInclude Include="PeakFinder.h" /> <ClInclude Include="RateTransposer.h" /> <ClInclude Include="SoundTouch.h" /> @@ -74,4 +80,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project>
\ No newline at end of file +</Project> 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 <intrin.h>
- #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(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
+ #if defined(__GNUC__) && defined(__i386__)
+ // gcc
+ #include "cpuid.h"
+ #elif defined(_M_IX86)
+ // windows non-gcc
+ #include <intrin.h>
+ #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 <math.h>
// 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'
|
