Implemented separate Cubic, Linear and Shannon interpolation algorithms.

This commit is contained in:
oparviai 2014-01-06 18:40:23 +00:00
parent abfeb3fcc9
commit a09135884a
11 changed files with 1017 additions and 534 deletions

View File

@ -4,6 +4,7 @@
Version="9.00"
Name="soundstretch"
ProjectGUID="{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}"
RootNamespace="soundstretch"
TargetFrameworkVersion="131072"
>
<Platforms>
@ -49,6 +50,7 @@
BasicRuntimeChecks="3"
RuntimeLibrary="1"
StructMemberAlignment="5"
FloatingPointModel="2"
PrecompiledHeaderFile=".\Debug/soundstretch.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
@ -147,6 +149,7 @@
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
PrecompiledHeaderFile=".\Release/soundstretch.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"

View File

@ -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: RateTransposer.h 177 2014-01-05 21:40:22Z 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;
}

View File

@ -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: RateTransposer.h 177 2014-01-05 21:40:22Z 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

View File

@ -0,0 +1,250 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Linear interpolation algorithm.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// $Id: RateTransposer.cpp 177 2014-01-05 21:40:22Z 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)
{
// not yet implemented
assert(FALSE);
return 0;
}
// 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)
{
// not yet implemented
return 0;
}
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 = iFract * src[c] + vol1 * src[c + numChannels];
*dest = (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;
}

View File

@ -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: RateTransposer.h 177 2014-01-05 21:40:22Z 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

View File

@ -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: RateTransposer.h 177 2014-01-05 21:40:22Z 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;
}

View File

@ -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: RateTransposer.h 177 2014-01-05 21:40:22Z 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

View File

@ -28,8 +28,10 @@ noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransp
lib_LTLIBRARIES=libSoundTouch.la
#
libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp BPMDetect.cpp PeakFinder.cpp
libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp \
RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp \
BPMDetect.cpp PeakFinder.cpp InterpolateLinear.cpp InterpolateCubic.cpp \
InterpolateShannon.cpp
# Compiler flags
AM_CXXFLAGS=-O3 -fcheck-new -I../../include

View File

