summaryrefslogtreecommitdiffstats
path: root/media/libsoundtouch/src/RateTransposer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libsoundtouch/src/RateTransposer.cpp')
-rw-r--r--media/libsoundtouch/src/RateTransposer.cpp315
1 files changed, 315 insertions, 0 deletions
diff --git a/media/libsoundtouch/src/RateTransposer.cpp b/media/libsoundtouch/src/RateTransposer.cpp
new file mode 100644
index 0000000000..4c202391e0
--- /dev/null
+++ b/media/libsoundtouch/src/RateTransposer.cpp
@@ -0,0 +1,315 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// Sample rate transposer. Changes sample rate by using linear interpolation
+/// together with anti-alias filtering (first order interpolation with anti-
+/// alias filtering should be quite adequate for this application)
+///
+/// Author : Copyright (c) Olli Parviainen
+/// Author e-mail : oparviai 'at' iki.fi
+/// SoundTouch WWW: http://www.surina.net/soundtouch
+///
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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 <memory.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "RateTransposer.h"
+#include "InterpolateLinear.h"
+#include "InterpolateCubic.h"
+#include "InterpolateShannon.h"
+#include "AAFilter.h"
+
+using namespace soundtouch;
+
+// Define default interpolation algorithm here
+TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
+
+
+// Constructor
+RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
+{
+ bUseAAFilter =
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
+ true;
+#else
+ // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
+ false;
+#endif
+
+ // Instantiates the anti-alias filter
+ pAAFilter = new AAFilter(64);
+ pTransposer = TransposerBase::newInstance();
+ clear();
+}
+
+
+RateTransposer::~RateTransposer()
+{
+ delete pAAFilter;
+ delete pTransposer;
+}
+
+
+/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
+void RateTransposer::enableAAFilter(bool newMode)
+{
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
+ // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
+ bUseAAFilter = newMode;
+ clear();
+#endif
+}
+
+
+/// Returns nonzero if anti-alias filter is enabled.
+bool RateTransposer::isAAFilterEnabled() const
+{
+ return bUseAAFilter;
+}
+
+
+AAFilter *RateTransposer::getAAFilter()
+{
+ return pAAFilter;
+}
+
+
+// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
+// iRate, larger faster iRates.
+void RateTransposer::setRate(double newRate)
+{
+ double fCutoff;
+
+ pTransposer->setRate(newRate);
+
+ // design a new anti-alias filter
+ if (newRate > 1.0)
+ {
+ fCutoff = 0.5 / newRate;
+ }
+ else
+ {
+ fCutoff = 0.5 * newRate;
+ }
+ pAAFilter->setCutoffFreq(fCutoff);
+}
+
+
+// Adds 'nSamples' pcs of samples from the 'samples' memory position into
+// the input of the object.
+void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
+{
+ processSamples(samples, nSamples);
+}
+
+
+// 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
+// the 'set_returnBuffer_size' function.
+void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
+{
+ uint count;
+
+ if (nSamples == 0) return;
+
+ // 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)
+ {
+ count = pTransposer->transpose(outputBuffer, inputBuffer);
+ return;
+ }
+
+ assert(pAAFilter);
+
+ // Transpose with anti-alias filter
+ if (pTransposer->rate < 1.0f)
+ {
+ // 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
+ {
+ // 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);
+
+ // Transpose the AA-filtered samples in "midBuffer"
+ pTransposer->transpose(outputBuffer, midBuffer);
+ }
+}
+
+
+// Sets the number of channels, 1 = mono, 2 = stereo
+void RateTransposer::setChannels(int nChannels)
+{
+ if (!verifyNumberOfChannels(nChannels) ||
+ (pTransposer->numChannels == nChannels)) return;
+
+ pTransposer->setChannels(nChannels);
+ inputBuffer.setChannels(nChannels);
+ midBuffer.setChannels(nChannels);
+ outputBuffer.setChannels(nChannels);
+}
+
+
+// Clears all the samples in the object
+void RateTransposer::clear()
+{
+ outputBuffer.clear();
+ midBuffer.clear();
+ inputBuffer.clear();
+ pTransposer->resetRegisters();
+
+ // prefill buffer to avoid losing first samples at beginning of stream
+ int prefill = getLatency();
+ inputBuffer.addSilent(prefill);
+}
+
+
+// Returns nonzero if there aren't any samples available for outputting.
+int RateTransposer::isEmpty() const
+{
+ int res;
+
+ res = FIFOProcessor::isEmpty();
+ if (res == 0) return 0;
+ return inputBuffer.isEmpty();
+}
+
+
+/// Return approximate initial input-output latency
+int RateTransposer::getLatency() const
+{
+ return pTransposer->getLatency() +
+ ((bUseAAFilter) ? (pAAFilter->getLength() / 2) : 0);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// TransposerBase - Base class for interpolation
+//
+
+// static function to set interpolation algorithm
+void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
+{
+ 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)((double)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();
+}
+
+
+void TransposerBase::setRate(double newRate)
+{
+ rate = newRate;
+}
+
+
+// static factory function
+TransposerBase *TransposerBase::newInstance()
+{
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES
+ // Notice: For integer arithmetic 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
+}