123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749 |
- ////////////////////////////////////////////////////////////////////////////////
- ///
- /// 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
- ///
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Last changed : $Date: 2013-06-14 17:34:33 +0000 (Fri, 14 Jun 2013) $
- // File revision : $Revision: 4 $
- //
- // $Id: RateTransposer.cpp 172 2013-06-14 17:34:33Z 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 <memory.h>
- #include <assert.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include "RateTransposer.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
- }
- // Constructor
- RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
- {
- numChannels = 2;
- bUseAAFilter = TRUE;
- fRate = 0;
- // Instantiates the anti-alias filter with default tap length
- // of 32
- pAAFilter = new AAFilter(32);
- }
- RateTransposer::~RateTransposer()
- {
- delete pAAFilter;
- }
- /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
- void RateTransposer::enableAAFilter(BOOL newMode)
- {
- bUseAAFilter = newMode;
- }
- /// 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(float newRate)
- {
- double fCutoff;
- fRate = newRate;
- // design a new anti-alias filter
- if (newRate > 1.0f)
- {
- fCutoff = 0.5f / newRate;
- }
- else
- {
- fCutoff = 0.5f * newRate;
- }
- pAAFilter->setCutoffFreq(fCutoff);
- }
- // 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)
- {
- processSamples(samples, 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
- // the 'set_returnBuffer_size' function.
- void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
- {
- uint count;
- uint sizeReq;
- if (nSamples == 0) return;
- assert(pAAFilter);
- // If anti-alias filter is turned off, simply transpose without applying
- // the filter
- if (bUseAAFilter == FALSE)
- {
- sizeReq = (uint)((float)nSamples / fRate + 1.0f);
- count = transpose(outputBuffer.ptrEnd(sizeReq), src, nSamples);
- outputBuffer.putSamples(count);
- return;
- }
- // Transpose with anti-alias filter
- if (fRate < 1.0f)
- {
- upsample(src, nSamples);
- }
- else
- {
- downsample(src, nSamples);
- }
- }
- // 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);
- }
- }
- // Sets the number of channels, 1 = mono, 2 = stereo
- 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);
- // Inits the linear interpolation registers
- resetRegisters();
- }
- // Clears all the samples in the object
- void RateTransposer::clear()
- {
- outputBuffer.clear();
- storeBuffer.clear();
- }
- // 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 storeBuffer.isEmpty();
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // RateTransposerInteger - integer arithmetic implementation
- //
- /// 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)
- {
- 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 RateTransposerInteger::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 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)
- {
- for (int c = 0; c < numChannels; c ++)
- {
- vol1 = (SCALE - iSlopeCount);
- temp = vol1 * sPrevSample[c] + iSlopeCount * src[c];
- *dest = (SAMPLETYPE)(temp / SCALE);
- dest ++;
- }
- i++;
- iSlopeCount += iRate;
- }
- // now always (iSlopeCount > SCALE)
- iSlopeCount -= SCALE;
- while (1)
- {
- while (iSlopeCount > SCALE)
- {
- iSlopeCount -= SCALE;
- src += numChannels;
- remaining --;
- if (remaining == 0) goto end;
- }
- for (int c = 0; c < numChannels; c ++)
- {
- vol1 = (SCALE - iSlopeCount);
- temp = src[c] * vol1 + iSlopeCount * src[c + numChannels];
- *dest = (SAMPLETYPE)(temp / SCALE);
- dest++;
- }
- i++;
- iSlopeCount += iRate;
- }
- end:
- // Store the last sample for the next round
- memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE));
- return i;
- }
- // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
- // iRate, larger faster iRates.
- void RateTransposerInteger::setRate(float newRate)
- {
- iRate = (int)(newRate * SCALE + 0.5f);
- RateTransposer::setRate(newRate);
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // RateTransposerFloat - floating point arithmetic implementation
- //
- //////////////////////////////////////////////////////////////////////////////
- // Constructor
- RateTransposerFloat::RateTransposerFloat() : RateTransposer()
- {
- // Notice: use local function calling syntax for sake of clarity,
- // to indicate the fact that C++ constructor can't call virtual functions.
- sPrevSample = NULL;
- RateTransposerFloat::resetRegisters();
- RateTransposerFloat::setRate(1.0f);
- }
- RateTransposerFloat::~RateTransposerFloat()
- {
- delete[] sPrevSample;
- }
- void RateTransposerFloat::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 RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
- {
- 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;
- }
- // Transposes the sample rate of the given samples using linear interpolation.
- // 'Mono' version of the routine. Returns the number of samples returned in
- // the "dest" buffer
- int RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
- {
- int i, remain;
- if (nSamples == 0) return 0; // no samples, no work
- remain = nSamples - 1;
- i = 0;
- // Process the last sample saved from the sPrevSampleLious call first...
- while (fSlopeCount <= 1.0f)
- {
- dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[0] + fSlopeCount * src[0]);
- dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[1] + fSlopeCount * src[1]);
- i++;
- fSlopeCount += fRate;
- }
- // now always (iSlopeCount > 1.0f)
- fSlopeCount -= 1.0f;
- if (nSamples > 1)
- {
- while (1)
- {
- while (fSlopeCount > 1.0f)
- {
- fSlopeCount -= 1.0f;
- remain --;
- src += 2;
- if (remain == 0) goto end;
- }
- dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[0]
- + fSlopeCount * src[2]);
- dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[1]
- + fSlopeCount * src[3]);
- i++;
- fSlopeCount += fRate;
- }
- }
- end:
- // Store the last sample for the next round
- sPrevSample[0] = src[0];
- sPrevSample[1] = src[1];
- return i;
- }
- int RateTransposerFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
- {
- int i, remaining;
- if (nSamples == 0) return 0; // no samples, no work
- remaining = nSamples - 1;
- i = 0;
- // Process the last sample saved from the sPrevSampleLious call first...
- while (fSlopeCount <= 1.0f)
- {
- for (int c = 0; c < numChannels; c ++)
- {
- *dest = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSample[c] + fSlopeCount * src[c]);
- dest ++;
- }
- i++;
- fSlopeCount += fRate;
- }
- // now always (iSlopeCount > 1.0f)
- fSlopeCount -= 1.0f;
- while (remaining > 0)
- {
- while (fSlopeCount > 1.0f)
- {
- fSlopeCount -= 1.0f;
- src += numChannels;
- remaining --;
- if (remaining == 0) goto end;
- }
- for (int c = 0; c < numChannels; c ++)
- {
- *dest = (SAMPLETYPE)((1.0f - fSlopeCount) * src[c]
- + fSlopeCount * src[c + numChannels]);
- dest++;
- }
- i++;
- fSlopeCount += fRate;
- }
- end:
- // Store the last sample for the next round
- memcpy(sPrevSample, src, numChannels * sizeof(SAMPLETYPE));
- return i;
- }
|