@ -43,131 +43,14 @@
#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 LinearTransposerBase: public TransposerBase
{
protected:
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 numSamples) = 0;
public:
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);
static LinearTransposerBase *newInstance();
};
/// A linear samplerate transposer class that uses integer arithmetics.
/// for the transposing.
class LinearTransposerInteger : public LinearTransposerBase
{
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:
LinearTransposerInteger();
virtual ~LinearTransposerInteger();
/// 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 LinearTransposerFloat : public LinearTransposerBase
{
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:
LinearTransposerFloat();
virtual ~LinearTransposerFloat();
};
TransposerBase::TransposerBase()
{
numChannels = 0;
rate = 1.0f;
}
TransposerBase::~TransposerBase()
{
}
void TransposerBase::setChannels(int channels)
{
numChannels = channels;
resetRegisters();
}
void TransposerBase::setRate(float newRate)
{
rate = newRate;
}
// 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();
}
*/
TransposerBase *TransposerBase::newInstance()
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
return ::new LinearTransposerInteger;
#else
return ::new LinearTransposerFloat;
#endif
}
// Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{
@ -231,22 +114,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::flushinputBuffer()
{
if (inputBuffer.isEmpty()) return;
outputBuffer.moveSamples(inputBuffer);
}
*/
// Adds 'nSamples' pcs of samples from the 'samples' memory position into
// the input of the object.
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
@ -305,37 +172,6 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
}
// Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer
int LinearTransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
{
int numSrcSamples = src.numSamples();
int sizeDemand = (int)((float)numSrcSamples / rate) + 8;
int numOutput;
SAMPLETYPE *psrc = src.ptrBegin();
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
#ifndef USE_MULTICH_ALWAYS
if (numChannels == 1)
{
numOutput = transposeMono(pdest, psrc, numSrcSamples);
}
else if (numChannels == 2)
{
numOutput = transposeStereo(pdest, psrc, numSrcSamples);
}
else
#endif // USE_MULTICH_ALWAYS
{
assert(numChannels > 0);
numOutput = transposeMulti(pdest, psrc, numSrcSamples);
}
dest.putSamples(numOutput);
src.receiveSamples(numOutput);
return numOutput;
}
// Sets the number of channels, 1 = mono, 2 = stereo
void RateTransposer::setChannels(int nChannels)
{
@ -372,381 +208,97 @@ int RateTransposer::isEmpty() const
//////////////////////////////////////////////////////////////////////////////
//
// LinearTransposerInteger - integer arithmetic implementation
// TransposerBase - Base class for interpolation
//
/// fixed-point interpolation routine precision
#define SCALE 65536
// Initialize default algorithm
TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
// Constructor
LinearTransposerInteger::LinearTransposerInteger() : LinearTransposerBase()
// 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;
TransposerBase::algorithm = a;
}
// Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer
int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
{
int numSrcSamples = src.numSamples();
int sizeDemand = (int)((float)numSrcSamples / rate) + 8;
int numOutput;
SAMPLETYPE *psrc = src.ptrBegin();
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
#ifndef USE_MULTICH_ALWAYS
if (numChannels == 1)
{
numOutput = transposeMono(pdest, psrc, numSrcSamples);
}
else if (numChannels == 2)
{
numOutput = transposeStereo(pdest, psrc, numSrcSamples);
}
else
#endif // USE_MULTICH_ALWAYS
{
assert(numChannels > 0);
numOutput = transposeMulti(pdest, psrc, numSrcSamples);
}
dest.putSamples(numOutput);
src.receiveSamples(numSrcSamples);
return numOutput;
}
TransposerBase::TransposerBase()
{
numChannels = 0;
rate = 1.0f;
}
TransposerBase::~TransposerBase()
{
}
void TransposerBase::setChannels(int channels)
{
numChannels = channels;
resetRegisters();
setRate(1.0f);
}
LinearTransposerInteger::~LinearTransposerInteger()
void TransposerBase::setRate(float newRate)
{
if (sPrevSample) delete[] sPrevSample;
rate = newRate;
}
void LinearTransposerInteger::resetRegisters()
// static factory function
TransposerBase *TransposerBase::newInstance()
{
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 LinearTransposerInteger::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;
}
// 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 LinearTransposerInteger::transposeStereo(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 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)
{
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;
}
end:
// Store the last sample for the next round
sPrevSample[0] = src[0];
sPrevSample[1] = src[1];
return i;
}
int LinearTransposerInteger::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)
{
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 LinearTransposerInteger::setRate(float newRate)
{
iRate = (int)(newRate * SCALE + 0.5f);
TransposerBase::setRate(newRate);
}
//////////////////////////////////////////////////////////////////////////////
//
// LinearTransposerFloat - floating point arithmetic implementation
//
//////////////////////////////////////////////////////////////////////////////
// Constructor
LinearTransposerFloat::LinearTransposerFloat() : LinearTransposerBase()
{
// Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions.
sPrevSample = NULL;
resetRegisters();
setRate(1.0f);
}
LinearTransposerFloat::~LinearTransposerFloat()
{
delete[] sPrevSample;
}
void LinearTransposerFloat::resetRegisters()
{
fSlopeCount = 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 LinearTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
int i, remain;
remain = nSamples - 1;
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 += rate;
}
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 += rate;
}
}
end:
// Store the last sample for the next round
sPrevSample[0] = src[0];
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 LinearTransposerFloat::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 += rate;
}
// 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 += rate;
}
}
end:
// Store the last sample for the next round
sPrevSample[0] = src[0];
sPrevSample[1] = src[1];
return i;
}
int LinearTransposerFloat::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 += rate;
}
// 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 += rate;
}
end:
// Store the last sample for the next round
memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE));
return i;
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// Notice: For integer arithmetics support only linear algorithm (due to simplest calculus)
return ::new InterpolateLinearInteger;
#else
switch (algorithm)
{
case LINEAR:
return new InterpolateLinearFloat;
case CUBIC:
return new InterpolateCubic;
case SHANNON:
return new InterpolateShannon;
default:
assert(false);
return NULL;
}
#endif
}

View File

@ -58,9 +58,28 @@ 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;
@ -68,10 +87,15 @@ public:
TransposerBase();
virtual ~TransposerBase();
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) = 0;
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);
};

View File

@ -49,6 +49,7 @@
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
FloatingPointModel="2"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Release/SoundTouch.pch"
AssemblerListingLocation=".\Release/"
@ -124,6 +125,7 @@
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
FloatingPointModel="2"
UsePrecompiledHeader="0"
PrecompiledHeaderFile=".\Debug/SoundTouch.pch"
AssemblerListingLocation=".\Debug/"
@ -257,6 +259,28 @@
BrowseInformation="1"
/>
</FileConfiguration>
<FileConfiguration
Name="debug release|Win32"
>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
/>
</FileConfiguration>
</File>
<File
RelativePath=".\InterpolateCubic.cpp"
>
</File>
<File
RelativePath=".\InterpolateLinear.cpp"
>
</File>
<File
RelativePath=".\InterpolateShannon.cpp"
>
</File>
<File
RelativePath=".\mmx_optimized.cpp"
@ -385,6 +409,18 @@
RelativePath="FIRFilter.h"
>
</File>
<File
RelativePath=".\InterpolateCubic.h"
>
</File>
<File
RelativePath=".\InterpolateLinear.h"
>
</File>
<File
RelativePath=".\InterpolateShannon.h"
>
</File>
<File
RelativePath=".\PeakFinder.h"
>