michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: /// michael@0: /// Cubic interpolation routine. michael@0: /// michael@0: /// Author : Copyright (c) Olli Parviainen michael@0: /// Author e-mail : oparviai 'at' iki.fi michael@0: /// SoundTouch WWW: http://www.surina.net/soundtouch michael@0: /// michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // michael@0: // $Id: InterpolateCubic.cpp 179 2014-01-06 18:41:42Z oparviai $ michael@0: // michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: // michael@0: // License : michael@0: // michael@0: // SoundTouch audio processing library michael@0: // Copyright (c) Olli Parviainen michael@0: // michael@0: // This library is free software; you can redistribute it and/or michael@0: // modify it under the terms of the GNU Lesser General Public michael@0: // License as published by the Free Software Foundation; either michael@0: // version 2.1 of the License, or (at your option) any later version. michael@0: // michael@0: // This library is distributed in the hope that it will be useful, michael@0: // but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: // Lesser General Public License for more details. michael@0: // michael@0: // You should have received a copy of the GNU Lesser General Public michael@0: // License along with this library; if not, write to the Free Software michael@0: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA michael@0: // michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #include michael@0: #include michael@0: #include "InterpolateCubic.h" michael@0: #include "STTypes.h" michael@0: michael@0: using namespace soundtouch; michael@0: michael@0: // cubic interpolation coefficients michael@0: static const float _coeffs[]= michael@0: { -0.5f, 1.0f, -0.5f, 0.0f, michael@0: 1.5f, -2.5f, 0.0f, 1.0f, michael@0: -1.5f, 2.0f, 0.5f, 0.0f, michael@0: 0.5f, -0.5f, 0.0f, 0.0f}; michael@0: michael@0: michael@0: InterpolateCubic::InterpolateCubic() michael@0: { michael@0: fract = 0; michael@0: } michael@0: michael@0: michael@0: void InterpolateCubic::resetRegisters() michael@0: { michael@0: fract = 0; michael@0: } michael@0: michael@0: michael@0: /// Transpose mono audio. Returns number of produced output samples, and michael@0: /// updates "srcSamples" to amount of consumed source samples michael@0: int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, michael@0: const SAMPLETYPE *psrc, michael@0: int &srcSamples) michael@0: { michael@0: int i; michael@0: int srcSampleEnd = srcSamples - 4; michael@0: int srcCount = 0; michael@0: michael@0: i = 0; michael@0: while (srcCount < srcSampleEnd) michael@0: { michael@0: float out; michael@0: const float x3 = 1.0f; michael@0: const float x2 = (float)fract; // x michael@0: const float x1 = x2*x2; // x^2 michael@0: const float x0 = x1*x2; // x^3 michael@0: float y0, y1, y2, y3; michael@0: michael@0: assert(fract < 1.0); michael@0: michael@0: y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; michael@0: y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; michael@0: y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; michael@0: y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; michael@0: michael@0: out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3]; michael@0: michael@0: pdest[i] = (SAMPLETYPE)out; michael@0: i ++; michael@0: michael@0: // update position fraction michael@0: fract += rate; michael@0: // update whole positions michael@0: int whole = (int)fract; michael@0: fract -= whole; michael@0: psrc += whole; michael@0: srcCount += whole; michael@0: } michael@0: srcSamples = srcCount; michael@0: return i; michael@0: } michael@0: michael@0: michael@0: /// Transpose stereo audio. Returns number of produced output samples, and michael@0: /// updates "srcSamples" to amount of consumed source samples michael@0: int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, michael@0: const SAMPLETYPE *psrc, michael@0: int &srcSamples) michael@0: { michael@0: int i; michael@0: int srcSampleEnd = srcSamples - 4; michael@0: int srcCount = 0; michael@0: michael@0: i = 0; michael@0: while (srcCount < srcSampleEnd) michael@0: { michael@0: const float x3 = 1.0f; michael@0: const float x2 = (float)fract; // x michael@0: const float x1 = x2*x2; // x^2 michael@0: const float x0 = x1*x2; // x^3 michael@0: float y0, y1, y2, y3; michael@0: float out0, out1; michael@0: michael@0: assert(fract < 1.0); michael@0: michael@0: y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; michael@0: y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; michael@0: y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; michael@0: y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; michael@0: michael@0: out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6]; michael@0: out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7]; michael@0: michael@0: pdest[2*i] = (SAMPLETYPE)out0; michael@0: pdest[2*i+1] = (SAMPLETYPE)out1; michael@0: i ++; michael@0: michael@0: // update position fraction michael@0: fract += rate; michael@0: // update whole positions michael@0: int whole = (int)fract; michael@0: fract -= whole; michael@0: psrc += 2*whole; michael@0: srcCount += whole; michael@0: } michael@0: srcSamples = srcCount; michael@0: return i; michael@0: } michael@0: michael@0: michael@0: /// Transpose multi-channel audio. Returns number of produced output samples, and michael@0: /// updates "srcSamples" to amount of consumed source samples michael@0: int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, michael@0: const SAMPLETYPE *psrc, michael@0: int &srcSamples) michael@0: { michael@0: int i; michael@0: int srcSampleEnd = srcSamples - 4; michael@0: int srcCount = 0; michael@0: michael@0: i = 0; michael@0: while (srcCount < srcSampleEnd) michael@0: { michael@0: const float x3 = 1.0f; michael@0: const float x2 = (float)fract; // x michael@0: const float x1 = x2*x2; // x^2 michael@0: const float x0 = x1*x2; // x^3 michael@0: float y0, y1, y2, y3; michael@0: michael@0: assert(fract < 1.0); michael@0: michael@0: y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; michael@0: y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; michael@0: y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; michael@0: y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; michael@0: michael@0: for (int c = 0; c < numChannels; c ++) michael@0: { michael@0: float out; michael@0: out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels]; michael@0: pdest[0] = (SAMPLETYPE)out; michael@0: pdest ++; michael@0: } michael@0: i ++; michael@0: michael@0: // update position fraction michael@0: fract += rate; michael@0: // update whole positions michael@0: int whole = (int)fract; michael@0: fract -= whole; michael@0: psrc += numChannels*whole; michael@0: srcCount += whole; michael@0: } michael@0: srcSamples = srcCount; michael@0: return i; michael@0: }