diff --git a/3rdparty/SoundTouch/AAFilter.cpp b/3rdparty/SoundTouch/AAFilter.cpp index c73b2c60b8..860f7d5223 100644 --- a/3rdparty/SoundTouch/AAFilter.cpp +++ b/3rdparty/SoundTouch/AAFilter.cpp @@ -1,9 +1,9 @@ //////////////////////////////////////////////////////////////////////////////// /// /// FIR low-pass (anti-alias) filter with filter coefficient design routine and -/// MMX optimization. -/// -/// Anti-alias filter is used to prevent folding of high frequencies when +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when /// transposing the sample rate with interpolation. /// /// Author : Copyright (c) Olli Parviainen @@ -12,7 +12,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-01-11 13:34:24 +0200 (Sun, 11 Jan 2009) $ +// Last changed : $Date: 2009-01-11 09:34:24 -0200 (dom, 11 jan 2009) $ // File revision : $Revision: 4 $ // // $Id: AAFilter.cpp 45 2009-01-11 11:34:24Z oparviai $ @@ -112,21 +112,21 @@ void AAFilter::calculateCoeffs() work = new double[length]; coeffs = new SAMPLETYPE[length]; - fc2 = 2.0 * cutoffFreq; + fc2 = 2.0 * cutoffFreq; wc = PI * fc2; tempCoeff = TWOPI / (double)length; sum = 0; - for (i = 0; i < length; i ++) + for (i = 0; i < length; i ++) { cntTemp = (double)i - (double)(length / 2); temp = cntTemp * wc; - if (temp != 0) + if (temp != 0) { h = fc2 * sin(temp) / temp; // sinc function - } - else + } + else { h = 1.0; } @@ -135,7 +135,7 @@ void AAFilter::calculateCoeffs() temp = w * h; work[i] = temp; - // calc net sum of coefficients + // calc net sum of coefficients sum += temp; } @@ -151,7 +151,7 @@ void AAFilter::calculateCoeffs() // divided by 16384 scaleCoeff = 16384.0f / sum; - for (i = 0; i < length; i ++) + for (i = 0; i < length; i ++) { // scale & round to nearest integer temp = work[i] * scaleCoeff; @@ -169,8 +169,8 @@ void AAFilter::calculateCoeffs() } -// Applies the filter to the given sequence of samples. -// Note : The amount of outputted samples is by value of 'filter length' +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' // smaller than the amount of input samples. uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const { diff --git a/3rdparty/SoundTouch/AAFilter.h b/3rdparty/SoundTouch/AAFilter.h index d92a3eac59..6b885e371c 100644 --- a/3rdparty/SoundTouch/AAFilter.h +++ b/3rdparty/SoundTouch/AAFilter.h @@ -1,10 +1,10 @@ //////////////////////////////////////////////////////////////////////////////// /// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method /// with several performance-increasing tweaks. /// -/// Anti-alias filter is used to prevent folding of high frequencies when +/// Anti-alias filter is used to prevent folding of high frequencies when /// transposing the sample rate with interpolation. /// /// Author : Copyright (c) Olli Parviainen @@ -13,7 +13,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ +// Last changed : $Date: 2008-02-10 14:26:55 -0200 (dom, 10 fev 2008) $ // File revision : $Revision: 4 $ // // $Id: AAFilter.h 11 2008-02-10 16:26:55Z oparviai $ @@ -67,8 +67,8 @@ public: ~AAFilter(); - /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling - /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the /// frequencies than that. void setCutoffFreq(double newCutoffFreq); @@ -77,12 +77,12 @@ public: uint getLength() const; - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter length' + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' /// smaller than the amount of input samples. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, uint numChannels) const; }; diff --git a/3rdparty/SoundTouch/BPMDetect.cpp b/3rdparty/SoundTouch/BPMDetect.cpp new file mode 100644 index 0000000000..34dbb4730a --- /dev/null +++ b/3rdparty/SoundTouch/BPMDetect.cpp @@ -0,0 +1,370 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2012-08-30 16:45:25 -0300 (qui, 30 ago 2012) $ +// File revision : $Revision: 4 $ +// +// $Id: BPMDetect.cpp 149 2012-08-30 19:45:25Z 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 +#include +#include +#include +#include "FIFOSampleBuffer.h" +#include "PeakFinder.h" +#include "BPMDetect.h" + +using namespace soundtouch; + +#define INPUT_BLOCK_SAMPLES 2048 +#define DECIMATED_BLOCK_SAMPLES 256 + +/// decay constant for calculating RMS volume sliding average approximation +/// (time constant is about 10 sec) +const float avgdecay = 0.99986f; + +/// Normalization coefficient for calculating RMS sliding average approximation. +const float avgnorm = (1 - avgdecay); + + +//////////////////////////////////////////////////////////////////////////////// + +// Enable following define to create bpm analysis file: + +// #define _CREATE_BPM_DEBUG_FILE + +#ifdef _CREATE_BPM_DEBUG_FILE + + #define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt" + + static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff) + { + FILE *fptr = fopen(DEBUGFILE_NAME, "wt"); + int i; + + if (fptr) + { + printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n"); + for (i = minpos; i < maxpos; i ++) + { + fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]); + } + fclose(fptr); + } + } +#else + #define _SaveDebugData(a,b,c,d) +#endif + +//////////////////////////////////////////////////////////////////////////////// + + +BPMDetect::BPMDetect(int numChannels, int aSampleRate) +{ + this->sampleRate = aSampleRate; + this->channels = numChannels; + + decimateSum = 0; + decimateCount = 0; + + envelopeAccu = 0; + + // Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's + // safe initial RMS signal level value for song data. This value is then adapted + // to the actual level during processing. +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + // integer samples + RMSVolumeAccu = (1500 * 1500) / avgnorm; +#else + // float samples, scaled to range [-1..+1[ + RMSVolumeAccu = (0.045f * 0.045f) / avgnorm; +#endif + + // choose decimation factor so that result is approx. 1000 Hz + decimateBy = sampleRate / 1000; + assert(decimateBy > 0); + assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); + + // Calculate window length & starting item according to desired min & max bpms + windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); + windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM); + + assert(windowLen > windowStart); + + // allocate new working objects + xcorr = new float[windowLen]; + memset(xcorr, 0, windowLen * sizeof(float)); + + // allocate processing buffer + buffer = new FIFOSampleBuffer(); + // we do processing in mono mode + buffer->setChannels(1); + buffer->clear(); +} + + + +BPMDetect::~BPMDetect() +{ + delete[] xcorr; + delete buffer; +} + + + +/// convert to mono, low-pass filter & decimate to about 500 Hz. +/// return number of outputted samples. +/// +/// Decimation is used to remove the unnecessary frequencies and thus to reduce +/// the amount of data needed to be processed as calculating autocorrelation +/// function is a very-very heavy operation. +/// +/// Anti-alias filtering is done simply by averaging the samples. This is really a +/// poor-man's anti-alias filtering, but it's not so critical in this kind of application +/// (it'd also be difficult to design a high-quality filter with steep cut-off at very +/// narrow band) +int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) +{ + int count, outcount; + LONG_SAMPLETYPE out; + + assert(channels > 0); + assert(decimateBy > 0); + outcount = 0; + for (count = 0; count < numsamples; count ++) + { + int j; + + // convert to mono and accumulate + for (j = 0; j < channels; j ++) + { + decimateSum += src[j]; + } + src += j; + + decimateCount ++; + if (decimateCount >= decimateBy) + { + // Store every Nth sample only + out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels)); + decimateSum = 0; + decimateCount = 0; +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + // check ranges for sure (shouldn't actually be necessary) + if (out > 32767) + { + out = 32767; + } + else if (out < -32768) + { + out = -32768; + } +#endif // SOUNDTOUCH_INTEGER_SAMPLES + dest[outcount] = (SAMPLETYPE)out; + outcount ++; + } + } + return outcount; +} + + + +// Calculates autocorrelation function of the sample history buffer +void BPMDetect::updateXCorr(int process_samples) +{ + int offs; + SAMPLETYPE *pBuffer; + + assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); + + pBuffer = buffer->ptrBegin(); + for (offs = windowStart; offs < windowLen; offs ++) + { + LONG_SAMPLETYPE sum; + int i; + + sum = 0; + for (i = 0; i < process_samples; i ++) + { + sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary + } +// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients + // if it's desired that the system adapts automatically to + // various bpms, e.g. in processing continouos music stream. + // The 'xcorr_decay' should be a value that's smaller than but + // close to one, and should also depend on 'process_samples' value. + + xcorr[offs] += (float)sum; + } +} + + +// Calculates envelope of the sample data +void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples) +{ + const static double decay = 0.7f; // decay constant for smoothing the envelope + const static double norm = (1 - decay); + + int i; + LONG_SAMPLETYPE out; + double val; + + for (i = 0; i < numsamples; i ++) + { + // calc average RMS volume + RMSVolumeAccu *= avgdecay; + val = (float)fabs((float)samples[i]); + RMSVolumeAccu += val * val; + + // cut amplitudes that are below cutoff ~2 times RMS volume + // (we're interested in peak values, not the silent moments) + if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm)) + { + val = 0; + } + + // smooth amplitude envelope + envelopeAccu *= decay; + envelopeAccu += val; + out = (LONG_SAMPLETYPE)(envelopeAccu * norm); + +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + // cut peaks (shouldn't be necessary though) + if (out > 32767) out = 32767; +#endif // SOUNDTOUCH_INTEGER_SAMPLES + samples[i] = (SAMPLETYPE)out; + } +} + + + +void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) +{ + SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; + + // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration + while (numSamples > 0) + { + int block; + int decSamples; + + block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples; + + // decimate. note that converts to mono at the same time + decSamples = decimate(decimated, samples, block); + samples += block * channels; + numSamples -= block; + + // envelope new samples and add them to buffer + calcEnvelope(decimated, decSamples); + buffer->putSamples(decimated, decSamples); + } + + // when the buffer has enought samples for processing... + if ((int)buffer->numSamples() > windowLen) + { + int processLength; + + // how many samples are processed + processLength = (int)buffer->numSamples() - windowLen; + + // ... calculate autocorrelations for oldest samples... + updateXCorr(processLength); + // ... and remove them from the buffer + buffer->receiveSamples(processLength); + } +} + + + +void BPMDetect::removeBias() +{ + int i; + float minval = 1e12f; // arbitrary large number + + for (i = windowStart; i < windowLen; i ++) + { + if (xcorr[i] < minval) + { + minval = xcorr[i]; + } + } + + for (i = windowStart; i < windowLen; i ++) + { + xcorr[i] -= minval; + } +} + + +float BPMDetect::getBpm() +{ + double peakPos; + double coeff; + PeakFinder peakFinder; + + coeff = 60.0 * ((double)sampleRate / (double)decimateBy); + + // save bpm debug analysis data if debug data enabled + _SaveDebugData(xcorr, windowStart, windowLen, coeff); + + // remove bias from xcorr data + removeBias(); + + // find peak position + peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); + + assert(decimateBy != 0); + if (peakPos < 1e-9) return 0.0; // detection failed. + + // calculate BPM + return (float) (coeff / peakPos); +} diff --git a/3rdparty/SoundTouch/BPMDetect.h b/3rdparty/SoundTouch/BPMDetect.h index 75289c6b9b..88628def06 100644 --- a/3rdparty/SoundTouch/BPMDetect.h +++ b/3rdparty/SoundTouch/BPMDetect.h @@ -14,10 +14,10 @@ /// taking absolute value that's smoothed by sliding average. Signal levels that /// are below a couple of times the general RMS amplitude level are cut away to /// leave only notable peaks there. -/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term /// autocorrelation function of the enveloped signal. -/// - After whole sound data file has been analyzed as above, the bpm level is -/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation /// function, calculates it's precise location and converts this reading to bpm's. /// /// Author : Copyright (c) Olli Parviainen @@ -26,10 +26,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $ +// Last changed : $Date: 2012-08-30 16:53:44 -0300 (qui, 30 ago 2012) $ // File revision : $Revision: 4 $ // -// $Id: BPMDetect.h 63 2009-02-21 16:00:14Z oparviai $ +// $Id: BPMDetect.h 150 2012-08-30 19:53:44Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -67,7 +67,7 @@ namespace soundtouch #define MIN_BPM 29 /// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. -#define MAX_BPM 230 +#define MAX_BPM 200 /// Class for calculating BPM rate for audio data. @@ -76,12 +76,12 @@ class BPMDetect protected: /// Auto-correlation accumulator bins. float *xcorr; - + /// Amplitude envelope sliding average approximation level accumulator - float envelopeAccu; + double envelopeAccu; /// RMS volume sliding average approximation level accumulator - float RMSVolumeAccu; + double RMSVolumeAccu; /// Sample average counter. int decimateCount; @@ -104,12 +104,12 @@ protected: /// Beginning of auto-correlation window: Autocorrelation isn't being updated for /// the first these many correlation bins. int windowStart; - + /// FIFO-buffer for decimated processing samples. soundtouch::FIFOSampleBuffer *buffer; - /// Updates auto-correlation function for given number of decimated samples that - /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe /// though). void updateXCorr(int process_samples /// How many samples are processed. ); @@ -128,6 +128,9 @@ protected: int numsamples ///< Number of samples in buffer ); + /// remove constant bias from xcorr data + void removeBias(); + public: /// Constructor. BPMDetect(int numChannels, ///< Number of channels in sample data. @@ -139,9 +142,9 @@ public: /// Inputs a block of samples for analyzing: Envelopes the samples and then /// updates the autocorrelation estimation. When whole song data has been input - /// in smaller blocks using this function, read the resulting bpm with 'getBpm' - /// function. - /// + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// /// Notice that data in 'samples' array can be disrupted in processing. void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer int numSamples ///< Number of samples in buffer diff --git a/3rdparty/SoundTouch/FIFOSampleBuffer.cpp b/3rdparty/SoundTouch/FIFOSampleBuffer.cpp index a395315ac7..80314d81f9 100644 --- a/3rdparty/SoundTouch/FIFOSampleBuffer.cpp +++ b/3rdparty/SoundTouch/FIFOSampleBuffer.cpp @@ -1,12 +1,12 @@ //////////////////////////////////////////////////////////////////////////////// /// -/// A buffer class for temporarily storaging sound samples, operates as a +/// A buffer class for temporarily storaging sound samples, operates as a /// first-in-first-out pipe. /// -/// Samples are added to the end of the sample buffer with the 'putSamples' +/// Samples are added to the end of the sample buffer with the 'putSamples' /// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// outputted samples from the buffer, as well as grows the buffer size +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size /// whenever necessary. /// /// Author : Copyright (c) Olli Parviainen @@ -15,10 +15,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-27 19:24:42 +0200 (Fri, 27 Feb 2009) $ +// Last changed : $Date: 2012-11-08 16:53:01 -0200 (qui, 08 nov 2012) $ // File revision : $Revision: 4 $ // -// $Id: FIFOSampleBuffer.cpp 68 2009-02-27 17:24:42Z oparviai $ +// $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -47,7 +47,6 @@ #include #include #include -#include #include "FIFOSampleBuffer.h" @@ -63,7 +62,7 @@ FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) samplesInBuffer = 0; bufferPos = 0; channels = (uint)numChannels; - ensureCapacity(32); // allocate initial capacity + ensureCapacity(32); // allocate initial capacity } @@ -89,11 +88,11 @@ void FIFOSampleBuffer::setChannels(int numChannels) // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and -// zeroes this pointer by copying samples from the 'bufferPos' pointer +// zeroes this pointer by copying samples from the 'bufferPos' pointer // location on to the beginning of the buffer. void FIFOSampleBuffer::rewind() { - if (buffer && bufferPos) + if (buffer && bufferPos) { memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); bufferPos = 0; @@ -101,7 +100,7 @@ void FIFOSampleBuffer::rewind() } -// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// Adds 'numSamples' pcs of samples from the 'samples' memory position to // the sample buffer. void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) { @@ -114,7 +113,7 @@ void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) // samples. // // This function is used to update the number of samples in the sample buffer -// when accessing the buffer directly with 'ptrEnd' function. Please be +// when accessing the buffer directly with 'ptrEnd' function. Please be // careful though! void FIFOSampleBuffer::putSamples(uint nSamples) { @@ -126,31 +125,31 @@ void FIFOSampleBuffer::putSamples(uint nSamples) } -// Returns a pointer to the end of the used part of the sample buffer (i.e. -// where the new samples are to be inserted). This function may be used for -// inserting new samples into the sample buffer directly. Please be careful! +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! // // Parameter 'slackCapacity' tells the function how much free capacity (in // terms of samples) there _at least_ should be, in order to the caller to -// succesfully insert all the required samples to the buffer. When necessary, +// succesfully insert all the required samples to the buffer. When necessary, // the function grows the buffer size to comply with this requirement. // -// When using this function as means for inserting new samples, also remember -// to increase the sample count afterwards, by calling the +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the // 'putSamples(numSamples)' function. -SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) { ensureCapacity(samplesInBuffer + slackCapacity); return buffer + samplesInBuffer * channels; } -// Returns a pointer to the beginning of the currently non-outputted samples. -// This function is provided for accessing the output samples directly. +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. // Please be careful! // // When using this function to output samples, also remember to 'remove' the -// outputted samples from the buffer by calling the +// outputted samples from the buffer by calling the // 'receiveSamples(numSamples)' function SAMPLETYPE *FIFOSampleBuffer::ptrBegin() { @@ -167,7 +166,7 @@ void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) { SAMPLETYPE *tempUnaligned, *temp; - if (capacityRequirement > getCapacity()) + if (capacityRequirement > getCapacity()) { // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; @@ -175,10 +174,10 @@ void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; if (tempUnaligned == NULL) { - throw std::runtime_error("Couldn't allocate memory!\n"); + ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); } // Align the buffer to begin at 16byte cache line boundary for optimal performance - temp = (SAMPLETYPE *)(((ulong)tempUnaligned + 15) & (ulong)-16); + temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); if (samplesInBuffer) { memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); @@ -187,8 +186,8 @@ void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) buffer = temp; bufferUnaligned = tempUnaligned; bufferPos = 0; - } - else + } + else { // simply rewind the buffer (if necessary) rewind(); @@ -260,3 +259,16 @@ void FIFOSampleBuffer::clear() samplesInBuffer = 0; bufferPos = 0; } + + +/// allow trimming (downwards) amount of samples in pipeline. +/// Returns adjusted amount of samples +uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) +{ + if (numSamples < samplesInBuffer) + { + samplesInBuffer = numSamples; + } + return samplesInBuffer; +} + diff --git a/3rdparty/SoundTouch/FIFOSampleBuffer.h b/3rdparty/SoundTouch/FIFOSampleBuffer.h index ed31c8db63..5f1eb5f3da 100644 --- a/3rdparty/SoundTouch/FIFOSampleBuffer.h +++ b/3rdparty/SoundTouch/FIFOSampleBuffer.h @@ -1,12 +1,12 @@ //////////////////////////////////////////////////////////////////////////////// /// -/// A buffer class for temporarily storaging sound samples, operates as a +/// A buffer class for temporarily storaging sound samples, operates as a /// first-in-first-out pipe. /// -/// Samples are added to the end of the sample buffer with the 'putSamples' +/// Samples are added to the end of the sample buffer with the 'putSamples' /// function, and are received from the beginning of the buffer by calling -/// the 'receiveSamples' function. The class automatically removes the -/// output samples from the buffer as well as grows the storage size +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size /// whenever necessary. /// /// Author : Copyright (c) Olli Parviainen @@ -15,10 +15,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $ +// Last changed : $Date: 2012-06-13 16:29:53 -0300 (qua, 13 jun 2012) $ // File revision : $Revision: 4 $ // -// $Id: FIFOSampleBuffer.h 63 2009-02-21 16:00:14Z oparviai $ +// $Id: FIFOSampleBuffer.h 143 2012-06-13 19:29:53Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -54,7 +54,7 @@ namespace soundtouch /// Sample buffer working in FIFO (first-in-first-out) principle. The class takes /// care of storage size adjustment and data moving during input/output operations. /// -/// Notice that in case of stereo audio, one sample is considered to consist of +/// Notice that in case of stereo audio, one sample is considered to consist of /// both channel data. class FIFOSampleBuffer : public FIFOSamplePipe { @@ -75,12 +75,12 @@ private: /// Channels, 1=mono, 2=stereo. uint channels; - /// Current position pointer to the buffer. This pointer is increased when samples are + /// Current position pointer to the buffer. This pointer is increased when samples are /// removed from the pipe so that it's necessary to actually rewind buffer (move data) /// only new data when is put to the pipe. uint bufferPos; - /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real /// beginning of the buffer. void rewind(); @@ -100,27 +100,27 @@ public: /// destructor ~FIFOSampleBuffer(); - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. /// Please be careful for not to corrupt the book-keeping! /// /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the + /// output samples from the buffer by calling the /// 'receiveSamples(numSamples)' function virtual SAMPLETYPE *ptrBegin(); - /// Returns a pointer to the end of the used part of the sample buffer (i.e. - /// where the new samples are to be inserted). This function may be used for + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for /// inserting new samples into the sample buffer directly. Please be careful /// not corrupt the book-keeping! /// - /// When using this function as means for inserting new samples, also remember - /// to increase the sample count afterwards, by calling the + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the /// 'putSamples(numSamples)' function. SAMPLETYPE *ptrEnd( - uint slackCapacity ///< How much free capacity (in samples) there _at least_ - ///< should be so that the caller can succesfully insert the - ///< desired samples to the buffer. If necessary, the function + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can succesfully insert the + ///< desired samples to the buffer. If necessary, the function ///< grows the buffer size to comply with this requirement. ); @@ -130,17 +130,17 @@ public: uint numSamples ///< Number of samples to insert. ); - /// Adjusts the book-keeping to increase number of samples in the buffer without + /// Adjusts the book-keeping to increase number of samples in the buffer without /// copying any actual samples. /// /// This function is used to update the number of samples in the sample buffer - /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// when accessing the buffer directly with 'ptrEnd' function. Please be /// careful though! virtual void putSamples(uint numSamples ///< Number of samples been inserted. ); - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than /// 'numsample' samples in the buffer, returns all that available. /// /// \return Number of samples returned. @@ -148,8 +148,8 @@ public: uint maxSamples ///< How many samples to receive at max. ); - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. /// /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// with 'ptrBegin' function. @@ -167,6 +167,10 @@ public: /// Clears all the samples. virtual void clear(); + + /// allow trimming (downwards) amount of samples in pipeline. + /// Returns adjusted amount of samples + uint adjustAmountOfSamples(uint numSamples); }; } diff --git a/3rdparty/SoundTouch/FIFOSamplePipe.h b/3rdparty/SoundTouch/FIFOSamplePipe.h index 31dc40f93d..805e92597e 100644 --- a/3rdparty/SoundTouch/FIFOSamplePipe.h +++ b/3rdparty/SoundTouch/FIFOSamplePipe.h @@ -5,7 +5,7 @@ /// into one end of the pipe with the 'putSamples' function, and the processed /// samples are received from the other end with the 'receiveSamples' function. /// -/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// 'FIFOProcessor' : A base class for classes the do signal processing with /// the samples while operating like a first-in-first-out pipe. When samples /// are input with the 'putSamples' function, the class processes them /// and moves the processed samples to the given 'output' pipe object, which @@ -17,10 +17,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-04-13 16:18:48 +0300 (Mon, 13 Apr 2009) $ +// Last changed : $Date: 2012-06-13 16:29:53 -0300 (qua, 13 jun 2012) $ // File revision : $Revision: 4 $ // -// $Id: FIFOSamplePipe.h 69 2009-04-13 13:18:48Z oparviai $ +// $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -63,12 +63,12 @@ public: virtual ~FIFOSamplePipe() {} - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. /// Please be careful for not to corrupt the book-keeping! /// /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the + /// output samples from the buffer by calling the /// 'receiveSamples(numSamples)' function virtual SAMPLETYPE *ptrBegin() = 0; @@ -89,8 +89,8 @@ public: other.receiveSamples(oNumSamples); }; - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than /// 'numsample' samples in the buffer, returns all that available. /// /// \return Number of samples returned. @@ -98,8 +98,8 @@ public: uint maxSamples ///< How many samples to receive at max. ) = 0; - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. /// /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// with 'ptrBegin' function. @@ -114,16 +114,21 @@ public: /// Clears all the samples. virtual void clear() = 0; + + /// allow trimming (downwards) amount of samples in pipeline. + /// Returns adjusted amount of samples + virtual uint adjustAmountOfSamples(uint numSamples) = 0; + }; -/// Base-class for sound processing routines working in FIFO principle. With this base +/// Base-class for sound processing routines working in FIFO principle. With this base /// class it's easy to implement sound processing stages that can be chained together, -/// so that samples that are fed into beginning of the pipe automatically go through +/// so that samples that are fed into beginning of the pipe automatically go through /// all the processing stages. /// -/// When samples are input to this class, they're first processed and then put to +/// When samples are input to this class, they're first processed and then put to /// the FIFO pipe that's defined as output of this class. This output pipe can be /// either other processing stage or a FIFO sample buffer. class FIFOProcessor :public FIFOSamplePipe @@ -141,7 +146,7 @@ protected: } - /// Constructor. Doesn't define output pipe; it has to be set be + /// Constructor. Doesn't define output pipe; it has to be set be /// 'setOutPipe' function. FIFOProcessor() { @@ -163,12 +168,12 @@ protected: } - /// Returns a pointer to the beginning of the output samples. - /// This function is provided for accessing the output samples directly. + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. /// Please be careful for not to corrupt the book-keeping! /// /// When using this function to output samples, also remember to 'remove' the - /// output samples from the buffer by calling the + /// output samples from the buffer by calling the /// 'receiveSamples(numSamples)' function virtual SAMPLETYPE *ptrBegin() { @@ -177,8 +182,8 @@ protected: public: - /// Output samples from beginning of the sample buffer. Copies requested samples to - /// output buffer and removes them from the sample buffer. If there are less than + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than /// 'numsample' samples in the buffer, returns all that available. /// /// \return Number of samples returned. @@ -190,8 +195,8 @@ public: } - /// Adjusts book-keeping so that given number of samples are removed from beginning of the - /// sample buffer without copying them anywhere. + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. /// /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// with 'ptrBegin' function. @@ -214,6 +219,14 @@ public: { return output->isEmpty(); } + + /// allow trimming (downwards) amount of samples in pipeline. + /// Returns adjusted amount of samples + virtual uint adjustAmountOfSamples(uint numSamples) + { + return output->adjustAmountOfSamples(numSamples); + } + }; } diff --git a/3rdparty/SoundTouch/FIRFilter.cpp b/3rdparty/SoundTouch/FIRFilter.cpp index 9f7351dce8..13a1896ce7 100644 --- a/3rdparty/SoundTouch/FIRFilter.cpp +++ b/3rdparty/SoundTouch/FIRFilter.cpp @@ -1,8 +1,8 @@ //////////////////////////////////////////////////////////////////////////////// /// -/// General FIR digital filter routines with MMX optimization. +/// General FIR digital filter routines with MMX optimization. /// -/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// Note : MMX optimized functions reside in a separate, platform-specific file, /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// /// Author : Copyright (c) Olli Parviainen @@ -11,10 +11,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-25 19:13:51 +0200 (Wed, 25 Feb 2009) $ +// Last changed : $Date: 2011-09-02 15:56:11 -0300 (sex, 02 set 2011) $ // File revision : $Revision: 4 $ // -// $Id: FIRFilter.cpp 67 2009-02-25 17:13:51Z oparviai $ +// $Id: FIRFilter.cpp 131 2011-09-02 18:56:11Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -43,7 +43,6 @@ #include #include #include -#include #include "FIRFilter.h" #include "cpu_detect.h" @@ -75,7 +74,7 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui { uint i, j, end; LONG_SAMPLETYPE suml, sumr; -#ifdef FLOAT_SAMPLES +#ifdef SOUNDTOUCH_FLOAT_SAMPLES // when using floating point samples, use a scaler instead of a divider // because division is much slower operation than multiplying. double dScaler = 1.0 / (double)resultDivider; @@ -88,14 +87,14 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui end = 2 * (numSamples - length); - for (j = 0; j < end; j += 2) + for (j = 0; j < end; j += 2) { const SAMPLETYPE *ptr; suml = sumr = 0; ptr = src + j; - for (i = 0; i < length; i += 4) + for (i = 0; i < length; i += 4) { // loop is unrolled by factor of 4 here for efficiency suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + @@ -108,7 +107,7 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui ptr[2 * i + 7] * filterCoeffs[i + 3]; } -#ifdef INTEGER_SAMPLES +#ifdef SOUNDTOUCH_INTEGER_SAMPLES suml >>= resultDivFactor; sumr >>= resultDivFactor; // saturate to 16 bit integer limits @@ -118,7 +117,7 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui #else suml *= dScaler; sumr *= dScaler; -#endif // INTEGER_SAMPLES +#endif // SOUNDTOUCH_INTEGER_SAMPLES dest[j] = (SAMPLETYPE)suml; dest[j + 1] = (SAMPLETYPE)sumr; } @@ -133,7 +132,7 @@ uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint { uint i, j, end; LONG_SAMPLETYPE sum; -#ifdef FLOAT_SAMPLES +#ifdef SOUNDTOUCH_FLOAT_SAMPLES // when using floating point samples, use a scaler instead of a divider // because division is much slower operation than multiplying. double dScaler = 1.0 / (double)resultDivider; @@ -143,24 +142,24 @@ uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint assert(length != 0); end = numSamples - length; - for (j = 0; j < end; j ++) + for (j = 0; j < end; j ++) { sum = 0; - for (i = 0; i < length; i += 4) + for (i = 0; i < length; i += 4) { // loop is unrolled by factor of 4 here for efficiency - sum += src[i + 0] * filterCoeffs[i + 0] + - src[i + 1] * filterCoeffs[i + 1] + - src[i + 2] * filterCoeffs[i + 2] + + sum += src[i + 0] * filterCoeffs[i + 0] + + src[i + 1] * filterCoeffs[i + 1] + + src[i + 2] * filterCoeffs[i + 2] + src[i + 3] * filterCoeffs[i + 3]; } -#ifdef INTEGER_SAMPLES +#ifdef SOUNDTOUCH_INTEGER_SAMPLES sum >>= resultDivFactor; // saturate to 16 bit integer limits sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; #else sum *= dScaler; -#endif // INTEGER_SAMPLES +#endif // SOUNDTOUCH_INTEGER_SAMPLES dest[j] = (SAMPLETYPE)sum; src ++; } @@ -174,7 +173,7 @@ uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) { assert(newLength > 0); - if (newLength % 8) throw std::runtime_error("FIR filter length not divisible by 8"); + if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); lengthDiv8 = newLength / 8; length = lengthDiv8 * 8; @@ -196,9 +195,9 @@ uint FIRFilter::getLength() const -// Applies the filter to the given sequence of samples. +// Applies the filter to the given sequence of samples. // -// Note : The amount of outputted samples is by value of 'filter_length' +// Note : The amount of outputted samples is by value of 'filter_length' // smaller than the amount of input samples. uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const { @@ -207,7 +206,7 @@ uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSample assert(length > 0); assert(lengthDiv8 * 8 == length); if (numSamples < length) return 0; - if (numChannels == 2) + if (numChannels == 2) { return evaluateFilterStereo(dest, src, numSamples); } else { @@ -217,13 +216,13 @@ uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSample -// Operator 'new' is overloaded so that it automatically creates a suitable instance +// Operator 'new' is overloaded so that it automatically creates a suitable instance // depending on if we've a MMX-capable CPU available or not. void * FIRFilter::operator new(size_t s) { // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! - throw std::runtime_error("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); - return NULL; + ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return newInstance(); } @@ -233,34 +232,25 @@ FIRFilter * FIRFilter::newInstance() uExtensions = detectCPUextensions(); - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + // Check if MMX/SSE instruction set extensions supported by CPU -#ifdef ALLOW_MMX +#ifdef SOUNDTOUCH_ALLOW_MMX // MMX routines available only with integer sample types if (uExtensions & SUPPORT_MMX) { return ::new FIRFilterMMX; } else -#endif // ALLOW_MMX +#endif // SOUNDTOUCH_ALLOW_MMX -#ifdef ALLOW_SSE +#ifdef SOUNDTOUCH_ALLOW_SSE if (uExtensions & SUPPORT_SSE) { // SSE support return ::new FIRFilterSSE; } else -#endif // ALLOW_SSE - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new FIRFilter3DNow; - } - else -#endif // ALLOW_3DNOW +#endif // SOUNDTOUCH_ALLOW_SSE { // ISA optimizations not supported, use plain C version diff --git a/3rdparty/SoundTouch/FIRFilter.h b/3rdparty/SoundTouch/FIRFilter.h index 2899c9bfd7..b593167452 100644 --- a/3rdparty/SoundTouch/FIRFilter.h +++ b/3rdparty/SoundTouch/FIRFilter.h @@ -1,8 +1,8 @@ //////////////////////////////////////////////////////////////////////////////// /// -/// General FIR digital filter routines with MMX optimization. +/// General FIR digital filter routines with MMX optimization. /// -/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// Note : MMX optimized functions reside in a separate, platform-specific file, /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// /// Author : Copyright (c) Olli Parviainen @@ -11,10 +11,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $ +// Last changed : $Date: 2011-02-13 17:13:57 -0200 (dom, 13 fev 2011) $ // File revision : $Revision: 4 $ // -// $Id: FIRFilter.h 63 2009-02-21 16:00:14Z oparviai $ +// $Id: FIRFilter.h 104 2011-02-13 19:13:57Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -48,11 +48,11 @@ namespace soundtouch { -class FIRFilter +class FIRFilter { protected: // Number of FIR filter taps - uint length; + uint length; // Number of FIR filter taps divided by 8 uint lengthDiv8; @@ -65,44 +65,44 @@ protected: // Memory for filter coefficients SAMPLETYPE *filterCoeffs; - virtual uint evaluateFilterStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples) const; - virtual uint evaluateFilterMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples) const; public: FIRFilter(); virtual ~FIRFilter(); - /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// Operator 'new' is overloaded so that it automatically creates a suitable instance /// depending on if we've a MMX-capable CPU available or not. static void * operator new(size_t s); static FIRFilter *newInstance(); - /// Applies the filter to the given sequence of samples. - /// Note : The amount of outputted samples is by value of 'filter_length' + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' /// smaller than the amount of input samples. /// /// \return Number of samples copied to 'dest'. - uint evaluate(SAMPLETYPE *dest, - const SAMPLETYPE *src, - uint numSamples, + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, uint numChannels) const; uint getLength() const; - virtual void setCoefficients(const SAMPLETYPE *coeffs, - uint newLength, + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, uint uResultDivFactor); }; // Optional subclasses that implement CPU-specific optimizations: -#ifdef ALLOW_MMX +#ifdef SOUNDTOUCH_ALLOW_MMX /// Class that implements MMX optimized functions exclusive for 16bit integer samples type. class FIRFilterMMX : public FIRFilter @@ -119,29 +119,10 @@ public: virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); }; -#endif // ALLOW_MMX +#endif // SOUNDTOUCH_ALLOW_MMX -#ifdef ALLOW_3DNOW - - /// Class that implements 3DNow! optimized functions exclusive for floating point samples type. - class FIRFilter3DNow : public FIRFilter - { - protected: - float *filterCoeffsUnalign; - float *filterCoeffsAlign; - - virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; - public: - FIRFilter3DNow(); - ~FIRFilter3DNow(); - virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); - }; - -#endif // ALLOW_3DNOW - - -#ifdef ALLOW_SSE +#ifdef SOUNDTOUCH_ALLOW_SSE /// Class that implements SSE optimized functions exclusive for floating point samples type. class FIRFilterSSE : public FIRFilter { @@ -157,7 +138,7 @@ public: virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); }; -#endif // ALLOW_SSE +#endif // SOUNDTOUCH_ALLOW_SSE } diff --git a/3rdparty/SoundTouch/Makefile.am b/3rdparty/SoundTouch/Makefile.am index eb39bcc96f..709f0cbd23 100644 --- a/3rdparty/SoundTouch/Makefile.am +++ b/3rdparty/SoundTouch/Makefile.am @@ -1,42 +1,71 @@ ## Process this file with automake to create Makefile.in ## -## $Id: Makefile.am,v 1.3 2006/02/05 18:33:34 Olli Exp $ -## -## Copyright (C) 2003 - David W. Durham +## $Id: Makefile.am 138 2012-04-01 20:00:09Z oparviai $ ## ## This file is part of SoundTouch, an audio processing library for pitch/time adjustments -## +## ## SoundTouch is free software; you can redistribute it and/or modify it under the ## terms of the GNU General Public License as published by the Free Software ## Foundation; either version 2 of the License, or (at your option) any later ## version. -## +## ## SoundTouch 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 General Public License for more details. -## +## ## You should have received a copy of the GNU General Public License along with ## this program; if not, write to the Free Software Foundation, Inc., 59 Temple ## Place - Suite 330, Boston, MA 02111-1307, USA -AUTOMAKE_OPTIONS = foreign -noinst_HEADERS=AAFilter.h cpu_detect.h FIRFilter.h RateTransposer.h TDStretch.h cpu_detect_x86_gcc.cpp -noinst_LIBRARIES = libSoundTouch.a +include $(top_srcdir)/config/am_include.mk -libSoundTouch_a_CXXFLAGS = -msse -mmmx -libSoundTouch_a_CFLAGS = -msse -mmmx -#lib_LTLIBRARIES=libSoundTouch.la -# the mmx_gcc.cpp and cpu_detect_x86_gcc.cpp may need to be conditionally included here from things discovered in configure.ac -libSoundTouch_a_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp mmx_optimized.cpp sse_optimized.cpp \ -RateTransposer.cpp SoundTouch.cpp TDStretch.cpp WavFile.cpp cpu_detect_x86_gcc.cpp +# set to something if you want other stuff to be included in the distribution tarball +EXTRA_DIST=SoundTouch.dsp SoundTouch.dsw SoundTouch.sln SoundTouch.vcproj + +noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h + +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 + + +# Compiler flags +AM_CXXFLAGS=-O3 -fcheck-new -I../../include + +# Compile the files that need MMX and SSE individually. +libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la +noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la +libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp +libSoundTouchSSE_la_SOURCES=sse_optimized.cpp + +# We enable optimizations by default. +# If MMX is supported compile with -mmmx. +# Do not assume -msse is also supported. +if HAVE_MMX +libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS) +else +libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS) +endif + +# We enable optimizations by default. +# If SSE is supported compile with -msse. +if HAVE_SSE +libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS) +else +libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS) +endif + +# Let the user disable optimizations if he wishes to. +if !X86_OPTIMIZATIONS +libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS) +libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS) +endif -# ??? test for -fcheck-new in configure.ac -# other compiler flags to add -AM_CXXFLAGS=-O3 -msse -fcheck-new -#-I../../include # other linking flags to add -#libSoundTouch_la_LIBADD= - +# noinst_LTLIBRARIES = libSoundTouchOpt.la +# libSoundTouch_la_LIBADD = libSoundTouchOpt.la +# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp +# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include diff --git a/3rdparty/SoundTouch/PeakFinder.cpp b/3rdparty/SoundTouch/PeakFinder.cpp new file mode 100644 index 0000000000..71203983f6 --- /dev/null +++ b/3rdparty/SoundTouch/PeakFinder.cpp @@ -0,0 +1,276 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Peak detection routine. +/// +/// The routine detects highest value on an array of values and calculates the +/// precise peak location as a mass-center of the 'hump' around the peak value. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2012-12-28 17:52:47 -0200 (sex, 28 dez 2012) $ +// File revision : $Revision: 4 $ +// +// $Id: PeakFinder.cpp 164 2012-12-28 19:52:47Z 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 +#include + +#include "PeakFinder.h" + +using namespace soundtouch; + +#define max(x, y) (((x) > (y)) ? (x) : (y)) + + +PeakFinder::PeakFinder() +{ + minPos = maxPos = 0; +} + + +// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. +int PeakFinder::findTop(const float *data, int peakpos) const +{ + int i; + int start, end; + float refvalue; + + refvalue = data[peakpos]; + + // seek within ±10 points + start = peakpos - 10; + if (start < minPos) start = minPos; + end = peakpos + 10; + if (end > maxPos) end = maxPos; + + for (i = start; i <= end; i ++) + { + if (data[i] > refvalue) + { + peakpos = i; + refvalue = data[i]; + } + } + + // failure if max value is at edges of seek range => it's not peak, it's at slope. + if ((peakpos == start) || (peakpos == end)) return 0; + + return peakpos; +} + + +// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding +// to direction defined by 'direction' until next 'hump' after minimum value will +// begin +int PeakFinder::findGround(const float *data, int peakpos, int direction) const +{ + int lowpos; + int pos; + int climb_count; + float refvalue; + float delta; + + climb_count = 0; + refvalue = data[peakpos]; + lowpos = peakpos; + + pos = peakpos; + + while ((pos > minPos+1) && (pos < maxPos-1)) + { + int prevpos; + + prevpos = pos; + pos += direction; + + // calculate derivate + delta = data[pos] - data[prevpos]; + if (delta <= 0) + { + // going downhill, ok + if (climb_count) + { + climb_count --; // decrease climb count + } + + // check if new minimum found + if (data[pos] < refvalue) + { + // new minimum found + lowpos = pos; + refvalue = data[pos]; + } + } + else + { + // going uphill, increase climbing counter + climb_count ++; + if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit + } + } + return lowpos; +} + + +// Find offset where the value crosses the given level, when starting from 'peakpos' and +// proceeds to direction defined in 'direction' +int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const +{ + float peaklevel; + int pos; + + peaklevel = data[peakpos]; + assert(peaklevel >= level); + pos = peakpos; + while ((pos >= minPos) && (pos < maxPos)) + { + if (data[pos + direction] < level) return pos; // crossing found + pos += direction; + } + return -1; // not found +} + + +// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos' +double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const +{ + int i; + float sum; + float wsum; + + sum = 0; + wsum = 0; + for (i = firstPos; i <= lastPos; i ++) + { + sum += (float)i * data[i]; + wsum += data[i]; + } + + if (wsum < 1e-6) return 0; + return sum / wsum; +} + + + +/// get exact center of peak near given position by calculating local mass of center +double PeakFinder::getPeakCenter(const float *data, int peakpos) const +{ + float peakLevel; // peak level + int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level + float cutLevel; // cutting value + float groundLevel; // ground level of the peak + int gp1, gp2; // bottom positions of the peak 'hump' + + // find ground positions. + gp1 = findGround(data, peakpos, -1); + gp2 = findGround(data, peakpos, 1); + + groundLevel = 0.5f * (data[gp1] + data[gp2]); + peakLevel = data[peakpos]; + + // calculate 70%-level of the peak + cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; + // find mid-level crossings + crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1); + crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1); + + if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak.. + + // calculate mass center of the peak surroundings + return calcMassCenter(data, crosspos1, crosspos2); +} + + + +double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) +{ + + int i; + int peakpos; // position of peak level + double highPeak, peak; + + this->minPos = aminPos; + this->maxPos = amaxPos; + + // find absolute peak + peakpos = minPos; + peak = data[minPos]; + for (i = minPos + 1; i < maxPos; i ++) + { + if (data[i] > peak) + { + peak = data[i]; + peakpos = i; + } + } + + // Calculate exact location of the highest peak mass center + highPeak = getPeakCenter(data, peakpos); + peak = highPeak; + + // Now check if the highest peak were in fact harmonic of the true base beat peak + // - sometimes the highest peak can be Nth harmonic of the true base peak yet + // just a slightly higher than the true base + + for (i = 3; i < 10; i ++) + { + double peaktmp, harmonic; + int i1,i2; + + harmonic = (double)i * 0.5; + peakpos = (int)(highPeak / harmonic + 0.5f); + if (peakpos < minPos) break; + peakpos = findTop(data, peakpos); // seek true local maximum index + if (peakpos == 0) continue; // no local max here + + // calculate mass-center of possible harmonic peak + peaktmp = getPeakCenter(data, peakpos); + + // accept harmonic peak if + // (a) it is found + // (b) is within ±4% of the expected harmonic interval + // (c) has at least half x-corr value of the max. peak + + double diff = harmonic * peaktmp / highPeak; + if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected + + // now compare to highest detected peak + i1 = (int)(highPeak + 0.5); + i2 = (int)(peaktmp + 0.5); + if (data[i2] >= 0.4*data[i1]) + { + // The harmonic is at least half as high primary peak, + // thus use the harmonic peak instead + peak = peaktmp; + } + } + + return peak; +} diff --git a/3rdparty/SoundTouch/PeakFinder.h b/3rdparty/SoundTouch/PeakFinder.h new file mode 100644 index 0000000000..c781643304 --- /dev/null +++ b/3rdparty/SoundTouch/PeakFinder.h @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// The routine detects highest value on an array of values and calculates the +/// precise peak location as a mass-center of the 'hump' around the peak value. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2011-12-30 18:33:46 -0200 (sex, 30 dez 2011) $ +// File revision : $Revision: 4 $ +// +// $Id: PeakFinder.h 132 2011-12-30 20:33:46Z 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 _PeakFinder_H_ +#define _PeakFinder_H_ + +namespace soundtouch +{ + +class PeakFinder +{ +protected: + /// Min, max allowed peak positions within the data vector + int minPos, maxPos; + + /// Calculates the mass center between given vector items. + double calcMassCenter(const float *data, ///< Data vector. + int firstPos, ///< Index of first vector item beloging to the peak. + int lastPos ///< Index of last vector item beloging to the peak. + ) const; + + /// Finds the data vector index where the monotoniously decreasing signal crosses the + /// given level. + int findCrossingLevel(const float *data, ///< Data vector. + float level, ///< Goal crossing level. + int peakpos, ///< Peak position index within the data vector. + int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. + ) const; + + // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. + int findTop(const float *data, int peakpos) const; + + + /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- + /// or left-hand side of the given peak position. + int findGround(const float *data, /// Data vector. + int peakpos, /// Peak position index within the data vector. + int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. + ) const; + + /// get exact center of peak near given position by calculating local mass of center + double getPeakCenter(const float *data, int peakpos) const; + +public: + /// Constructor. + PeakFinder(); + + /// Detect exact peak position of the data vector by finding the largest peak 'hump' + /// and calculating the mass-center location of the peak hump. + /// + /// \return The location of the largest base harmonic peak hump. + double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has + /// to be at least 'maxPos' items long. + int minPos, ///< Min allowed peak location within the vector data. + int maxPos ///< Max allowed peak location within the vector data. + ); +}; + +} + +#endif // _PeakFinder_H_ diff --git a/3rdparty/SoundTouch/README.html b/3rdparty/SoundTouch/README.html index 15a34c8648..5b2bcbb240 100644 --- a/3rdparty/SoundTouch/README.html +++ b/3rdparty/SoundTouch/README.html @@ -1,6 +1,7 @@ + SoundTouch library README @@ -9,32 +10,26 @@ content="Readme file for SoundTouch audio processing library"> - SoundTouch library README - +
-

SoundTouch audio processing library v1.5.0 -

-

SoundTouch library Copyright (c) Olli -Parviainen 2002-2009

+

SoundTouch audio processing library v1.7.1

+

SoundTouch library Copyright © Olli Parviainen 2001-2012


1. Introduction

-

SoundTouch is an open-source audio -processing library that allows changing the sound tempo, pitch -and playback rate parameters independently from each other, i.e.:

+

SoundTouch is an open-source audio processing library that allows +changing the sound tempo, pitch and playback rate parameters +independently from each other, i.e.:

    -
  • Sound tempo can be increased or decreased while -maintaining the original pitch
  • -
  • Sound pitch can be increased or decreased while -maintaining the original tempo
  • -
  • Change playback rate that affects both tempo -and pitch at the same time
  • -
  • Choose any combination of tempo/pitch/rate
  • +
  • Sound tempo can be increased or decreased while maintaining the +original pitch
  • +
  • Sound pitch can be increased or decreased while maintaining the +original tempo
  • +
  • Change playback rate that affects both tempo and pitch at the +same time
  • +
  • Choose any combination of tempo/pitch/rate

1.1 Contact information

Author email: oparviai 'at' iki.fi

@@ -42,50 +37,54 @@ and pitch at the same time

2. Compiling SoundTouch

Before compiling, notice that you can choose the sample data format -if it's desirable to use floating point sample -data instead of 16bit integers. See section "sample data format" -for more information.

+if it's desirable to use floating point sample data instead of 16bit +integers. See section "sample data format" for more information.

2.1. Building in Microsoft Windows

Project files for Microsoft Visual C++ 6.0 and Visual C++ .NET are -supplied with the source code package. 

-

Please notice that SoundTouch -library uses processor-specific optimizations for Pentium III and AMD -processors. Visual Studio .NET and later versions supports the required -instructions by default, but Visual Studio 6.0 requires a processor pack upgrade -to be installed in order to support these optimizations. The processor pack upgrade can be downloaded from -Microsoft site at this URL:

-

http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx

-

If the above URL is unavailable or removed, go -to http://msdn.microsoft.com -and perform a search with keywords "processor pack".

-

To build the binaries with Visual C++ -compiler, either run "make-win.bat" script, or open the -appropriate project files in source code directories with Visual -Studio. The final executable will appear under the "SoundTouch\bin" -directory. If using the Visual Studio IDE instead of the make-win.bat script, directories bin and -lib may need to be created manually to the SoundTouch -package root for the final executables. The make-win.bat script -creates these directories automatically. +supplied with the source code package.

+

Please notice that SoundTouch library uses processor-specific +optimizations for Pentium III and AMD processors. Visual Studio .NET +and later versions supports the required instructions by default, but +Visual Studio 6.0 requires a processor pack upgrade to be installed in +order to support these optimizations. The processor pack upgrade can be +downloaded from Microsoft site at this URL:

+

http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx

+

If the above URL is unavailable or removed, go to http://msdn.microsoft.com and +perform a search with keywords "processor pack".

+

To build the binaries with Visual C++ compiler, either run +"make-win.bat" script, or open the appropriate project files in source +code directories with Visual Studio. The final executable will appear +under the "SoundTouch\bin" directory. If using the Visual Studio IDE +instead of the make-win.bat script, directories bin and lib may need to +be created manually to the SoundTouch package root for the final +executables. The make-win.bat script creates these directories +automatically.

2.2. Building in Gnu platforms

-

The SoundTouch library can be compiled in -practically any platform supporting GNU compiler (GCC) tools. -SoundTouch have been tested with gcc version 3.3.4., but it -shouldn't be very specific about the gcc version. Assembler-level -performance optimizations for GNU platform are currently available in -x86 platforms only, they are automatically disabled and replaced with -standard C routines in other processor platforms.

-

To build and install the binaries, run the -following commands in the SoundTouch/ directory:

+

The SoundTouch library compiles in practically any platform +supporting GNU compiler (GCC) tools. SoundTouch requires GCC version 4.3 or later.

+

To build and install the binaries, run the following commands in +/soundtouch directory:

+ + + + @@ -93,8 +92,7 @@ environment.

make         -
@@ -102,175 +100,163 @@ SoundStretch utility.

make install -
+
./bootstrap  -
+
Creates "configure" file with +local autoconf/automake toolset.
+
./configure  -
-

Configures the SoundTouch package for the local -environment.

+

Configures the SoundTouch package for the local environment. +Notice that "configure" file is not available before running the +"./bootstrap" command as above.
+

-

Builds the SoundTouch library & -SoundStretch utility.

+

Builds the SoundTouch library & SoundStretch utility.

-

Installs the SoundTouch & BPM libraries -to /usr/local/lib and SoundStretch utility to /usr/local/bin. -Please notice that 'root' privileges may be required to install the -binaries to the destination locations.

+

Installs the SoundTouch & BPM libraries to /usr/local/lib +and SoundStretch utility to /usr/local/bin. Please notice that +'root' privileges may be required to install the binaries to the +destination locations.

2.2.1 Required GNU tools 

-

Bash shell, GNU C++ compiler, libtool, autoconf and automake tools are required -for compiling -the SoundTouch library. These are usually included with the GNU/Linux distribution, but if -not, install these packages first. For example, in Ubuntu Linux these can be acquired and -installed with the following command:

-
sudo apt-get install automake autoconf libtool build-essential
+

Bash shell, GNU C++ compiler, libtool, autoconf and automake tools +are required for compiling the SoundTouch library. These are usually +included with the GNU/Linux distribution, but if not, install these +packages first. For example, Ubuntu Linux can acquire and install +these with the following command:

+
sudo apt-get install automake autoconf libtool build-essential

2.2.2 Problems with GCC compiler compatibility

-

At the release time the SoundTouch package has been tested to compile in -GNU/Linux platform. However, in past it's happened that new gcc versions aren't -necessarily compatible with the assembler settings used in the optimized -routines. If you have problems getting the -SoundTouch library compiled, try the workaround of disabling the optimizations -by editing the file "include/STTypes.h" and removing the following -definition there:

+

At the release time the SoundTouch package has been tested to +compile in GNU/Linux platform. However, If you have problems getting the +SoundTouch library compiled, try disabling optimizations that are specific for +x86 processors by running ./configure script with switch

-
#define ALLOW_OPTIMIZATIONS 1
+
--enable-x86-optimizations=no
-

2.2.3 Problems with configure script or build process 

-

Incompatibilities between various GNU toolchain versions may cause errors when running the "configure" script or building the source -codes, if your GNU tool versions are not compatible with the versions used for -preparing the SoundTouch kit. 

-

To resolve the issue, regenerate the configure scripts with your local tool -set by running -the "./bootstrap" script included in the SoundTouch source code -kit. After that, run the configure script and make as usually.

-

2.2.4 Compiler issues with non-x86 processors

-

SoundTouch library works also on non-x86 processors.

-

However, in case that you get compiler errors when trying to compile for non-Intel processor, edit the file -"source\SoundTouch\Makefile.am" and remove the "-msse2" -flag on the AM_CXXFLAGS line:

-
AM_CXXFLAGS=-O3 -fcheck-new -I../../include    # Note: -msse2 flag removed!
-

After that, run "./bootstrap" script, and then run configure -and make again.

+ +Alternatively, if you don't use GNU Configure system, edit file "include/STTypes.h" +directly and remove the following definition:
+
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
+
+ +

2.2.3 Compiling Shared Library / DLL version

+

+ The GNU compilation does not automatically create a shared-library version of + SoundTouch (.so or .dll). If such is desired, then you can create it as follows + after running the usual compilation:

+
+
g++ -shared -static -DDLL_EXPORTS -I../../include -o SoundTouch.dll \
+     SoundTouchDLL.cpp ../SoundTouch/.libs/libSoundTouch.a
+sstrip SoundTouch.dll
+
+ +

2.1. Building in Android

+

Android compilation instructions are within the + source code package, see file "source/Android-lib/README-SoundTouch-Android.html" + in the package.

+
-

3. About implementation & Usage tips

-

3.1. Supported sample data formats

-

The sample data format can be chosen -between 16bit signed integer and 32bit floating point values, the -default is 32bit floating point.

- -

-In Windows environment, the sample data format is chosen -in file "STTypes.h" by choosing one of the following -defines:

+

3. About implementation & Usage tips

3.1. Supported sample data formats

+

The sample data format can be chosen between 16bit signed integer +and 32bit floating point values, the default is 32bit floating point.

+

In Windows environment, the sample data format is chosen in file +"STTypes.h" by choosing one of the following defines:

    -
  • #define INTEGER_SAMPLES -for 16bit signed -integer
  • -
  • #define FLOAT_SAMPLES for -32bit floating point
  • +
  • #define +SOUNDTOUCH_INTEGER_SAMPLES for 16bit signed integer
  • +
  • #define SOUNDTOUCH_FLOAT_SAMPLES for 32bit floating +point
-

-In GNU environment, the floating sample format is used by default, but -integer sample format can be chosen by giving the -following switch to the configure script: +

In GNU environment, the floating sample format is used by default, +but integer sample format can be chosen by giving the following switch +to the configure script:

-
./configure --enable-integer-samples
+
./configure --enable-integer-samples
- -

The sample data can have either single (mono) -or double (stereo) audio channel. Stereo data is interleaved so -that every other data value is for left channel and every second -for right channel. Notice that while it'd be possible in theory -to process stereo sound as two separate mono channels, this isn't -recommended because processing the channels separately would -result in losing the phase coherency between the channels, which -consequently would ruin the stereo effect.

-

Sample rates between 8000-48000H are -supported.

+

The sample data can have either single (mono) or double (stereo) +audio channel. Stereo data is interleaved so that every other data +value is for left channel and every second for right channel. Notice +that while it'd be possible in theory to process stereo sound as two +separate mono channels, this isn't recommended because processing the +channels separately would result in losing the phase coherency between +the channels, which consequently would ruin the stereo effect.

+

Sample rates between 8000-48000H are supported.

3.2. Processing latency

-

The processing and latency constraints of -the SoundTouch library are:

+

The processing and latency constraints of the SoundTouch library are:

    -
  • Input/output processing latency for the -SoundTouch processor is around 100 ms. This is when time-stretching is -used. If the rate transposing effect alone is used, the latency -requirement -is much shorter, see section 'About algorithms'.
  • -
  • Processing CD-quality sound (16bit stereo -sound with 44100H sample rate) in real-time or faster is possible -starting from processors equivalent to Intel Pentium 133Mh or better, -if using the "quick" processing algorithm. If not using the "quick" -mode or -if floating point sample data are being used, several times more CPU -power is typically required.
  • +
  • Input/output processing latency for the SoundTouch processor is +around 100 ms. This is when time-stretching is used. If the rate +transposing effect alone is used, the latency requirement is much +shorter, see section 'About algorithms'.
  • +
  • Processing CD-quality sound (16bit stereo sound with 44100H +sample rate) in real-time or faster is possible starting from +processors equivalent to Intel Pentium 133Mh or better, if using the +"quick" processing algorithm. If not using the "quick" mode or if +floating point sample data are being used, several times more CPU power +is typically required.

3.3. About algorithms

-

SoundTouch provides three seemingly -independent effects: tempo, pitch and playback rate control. -These three controls are implemented as combination of two primary -effects, sample rate transposing and time-stretching.

-

Sample rate transposing affects -both the audio stream duration and pitch. It's implemented simply -by converting the original audio sample stream to the  desired -duration by interpolating from the original audio samples. In SoundTouch, linear interpolation with anti-alias filtering is -used. Theoretically a higher-order interpolation provide better -result than 1st order linear interpolation, but in audio -application linear interpolation together with anti-alias -filtering performs subjectively about as well as higher-order -filtering would.

-

Time-stretching means changing -the audio stream duration without affecting it's pitch. SoundTouch -uses WSOLA-like time-stretching routines that operate in the time -domain. Compared to sample rate transposing, time-stretching is a -much heavier operation and also requires a longer processing -"window" of sound samples used by the -processing algorithm, thus increasing the algorithm input/output -latency. Typical i/o latency for the SoundTouch -time-stretch algorithm is around 100 ms.

-

Sample rate transposing and time-stretching -are then used together to produce the tempo, pitch and rate -controls:

+

SoundTouch provides three seemingly independent effects: tempo, +pitch and playback rate control. These three controls are implemented +as combination of two primary effects, sample rate transposing +and time-stretching.

+

Sample rate transposing affects both the audio stream +duration and pitch. It's implemented simply by converting the original +audio sample stream to the  desired duration by interpolating from +the original audio samples. In SoundTouch, linear interpolation with +anti-alias filtering is used. Theoretically a higher-order +interpolation provide better result than 1st order linear +interpolation, but in audio application linear interpolation together +with anti-alias filtering performs subjectively about as well as +higher-order filtering would.

+

Time-stretching means changing the audio stream duration +without affecting it's pitch. SoundTouch uses WSOLA-like +time-stretching routines that operate in the time domain. Compared to +sample rate transposing, time-stretching is a much heavier operation +and also requires a longer processing "window" of sound samples used by +the processing algorithm, thus increasing the algorithm input/output +latency. Typical i/o latency for the SoundTouch time-stretch algorithm +is around 100 ms.

+

Sample rate transposing and time-stretching are then used together +to produce the tempo, pitch and rate controls:

    -
  • 'Tempo' control is -implemented purely by time-stretching.
  • -
  • 'Rate' control is implemented -purely by sample rate transposing.
  • -
  • 'Pitch' control is -implemented as a combination of time-stretching and sample rate -transposing. For example, to increase pitch the audio stream is first -time-stretched to longer duration (without affecting pitch) and then -transposed back to original duration by sample rate transposing, which -simultaneously reduces duration and increases pitch. The result is -original duration but increased pitch.
  • +
  • 'Tempo' control is implemented purely by +time-stretching.
  • +
  • 'Rate' control is implemented purely by sample +rate transposing.
  • +
  • 'Pitch' control is implemented as a +combination of time-stretching and sample rate transposing. For +example, to increase pitch the audio stream is first time-stretched to +longer duration (without affecting pitch) and then transposed back to +original duration by sample rate transposing, which simultaneously +reduces duration and increases pitch. The result is original duration +but increased pitch.

3.4 Tuning the algorithm parameters

-

The time-stretch algorithm has few -parameters that can be tuned to optimize sound quality for -certain application. The current default parameters have been -chosen by iterative if-then analysis (read: "trial and error") -to obtain best subjective sound quality in pop/rock music -processing, but in applications processing different kind of -sound the default parameter set may result into a sub-optimal -result.

-

The time-stretch algorithm default -parameter values are set by the following #defines in file "TDStretch.h":

+

The time-stretch algorithm has few parameters that can be tuned to +optimize sound quality for certain application. The current default +parameters have been chosen by iterative if-then analysis (read: "trial +and error") to obtain best subjective sound quality in pop/rock music +processing, but in applications processing different kind of sound the +default parameter set may result into a sub-optimal result.

+

The time-stretch algorithm default parameter values are set by the +following #defines in file "TDStretch.h":

-
#define DEFAULT_SEQUENCE_MS     AUTOMATIC
-#define DEFAULT_SEEKWINDOW_MS   AUTOMATIC
-#define DEFAULT_OVERLAP_MS      8
+
#define DEFAULT_SEQUENCE_MS     AUTOMATIC
#define DEFAULT_SEEKWINDOW_MS AUTOMATIC
#define DEFAULT_OVERLAP_MS 8
-

These parameters affect to the time-stretch -algorithm as follows:

+

These parameters affect to the time-stretch algorithm as follows:

    -
  • DEFAULT_SEQUENCE_MS: This is -the default length of a single processing sequence in milliseconds -which determines the how the original sound is chopped in -the time-stretch algorithm. Larger values mean fewer sequences -are used in processing. In principle a larger value sounds better when -slowing down the tempo, but worse when increasing the tempo and vice -versa. 
    +
  • DEFAULT_SEQUENCE_MS: This is the default +length of a single processing sequence in milliseconds which determines +the how the original sound is chopped in the time-stretch algorithm. +Larger values mean fewer sequences are used in processing. In principle +a larger value sounds better when slowing down the tempo, but worse +when increasing the tempo and vice versa. 

    - By default, this setting value is calculated automatically according to - tempo value.
    +By default, this setting value is calculated automatically according to +tempo value.
  • -
  • DEFAULT_SEEKWINDOW_MS: The seeking window +
  • DEFAULT_SEEKWINDOW_MS: The seeking window default length in milliseconds is for the algorithm that seeks the best -possible overlapping location. This determines from how -wide a sample "window" the algorithm can use to find an optimal mixing -location when the sound sequences are to be linked back together. 
    +possible overlapping location. This determines from how wide a sample +"window" the algorithm can use to find an optimal mixing location when +the sound sequences are to be linked back together. 

    The bigger this window setting is, the higher the possibility to find a better mixing position becomes, but at the same time large values may @@ -279,474 +265,513 @@ chosen at more uneven intervals. If there's a disturbing artifact that sounds as if a constant frequency was drifting around, try reducing this setting.

    - By default, this setting value is calculated automatically according to - tempo value.
    +By default, this setting value is calculated automatically according to +tempo value.
  • -
  • DEFAULT_OVERLAP_MS: Overlap -length in milliseconds. When the sound sequences are mixed back -together to form again a continuous sound stream, this parameter -defines how much the ends of the consecutive sequences will overlap with each other.
    +
  • DEFAULT_OVERLAP_MS: Overlap length in +milliseconds. When the sound sequences are mixed back together to form +again a continuous sound stream, this parameter defines how much the +ends of the consecutive sequences will overlap with each other.

    - This shouldn't be that critical parameter. If you reduce the +This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting by a large amount, you might wish to try a smaller value on this.
-

Notice that these parameters can also be -set during execution time with functions "TDStretch::setParameters()" -and "SoundTouch::setSetting()".

-

The table below summaries how the -parameters can be adjusted for different applications:

+

Notice that these parameters can also be set during execution time +with functions "TDStretch::setParameters()" and "SoundTouch::setSetting()".

+

The table below summaries how the parameters can be adjusted for +different applications:

- - - + + + - - - - + + + + - - - - + + + + - + - - + +
Parameter nameDefault value -magnitudeLarger value -affects...Smaller value -affects...Default value magnitudeLarger value affects...Smaller value affects... Effect to CPU burden
SEQUENCE_MS
Default value is relatively -large, chosen for slowing down music tempoLarger value is usually -better for slowing down tempo. Growing the value decelerates the -"echoing" artifact when slowing down the tempo.Smaller value might be better -for speeding up tempo. Reducing the value accelerates the "echoing" -artifact when slowing down the tempo Increasing the parameter -value reduces computation burdenDefault value is relatively large, chosen for +slowing down music tempoLarger value is usually better for slowing down +tempo. Growing the value decelerates the "echoing" artifact when +slowing down the tempo.Smaller value might be better for speeding up +tempo. Reducing the value accelerates the "echoing" artifact when +slowing down the tempo Increasing the parameter value reduces +computation burden
SEEKWINDOW_MS
Default value is relatively -large, chosen for slowing down music tempoLarger value eases finding a -good mixing position, but may cause a "drifting" artifactSmaller reduce possibility to -find a good mixing position, but reduce the "drifting" artifact.Increasing the parameter -value increases computation burdenDefault value is relatively large, chosen for +slowing down music tempoLarger value eases finding a good mixing +position, but may cause a "drifting" artifactSmaller reduce possibility to find a good mixing +position, but reduce the "drifting" artifact.Increasing the parameter value increases +computation burden
OVERLAP_MS
Default value is relatively -large, chosen to suit with above parameters.Default value is relatively large, chosen to +suit with above parameters.  If you reduce the "sequence -ms" setting, you might wish to try a smaller value.Increasing the parameter -value increases computation burdenIf you reduce the "sequence ms" setting, you +might wish to try a smaller value.Increasing the parameter value increases +computation burden

3.5 Performance Optimizations

General optimizations:

-

The time-stretch routine has a 'quick' mode -that substantially speeds up the algorithm but may degrade the -sound quality by a small amount. This mode is activated by -calling SoundTouch::setSetting() function with parameter  id -of SETTING_USE_QUICKSEEK and value "1", i.e.

+

The time-stretch routine has a 'quick' mode that substantially +speeds up the algorithm but may degrade the sound quality by a small +amount. This mode is activated by calling SoundTouch::setSetting() +function with parameter  id of SETTING_USE_QUICKSEEK and value +"1", i.e.

setSetting(SETTING_USE_QUICKSEEK, 1);

CPU-specific optimizations:

    -
  • Intel MMX optimized routines are used with -compatible CPUs when 16bit integer sample type is used. MMX optimizations are available both in Win32 and Gnu/x86 platforms. -Compatible processors are Intel PentiumMMX and later; AMD K6-2, Athlon -and later.
  • -
  • Intel SSE optimized routines are used with -compatible CPUs when floating point sample type is used. SSE optimizations are currently implemented for Win32 platform only. -Processors compatible with SSE extension are Intel processors starting -from Pentium-III, and AMD processors starting from Athlon XP.
  • -
  • AMD 3DNow! optimized routines are used with -compatible CPUs when floating point sample type is used, but SSE -extension isn't supported . 3DNow! optimizations are currently -implemented for Win32 platform only. These optimizations are used in -AMD K6-2 and Athlon (classic) CPU's; better performing SSE routines are -used with AMD processor starting from Athlon XP.
  • +
  • Intel MMX optimized routines are used with compatible CPUs when +16bit integer sample type is used. MMX optimizations are available both +in Win32 and Gnu/x86 platforms. Compatible processors are Intel +PentiumMMX and later; AMD K6-2, Athlon and later.
  • +
  • Intel SSE optimized routines are used with compatible CPUs when +floating point sample type is used. SSE optimizations are currently +implemented for Win32 platform only. Processors compatible with SSE +extension are Intel processors starting from Pentium-III, and AMD +processors starting from Athlon XP.
  • +
  • AMD 3DNow! optimized routines are used with compatible CPUs when +floating point sample type is used, but SSE extension isn't supported . +3DNow! optimizations are currently implemented for Win32 platform only. +These optimizations are used in AMD K6-2 and Athlon (classic) CPU's; +better performing SSE routines are used with AMD processor starting +from Athlon XP.

4. SoundStretch audio processing utility

SoundStretch audio processing utility
-Copyright (c) Olli Parviainen 2002-2009

-

SoundStretch is a simple command-line -application that can change tempo, pitch and playback rates of -WAV sound files. This program is intended primarily to -demonstrate how the "SoundTouch" library can be used to -process sound in your own program, but it can as well be used for -processing sound files.

+ Copyright (c) Olli Parviainen 2002-2012

+

SoundStretch is a simple command-line application that can change +tempo, pitch and playback rates of WAV sound files. This program is +intended primarily to demonstrate how the "SoundTouch" library can be +used to process sound in your own program, but it can as well be used +for processing sound files.

4.1. SoundStretch Usage Instructions

SoundStretch Usage syntax:

soundstretch infilename outfilename [switches]

Where:

- +
- + - + - +
-
"infilename"
+
"infilename"
Name of the input sound -data file (in .WAV audio file format). Give "stdin" as filename to use - standard input pipe. Name of the input sound data file (in .WAV audio +file format). Give "stdin" as filename to use standard input pipe.
-
"outfilename"
+
"outfilename"
Name of the output sound -file where the resulting sound is saved (in .WAV audio file format). -This parameter may be omitted if you  don't want to save the -output -(e.g. when only calculating BPM rate with '-bpm' switch). Give "stdout" - as filename to use standard output pipe.Name of the output sound file where the +resulting sound is saved (in .WAV audio file format). This parameter +may be omitted if you  don't want to save the output (e.g. when +only calculating BPM rate with '-bpm' switch). Give "stdout" as +filename to use standard output pipe.
 [switches]
Are one or more control -switches.Are one or more control switches.

Available control switches are:

- +
- + - + - + - + - + - + - +
-tempo=n 
Change the sound tempo by n -percents (n = -95.0 .. +5000.0 %) Change the sound tempo by n percents (n = -95.0 +.. +5000.0 %)
-pitch=n
Change the sound pitch by n -semitones (n = -60.0 .. + 60.0 semitones) Change the sound pitch by n semitones (n = -60.0 +.. + 60.0 semitones)
-rate=n
Change the sound playback rate by -n percents (n = -95.0 .. +5000.0 %) Change the sound playback rate by n percents (n += -95.0 .. +5000.0 %)
-bpm=n
Detect the Beats-Per-Minute (BPM) rate of the sound and adjust the tempo to meet 'n' - BPMs. When this switch is - applied, the "-tempo" switch is ignored. If "=n" is -omitted, i.e. switch "-bpm" is used alone, then the BPM rate is - estimated and displayed, but tempo not adjusted according to the BPM -value. Detect the Beats-Per-Minute (BPM) rate of the +sound and adjust the tempo to meet 'n' BPMs. When this switch is +applied, the "-tempo" switch is ignored. If "=n" is omitted, i.e. +switch "-bpm" is used alone, then the BPM rate is estimated and +displayed, but tempo not adjusted according to the BPM value.
-quick
Use quicker tempo change -algorithm. Gains speed but loses sound quality. Use quicker tempo change algorithm. Gains speed +but loses sound quality.
-naa
Don't use anti-alias -filtering in sample rate transposing. Gains speed but loses sound -quality. Don't use anti-alias filtering in sample rate +transposing. Gains speed but loses sound quality.
-license
Displays the program license -text (LGPL)Displays the program license text (LGPL)

Notes:

    -
  • To use standard input/output pipes for processing, give "stdin" - and "stdout" as input/output filenames correspondingly. The - standard input/output pipes will still carry the audio data in .wav audio - file format.
  • -
  • The numerical switches allow both integer (e.g. "-tempo=123") and decimal (e.g. -"-tempo=123.45") numbers.
  • -
  • The "-naa" and/or "-quick" switches can be -used to reduce CPU usage while compromising some sound quality
  • -
  • The BPM detection algorithm works by detecting -repeating bass or drum patterns at low frequencies of <250Hz. A - lower-than-expected BPM figure may be reported for music with uneven or - complex bass patterns.
  • +
  • To use standard input/output pipes for processing, give "stdin" +and "stdout" as input/output filenames correspondingly. The standard +input/output pipes will still carry the audio data in .wav audio file +format.
  • +
  • The numerical switches allow both integer (e.g. "-tempo=123") +and decimal (e.g. "-tempo=123.45") numbers.
  • +
  • The "-naa" and/or "-quick" switches can be used to reduce CPU +usage while compromising some sound quality
  • +
  • The BPM detection algorithm works by detecting repeating bass or +drum patterns at low frequencies of <250Hz. A lower-than-expected +BPM figure may be reported for music with uneven or complex bass +patterns.

4.2. SoundStretch usage examples

Example 1

-

The following command increases tempo of -the sound file "originalfile.wav" by 12.5% and stores result to file "destinationfile.wav":

+

The following command increases tempo of the sound file +"originalfile.wav" by 12.5% and stores result to file +"destinationfile.wav":

soundstretch originalfile.wav destinationfile.wav -tempo=12.5

Example 2

-

The following command decreases the sound -pitch (key) of the sound file "orig.wav" by two -semitones and stores the result to file "dest.wav":

+

The following command decreases the sound pitch (key) of the sound +file "orig.wav" by two semitones and stores the result to file +"dest.wav":

soundstretch orig.wav dest.wav -pitch=-2

Example 3

-

The following command processes the file "orig.wav" by decreasing the sound tempo by 25.3% and -increasing the sound pitch (key) by 1.5 semitones. Resulting .wav audio data is -directed to standard output pipe:

+

The following command processes the file "orig.wav" by decreasing +the sound tempo by 25.3% and increasing the sound pitch (key) by 1.5 +semitones. Resulting .wav audio data is directed to standard output +pipe:

soundstretch orig.wav stdout -tempo=-25.3 -pitch=1.5

Example 4

-

The following command detects the BPM rate -of the file "orig.wav" and adjusts the tempo to match -100 beats per minute. Result is stored to file "dest.wav":

+

The following command detects the BPM rate of the file "orig.wav" +and adjusts the tempo to match 100 beats per minute. Result is stored +to file "dest.wav":

soundstretch orig.wav dest.wav -bpm=100

Example 5

-

The following command reads .wav sound data from standard input pipe and -estimates the BPM rate:

+

The following command reads .wav sound data from standard input pipe +and estimates the BPM rate:

soundstretch stdin -bpm

5. Change History

5.1. SoundTouch library Change History

- +

1.7.1:

+
    +
  • Added files for Android compilation +
+

1.7.0:

+
    +
  • Sound quality improvements/li> +
  • Improved flush() to adjust output sound stream duration to match better with + ideal duration
  • +
  • Rewrote x86 cpu feature check to resolve compatibility problems
  • +
  • Configure script automatically checks if CPU supports mmx & sse compatibility for GNU platform, and + the script support now "--enable-x86-optimizations" switch to allow disabling x86-specific optimizations.
  • +
  • Revised #define conditions for 32bit/64bit compatibility
  • +
  • gnu autoconf/automake script compatibility fixes
  • +
  • Tuned beat-per-minute detection algorithm
  • +
+

1.6.0:

+
    +
  • Added automatic cutoff threshold adaptation to beat detection +routine to better adapt BPM calculation to different types of music
  • +
  • Retired 3DNow! optimization support as 3DNow! is nowadays +obsoleted and assembler code is nuisance to maintain
  • +
  • Retired "configure" file from source code package due to +autoconf/automake versio conflicts, so that it is from now on to be +generated by invoking "boostrap" script that uses locally available +toolchain version for generating the "configure" file
  • +
  • Resolved namespace/label naming conflicts with other libraries by +replacing global labels such as INTEGER_SAMPLES with more specific +SOUNDTOUCH_INTEGER_SAMPLES etc.
    +
  • +
  • Updated windows build scripts & project files for Visual +Studio 2008 support
  • +
  • Updated SoundTouch.dll API for .NET compatibility
  • +
  • Added API for querying nominal processing input & output +sample batch sizes
  • +

1.5.0:

    -
  • Added normalization to correlation calculation and improvement automatic seek/sequence parameter calculation to improve sound quality
  • - -
  • Bugfixes:  -
      -
    • Fixed negative array indexing in quick seek algorithm
    • -
    • FIR autoalias filter running too far in processing buffer
    • -
    • Check against zero sample count in rate transposing
    • -
    • Fix for x86-64 support: Removed pop/push instructions from the cpu detection algorithm. 
    • -
    • Check against empty buffers in FIFOSampleBuffer
    • -
    • Other minor fixes & code cleanup
    • -
    -
  • - -
  • Fixes in compilation scripts for non-Intel platforms
  • -
  • Added Dynamic-Link-Library (DLL) version of SoundTouch library build, - provided with Delphi/Pascal wrapper for calling the dll routines
  • -
  • Added #define PREVENT_CLICK_AT_RATE_CROSSOVER that prevents a click artifact - when crossing the nominal pitch from either positive to negative side or vice - versa
  • - +
  • Added normalization to correlation calculation and improvement +automatic seek/sequence parameter calculation to improve sound quality
  • +
  • Bugfixes:  +
      +
    • Fixed negative array indexing in quick seek algorithm
    • +
    • FIR autoalias filter running too far in processing buffer
    • +
    • Check against zero sample count in rate transposing
    • +
    • Fix for x86-64 support: Removed pop/push instructions from +the cpu detection algorithm. 
    • +
    • Check against empty buffers in FIFOSampleBuffer
    • +
    • Other minor fixes & code cleanup
    • +
    +
  • +
  • Fixes in compilation scripts for non-Intel platforms
  • +
  • Added Dynamic-Link-Library (DLL) version of SoundTouch library +build, provided with Delphi/Pascal wrapper for calling the dll routines +
  • +
  • Added #define PREVENT_CLICK_AT_RATE_CROSSOVER that prevents a +click artifact when crossing the nominal pitch from either positive to +negative side or vice versa
-

1.4.1:

    -
  • Fixed a buffer overflow bug in BPM detect algorithm routines if processing - more than 2048 samples at one call 
  • - +
  • Fixed a buffer overflow bug in BPM detect algorithm routines if +processing more than 2048 samples at one call 
-

1.4.0:

    -
  • Improved sound quality by automatic calculation of time stretch algorithm - processing parameters according to tempo setting
  • -
  • Moved BPM detection routines from SoundStretch application into SoundTouch - library
  • -
  • Bugfixes: Usage of uninitialied variables, GNU build scripts, compiler errors - due to 'const' keyword mismatch.
  • -
  • Source code cleanup
  • - +
  • Improved sound quality by automatic calculation of time stretch +algorithm processing parameters according to tempo setting
  • +
  • Moved BPM detection routines from SoundStretch application into +SoundTouch library
  • +
  • Bugfixes: Usage of uninitialied variables, GNU build scripts, +compiler errors due to 'const' keyword mismatch.
  • +
  • Source code cleanup
- -

v1.3.1: -

+

1.3.1:

    -
  • Changed static class declaration to GCC 4.x compiler compatible syntax.
  • -
  • Enabled MMX/SSE-optimized routines also for GCC compilers. Earlier -the MMX/SSE-optimized routines were written in compiler-specific inline -assembler, now these routines are migrated to use compiler intrinsic -syntax which allows compiling the same MMX/SSE-optimized source code with -both Visual C++ and GCC compilers.
  • -
  • Set floating point as the default sample format and added switch to -the GNU configure script for selecting the other sample format.
  • - +
  • Changed static class declaration to GCC 4.x compiler compatible +syntax.
  • +
  • Enabled MMX/SSE-optimized routines also for GCC compilers. +Earlier the MMX/SSE-optimized routines were written in +compiler-specific inline assembler, now these routines are migrated to +use compiler intrinsic syntax which allows compiling the same +MMX/SSE-optimized source code with both Visual C++ and GCC compilers.
  • +
  • Set floating point as the default sample format and added switch +to the GNU configure script for selecting the other sample format.
- -

v1.3.0: -

+

1.3.0:

    -
  • Fixed tempo routine output duration inaccuracy due to rounding +
  • Fixed tempo routine output duration inaccuracy due to rounding error
  • -
  • Implemented separate processing routines for integer and +
  • Implemented separate processing routines for integer and floating arithmetic to allow improvements to floating point routines (earlier used algorithms mostly optimized for integer arithmetic also for floating point samples)
  • -
  • Fixed a bug that distorts sound if sample rate changes during the -sound stream
  • -
  • Fixed a memory leak that appeared in MMX/SSE/3DNow! optimized +
  • Fixed a bug that distorts sound if sample rate changes during +the sound stream
  • +
  • Fixed a memory leak that appeared in MMX/SSE/3DNow! optimized routines
  • -
  • Reduced redundant code pieces in MMX/SSE/3DNow! optimized -routines vs. the standard C routines.
  • -
  • MMX routine incompatibility with new gcc compiler versions
  • -
  • Other miscellaneous bug fixes
  • +
  • Reduced redundant code pieces in MMX/SSE/3DNow! optimized +routines vs. the standard C routines.
  • +
  • MMX routine incompatibility with new gcc compiler versions
  • +
  • Other miscellaneous bug fixes
-

v1.2.1:

+

1.2.1:

    -
  • Added automake/autoconf scripts for GNU -platforms (in courtesy of David Durham)
  • -
  • Fixed SCALE overflow bug in rate transposer -routine.
  • -
  • Fixed 64bit address space bugs.
  • -
  • Created a 'soundtouch' namespace for -SAMPLETYPE definitions.
  • +
  • Added automake/autoconf scripts for GNU platforms (in courtesy +of David Durham)
  • +
  • Fixed SCALE overflow bug in rate transposer routine.
  • +
  • Fixed 64bit address space bugs.
  • +
  • Created a 'soundtouch' namespace for SAMPLETYPE definitions.
-

v1.2.0:

+

1.2.0:

    -
  • Added support for 32bit floating point sample -data type with SSE/3DNow! optimizations for Win32 platform (SSE/3DNow! optimizations currently not supported in GCC environment)
  • -
  • Replaced 'make-gcc' script for GNU environment -by master Makefile
  • -
  • Added time-stretch routine configurability to -SoundTouch main class
  • -
  • Bugfixes
  • +
  • Added support for 32bit floating point sample data type with +SSE/3DNow! optimizations for Win32 platform (SSE/3DNow! optimizations +currently not supported in GCC environment)
  • +
  • Replaced 'make-gcc' script for GNU environment by master +Makefile
  • +
  • Added time-stretch routine configurability to SoundTouch main +class
  • +
  • Bugfixes
-

v1.1.1:

+

1.1.1:

    -
  • Moved SoundTouch under lesser GPL license (LGPL). This allows using SoundTouch library in programs that aren't -released under GPL license.
  • -
  • Changed MMX routine organiation so that MMX optimized routines are now implemented in classes that are derived from -the basic classes having the standard non-mmx routines.
  • -
  • MMX routines to support gcc version 3.
  • -
  • Replaced windows makefiles by script using the .dsw files
  • +
  • Moved SoundTouch under lesser GPL license (LGPL). This allows +using SoundTouch library in programs that aren't released under GPL +license.
  • +
  • Changed MMX routine organiation so that MMX optimized routines +are now implemented in classes that are derived from the basic classes +having the standard non-mmx routines.
  • +
  • MMX routines to support gcc version 3.
  • +
  • Replaced windows makefiles by script using the .dsw files
-

v1.01:

+

1.0.1:

    -
  • "mmx_gcc.cpp": Added "using namespace std" and -removed "return 0" from a function with void return value to fix -compiler errors when compiling the library in Solaris environment.
  • -
  • Moved file "FIFOSampleBuffer.h" to "include" -directory to allow accessing the FIFOSampleBuffer class from external -files.
  • +
  • "mmx_gcc.cpp": Added "using namespace std" and removed "return +0" from a function with void return value to fix compiler errors when +compiling the library in Solaris environment.
  • +
  • Moved file "FIFOSampleBuffer.h" to "include" directory to allow +accessing the FIFOSampleBuffer class from external files.
-

v1.0:

+

1.0:

    -
  • Initial release
  • +
  • Initial release

 

-

5.2. SoundStretch application Change -History

- +

5.2. SoundStretch application Change History

+

1.7.0:

+
    +
  • Bugfixes in Wavfile: exception string formatting, avoid getLengthMs() integer + precision overflow, support WAV files using 24/32bit sample format.
  • +
+

1.5.0:

+
    +
  • Added "-speech" switch to activate algorithm parameters more +suitable for speech processing than the default parameters tuned for +music processing.
  • +

1.4.0:

    -
  • Moved BPM detection routines from SoundStretch application into SoundTouch - library
  • -
  • Allow using standard input/output pipes as audio processing input/output - streams
  • - +
  • Moved BPM detection routines from SoundStretch application into +SoundTouch library
  • +
  • Allow using standard input/output pipes as audio processing +input/output streams
- -

v1.3.0:

+

1.3.0:

    -
  • Simplified accessing WAV files with floating -point sample format. -
  • +
  • Simplified accessing WAV files with floating point sample +format.
-

v1.2.1:

+

1.2.1:

    -
  • Fixed 64bit address space bugs.
  • +
  • Fixed 64bit address space bugs.
-

v1.2.0:

+

1.2.0:

    -
  • Added support for 32bit floating point sample -data type
  • -
  • Restructured the BPM routines into separate -library
  • -
  • Fixed big-endian conversion bugs in WAV file -routines (hopefully :)
  • +
  • Added support for 32bit floating point sample data type
  • +
  • Restructured the BPM routines into separate library
  • +
  • Fixed big-endian conversion bugs in WAV file routines (hopefully +:)
-

v1.1.1:

+

1.1.1:

    -
  • Fixed bugs in WAV file reading & added -byte-order conversion for big-endian processors.
  • -
  • Moved SoundStretch source code under 'example' -directory to highlight difference from SoundTouch stuff.
  • -
  • Replaced windows makefiles by script using the .dsw files
  • -
  • Output file name isn't required if output -isn't desired (e.g. if using the switch '-bpm' in plain format only)
  • +
  • Fixed bugs in WAV file reading & added byte-order conversion +for big-endian processors.
  • +
  • Moved SoundStretch source code under 'example' directory to +highlight difference from SoundTouch stuff.
  • +
  • Replaced windows makefiles by script using the .dsw files
  • +
  • Output file name isn't required if output isn't desired (e.g. if +using the switch '-bpm' in plain format only)
-

v1.1:

+

1.1:

    -
  • Fixed "Release" settings in Microsoft Visual -C++ project file (.dsp)
  • -
  • Added beats-per-minute (BPM) detection routine -and command-line switch "-bpm"
  • +
  • Fixed "Release" settings in Microsoft Visual C++ project file +(.dsp)
  • +
  • Added beats-per-minute (BPM) detection routine and command-line +switch "-bpm"
-

v1.01:

+

1.01:

    -
  • Initial release
  • +
  • Initial release

-

6. Acknowledgements

-

Kudos for these people who have contributed to development or submitted -bugfixes since -SoundTouch v1.3.1:

+

6. Acknowledgements

+

Kudos for these people who have contributed to development or +submitted bugfixes since SoundTouch v1.3.1:

    -
  • Arthur A
  • -
  • Richard Ash
  • -
  • Stanislav Brabec
  • -
  • Christian Budde
  • -
  • Brian Cameron
  • -
  • Jason Champion
  • -
  • Patrick Colis
  • -
  • Justin Frankel
  • -
  • Jason Garland
  • -
  • Takashi Iwai
  • -
  • Paulo Pizarro
  • -
  • RJ Ryan
  • -
  • John Sheehy
  • +
  • Arthur A
  • +
  • Richard Ash
  • +
  • Stanislav Brabec
  • +
  • Christian Budde
  • +
  • Jacek Caban
  • +
  • Brian Cameron
  • +
  • Jason Champion
  • +
  • David Clark
  • +
  • Patrick Colis
  • +
  • Miquel Colon
  • +
  • Justin Frankel
  • +
  • Jason Garland
  • +
  • Takashi Iwai
  • +
  • Yuval Naveh
  • +
  • Paulo Pizarro
  • +
  • Blaise Potard
  • +
  • RJ Ryan
  • +
  • Patrick Colis
  • +
  • Miquel Colon
  • +
  • Sandro Cumerlato
  • +
  • Justin Frankel
  • +
  • Jason Garland
  • +
  • Takashi Iwai
  • +
  • Mathias Möhl
  • +
  • Yuval Naveh
  • +
  • Paulo Pizarro
  • +
  • Blaise Potard
  • +
  • RJ Ryan
  • +
  • John Sheehy
  • +
  • Tim Shuttleworth
  • +
  • John Stumpo
  • +
  • Tim Shuttleworth
  • +
  • Katja Vetter
-

Moral greetings to all other contributors and users also!

+

Moral greetings to all other contributors and users also!


-

7. LICENSE

+

7. 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 version 2.1 as published by the Free Software -Foundation.

-

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

-
- +

This library is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License version 2.1 +as published by the Free Software Foundation.

+

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

+
+

+ RREADME.html file updated on 28-Dec-2012

diff --git a/3rdparty/SoundTouch/RateTransposer.cpp b/3rdparty/SoundTouch/RateTransposer.cpp index 7d992f8ce2..19d4bf8ef2 100644 --- a/3rdparty/SoundTouch/RateTransposer.cpp +++ b/3rdparty/SoundTouch/RateTransposer.cpp @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation +/// +/// 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) /// @@ -10,10 +10,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-10-31 16:37:24 +0200 (Sat, 31 Oct 2009) $ +// Last changed : $Date: 2011-09-02 15:56:11 -0300 (sex, 02 set 2011) $ // File revision : $Revision: 4 $ // -// $Id: RateTransposer.cpp 74 2009-10-31 14:37:24Z oparviai $ +// $Id: RateTransposer.cpp 131 2011-09-02 18:56:11Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -42,11 +42,9 @@ #include #include #include -#include #include "RateTransposer.h" #include "AAFilter.h" -using namespace std; using namespace soundtouch; @@ -61,18 +59,18 @@ protected: virtual void resetRegisters(); - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples); public: RateTransposerInteger(); virtual ~RateTransposerInteger(); - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// rate, larger faster rates. virtual void setRate(float newRate); @@ -89,11 +87,11 @@ protected: virtual void resetRegisters(); - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples); - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples); public: @@ -104,18 +102,18 @@ public: -// Operator 'new' is overloaded so that it automatically creates a suitable instance +// 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) { - throw runtime_error("Error in RateTransoser::new: don't use \"new TDStretch\" directly, use \"newInstance\" to create a new instance instead!"); - return NULL; + 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 INTEGER_SAMPLES +#ifdef SOUNDTOUCH_INTEGER_SAMPLES return ::new RateTransposerInteger; #else return ::new RateTransposerFloat; @@ -165,7 +163,7 @@ AAFilter *RateTransposer::getAAFilter() -// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower +// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower // iRate, larger faster iRates. void RateTransposer::setRate(float newRate) { @@ -174,11 +172,11 @@ void RateTransposer::setRate(float newRate) fRate = newRate; // design a new anti-alias filter - if (newRate > 1.0f) + if (newRate > 1.0f) { fCutoff = 0.5f / newRate; - } - else + } + else { fCutoff = 0.5f * newRate; } @@ -220,7 +218,7 @@ void RateTransposer::upsample(const SAMPLETYPE *src, uint nSamples) // 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' + // 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); @@ -231,7 +229,7 @@ void RateTransposer::upsample(const SAMPLETYPE *src, uint nSamples) // Apply the anti-alias filter to samples in "store output", output the // result to "dest" num = storeBuffer.numSamples(); - count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), + count = pAAFilter->evaluate(outputBuffer.ptrEnd(num), storeBuffer.ptrBegin(), num, (uint)numChannels); outputBuffer.putSamples(count); @@ -253,13 +251,13 @@ void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples) // 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 + // 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), + count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp), storeBuffer.ptrBegin(), sizeTemp, (uint)numChannels); if (count == 0) return; @@ -274,7 +272,7 @@ void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples) } -// Transposes sample rate by applying anti-alias filter to prevent folding. +// 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. @@ -288,7 +286,7 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint 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); @@ -297,26 +295,26 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) } // Transpose with anti-alias filter - if (fRate < 1.0f) + if (fRate < 1.0f) { upsample(src, nSamples); - } - else + } + else { downsample(src, nSamples); } } -// Transposes the sample rate of the given samples using linear interpolation. +// Transposes the sample rate of the given samples using linear interpolation. // Returns the number of samples returned in the "dest" buffer inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) { - if (numChannels == 2) + if (numChannels == 2) { return transposeStereo(dest, src, nSamples); - } - else + } + else { return transposeMono(dest, src, nSamples); } @@ -363,7 +361,7 @@ int RateTransposer::isEmpty() const ////////////////////////////////////////////////////////////////////////////// // // RateTransposerInteger - integer arithmetic implementation -// +// /// fixed-point interpolation routine precision #define SCALE 65536 @@ -371,7 +369,7 @@ int RateTransposer::isEmpty() const // Constructor RateTransposerInteger::RateTransposerInteger() : RateTransposer() { - // Notice: use local function calling syntax for sake of clarity, + // Notice: use local function calling syntax for sake of clarity, // to indicate the fact that C++ constructor can't call virtual functions. RateTransposerInteger::resetRegisters(); RateTransposerInteger::setRate(1.0f); @@ -386,14 +384,14 @@ RateTransposerInteger::~RateTransposerInteger() void RateTransposerInteger::resetRegisters() { iSlopeCount = 0; - sPrevSampleL = + sPrevSampleL = sPrevSampleR = 0; } -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in +// 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 uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) { @@ -402,11 +400,11 @@ uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *sr if (nSamples == 0) return 0; // no samples, no work - used = 0; + used = 0; i = 0; // Process the last sample saved from the previous call first... - while (iSlopeCount <= SCALE) + while (iSlopeCount <= SCALE) { vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; @@ -419,7 +417,7 @@ uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *sr while (1) { - while (iSlopeCount > SCALE) + while (iSlopeCount > SCALE) { iSlopeCount -= SCALE; used ++; @@ -440,8 +438,8 @@ end: } -// Transposes the sample rate of the given samples using linear interpolation. -// 'Stereo' version of the routine. Returns the number of samples returned in +// 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 uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) { @@ -450,11 +448,11 @@ uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE * if (nSamples == 0) return 0; // no samples, no work - used = 0; + used = 0; i = 0; // Process the last sample saved from the sPrevSampleLious call first... - while (iSlopeCount <= SCALE) + while (iSlopeCount <= SCALE) { vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount); temp = vol1 * sPrevSampleL + iSlopeCount * src[0]; @@ -469,7 +467,7 @@ uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE * while (1) { - while (iSlopeCount > SCALE) + while (iSlopeCount > SCALE) { iSlopeCount -= SCALE; used ++; @@ -494,7 +492,7 @@ end: } -// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower +// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower // iRate, larger faster iRates. void RateTransposerInteger::setRate(float newRate) { @@ -506,13 +504,13 @@ void RateTransposerInteger::setRate(float newRate) ////////////////////////////////////////////////////////////////////////////// // // RateTransposerFloat - floating point arithmetic implementation -// +// ////////////////////////////////////////////////////////////////////////////// // Constructor RateTransposerFloat::RateTransposerFloat() : RateTransposer() { - // Notice: use local function calling syntax for sake of clarity, + // Notice: use local function calling syntax for sake of clarity, // to indicate the fact that C++ constructor can't call virtual functions. RateTransposerFloat::resetRegisters(); RateTransposerFloat::setRate(1.0f); @@ -527,24 +525,24 @@ RateTransposerFloat::~RateTransposerFloat() void RateTransposerFloat::resetRegisters() { fSlopeCount = 0; - sPrevSampleL = + sPrevSampleL = sPrevSampleR = 0; } -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in +// 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 uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) { unsigned int i, used; - used = 0; + used = 0; i = 0; // Process the last sample saved from the previous call first... - while (fSlopeCount <= 1.0f) + while (fSlopeCount <= 1.0f) { dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); i++; @@ -556,7 +554,7 @@ uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, { while (1) { - while (fSlopeCount > 1.0f) + while (fSlopeCount > 1.0f) { fSlopeCount -= 1.0f; used ++; @@ -575,8 +573,8 @@ end: } -// Transposes the sample rate of the given samples using linear interpolation. -// 'Mono' version of the routine. Returns the number of samples returned in +// 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 uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples) { @@ -584,11 +582,11 @@ uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *sr if (nSamples == 0) return 0; // no samples, no work - used = 0; + used = 0; i = 0; // Process the last sample saved from the sPrevSampleLious call first... - while (fSlopeCount <= 1.0f) + while (fSlopeCount <= 1.0f) { dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]); dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]); @@ -602,7 +600,7 @@ uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *sr { while (1) { - while (fSlopeCount > 1.0f) + while (fSlopeCount > 1.0f) { fSlopeCount -= 1.0f; used ++; @@ -610,9 +608,9 @@ uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *sr } srcPos = 2 * used; - dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos] + fSlopeCount * src[srcPos + 2]); - dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1] + fSlopeCount * src[srcPos + 3]); i++; diff --git a/3rdparty/SoundTouch/RateTransposer.h b/3rdparty/SoundTouch/RateTransposer.h index 6ab0586484..8374a0f834 100644 --- a/3rdparty/SoundTouch/RateTransposer.h +++ b/3rdparty/SoundTouch/RateTransposer.h @@ -1,10 +1,10 @@ //////////////////////////////////////////////////////////////////////////////// -/// -/// Sample rate transposer. Changes sample rate by using linear interpolation +/// +/// 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). /// -/// Use either of the derived classes of 'RateTransposerInteger' or +/// Use either of the derived classes of 'RateTransposerInteger' or /// 'RateTransposerFloat' for corresponding integer/floating point tranposing /// algorithm implementation. /// @@ -14,7 +14,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-21 18:00:14 +0200 (Sat, 21 Feb 2009) $ +// Last changed : $Date: 2009-02-21 13:00:14 -0300 (sáb, 21 fev 2009) $ // File revision : $Revision: 4 $ // // $Id: RateTransposer.h 63 2009-02-21 16:00:14Z oparviai $ @@ -57,9 +57,9 @@ namespace soundtouch /// 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 +/// 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 { @@ -85,26 +85,26 @@ protected: virtual void resetRegisters() = 0; - virtual uint transposeStereo(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples) = 0; - virtual uint transposeMono(SAMPLETYPE *dest, - const SAMPLETYPE *src, + virtual uint transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples) = 0; - inline uint transpose(SAMPLETYPE *dest, - const SAMPLETYPE *src, + inline uint transpose(SAMPLETYPE *dest, + const SAMPLETYPE *src, uint numSamples); - void downsample(const SAMPLETYPE *src, + void downsample(const SAMPLETYPE *src, uint numSamples); - void upsample(const SAMPLETYPE *src, + void upsample(const SAMPLETYPE *src, uint numSamples); - /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// 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 processSamples(const SAMPLETYPE *src, + void processSamples(const SAMPLETYPE *src, uint numSamples); @@ -112,12 +112,12 @@ public: RateTransposer(); virtual ~RateTransposer(); - /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// 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); - /// 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 + /// 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(); @@ -136,7 +136,7 @@ public: /// Returns nonzero if anti-alias filter is enabled. BOOL isAAFilterEnabled() const; - /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// rate, larger faster rates. virtual void setRate(float newRate); diff --git a/3rdparty/SoundTouch/STTypes.h b/3rdparty/SoundTouch/STTypes.h index 1fcd9e2da9..2c4584a142 100644 --- a/3rdparty/SoundTouch/STTypes.h +++ b/3rdparty/SoundTouch/STTypes.h @@ -8,10 +8,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-05-17 14:30:57 +0300 (Sun, 17 May 2009) $ +// Last changed : $Date: 2012-12-28 12:53:56 -0200 (sex, 28 dez 2012) $ // File revision : $Revision: 3 $ // -// $Id: STTypes.h 70 2009-05-17 11:30:57Z oparviai $ +// $Id: STTypes.h 162 2012-12-28 14:53:56Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -42,8 +42,21 @@ typedef unsigned int uint; typedef unsigned long ulong; -#ifdef __GNUC__ - // In GCC, include soundtouch_config.h made by config scritps +// Patch for MinGW: on Win64 long is 32-bit +#ifdef _WIN64 + typedef unsigned long long ulongptr; +#else + typedef ulong ulongptr; +#endif + + +// Helper macro for aligning pointer up to next 16-byte boundary +#define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 ) + + +#if (defined(__GNUC__) && !defined(ANDROID)) + // In GCC, include soundtouch_config.h made by config scritps. + // Skip this in Android compilation that uses GCC but without configure scripts. #include "soundtouch_config.h" #endif @@ -60,64 +73,81 @@ typedef unsigned long ulong; namespace soundtouch { + /// Activate these undef's to overrule the possible sampletype + /// setting inherited from some other header file: + //#undef SOUNDTOUCH_INTEGER_SAMPLES + //#undef SOUNDTOUCH_FLOAT_SAMPLES -/// Activate these undef's to overrule the possible sampletype -/// setting inherited from some other header file: -//#undef INTEGER_SAMPLES -//#undef FLOAT_SAMPLES + #if (defined(__SOFTFP__)) + // For Android compilation: Force use of Integer samples in case that + // compilation uses soft-floating point emulation - soft-fp is way too slow + #undef SOUNDTOUCH_FLOAT_SAMPLES + #define SOUNDTOUCH_INTEGER_SAMPLES 1 + #endif -#if !(INTEGER_SAMPLES || FLOAT_SAMPLES) + #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples + #define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples + + #endif - /// Choose either 32bit floating point or 16bit integer sampletype - /// by choosing one of the following defines, unless this selection - /// has already been done in some other file. - //// - /// Notes: - /// - In Windows environment, choose the sample format with the - /// following defines. - /// - In GNU environment, the floating point samples are used by - /// default, but integer samples can be chosen by giving the - /// following switch to the configure script: - /// ./configure --enable-integer-samples - /// However, if you still prefer to select the sample format here - /// also in GNU environment, then please #undef the INTEGER_SAMPLE - /// and FLOAT_SAMPLE defines first as in comments above. - //#define INTEGER_SAMPLES 1 //< 16bit integer samples - #define FLOAT_SAMPLES 1 //< 32bit float samples - - #endif - - #if (WIN32 || __i386__ || __x86_64__) - /// Define this to allow X86-specific assembler/intrinsic optimizations. + #if (_M_IX86 || __i386__ || __x86_64__ || _M_X64) + /// Define this to allow X86-specific assembler/intrinsic optimizations. /// Notice that library contains also usual C++ versions of each of these - /// these routines, so if you're having difficulties getting the optimized - /// routines compiled for whatever reason, you may disable these optimizations + /// these routines, so if you're having difficulties getting the optimized + /// routines compiled for whatever reason, you may disable these optimizations /// to make the library compile. - #define ALLOW_X86_OPTIMIZATIONS 1 + #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 + + /// In GNU environment, allow the user to override this setting by + /// giving the following switch to the configure script: + /// ./configure --disable-x86-optimizations + /// ./configure --enable-x86-optimizations=no + #ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS + #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS + #endif + #else + /// Always disable optimizations when not using a x86 systems. + #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS #endif - // If defined, allows the SIMD-optimized routines to take minor shortcuts - // for improved performance. Undefine to require faithfully similar SIMD + // If defined, allows the SIMD-optimized routines to take minor shortcuts + // for improved performance. Undefine to require faithfully similar SIMD // calculations as in normal C implementation. - #define ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 - #ifdef INTEGER_SAMPLES + #ifdef SOUNDTOUCH_INTEGER_SAMPLES // 16bit integer sample type typedef short SAMPLETYPE; // data type for sample accumulation: Use 32bit integer to prevent overflows typedef long LONG_SAMPLETYPE; - #ifdef FLOAT_SAMPLES + #ifdef SOUNDTOUCH_FLOAT_SAMPLES // check that only one sample type is defined #error "conflicting sample types defined" - #endif // FLOAT_SAMPLES + #endif // SOUNDTOUCH_FLOAT_SAMPLES - #ifdef ALLOW_X86_OPTIMIZATIONS + #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS // Allow MMX optimizations - #define ALLOW_MMX 1 + #define SOUNDTOUCH_ALLOW_MMX 1 #endif #else @@ -127,23 +157,31 @@ namespace soundtouch // data type for sample accumulation: Use double to utilize full precision. typedef double LONG_SAMPLETYPE; - #ifdef ALLOW_X86_OPTIMIZATIONS - // Allow 3DNow! and SSE optimizations - #if WIN32 - #define ALLOW_3DNOW 1 - #endif - - #define ALLOW_SSE 1 + #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS + // Allow SSE optimizations + #define SOUNDTOUCH_ALLOW_SSE 1 #endif - #endif // INTEGER_SAMPLES + #endif // SOUNDTOUCH_INTEGER_SAMPLES + }; +// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions: +// #define ST_NO_EXCEPTION_HANDLING 1 +#ifdef ST_NO_EXCEPTION_HANDLING + // Exceptions disabled. Throw asserts instead if enabled. + #include + #define ST_THROW_RT_ERROR(x) {assert((const char *)x);} +#else + // use c++ standard exceptions + #include + #define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);} +#endif -// When this #define is active, eliminates a clicking sound when the "rate" or "pitch" -// parameter setting crosses from value <1 to >=1 or vice versa during processing. -// Default is off as such crossover is untypical case and involves a slight sound +// When this #define is active, eliminates a clicking sound when the "rate" or "pitch" +// parameter setting crosses from value <1 to >=1 or vice versa during processing. +// Default is off as such crossover is untypical case and involves a slight sound // quality compromise. -//#define PREVENT_CLICK_AT_RATE_CROSSOVER 1 +//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1 #endif diff --git a/3rdparty/SoundTouch/SoundTouch.cpp b/3rdparty/SoundTouch/SoundTouch.cpp index 8abfc23b27..c66c16c54a 100644 --- a/3rdparty/SoundTouch/SoundTouch.cpp +++ b/3rdparty/SoundTouch/SoundTouch.cpp @@ -1,27 +1,27 @@ ////////////////////////////////////////////////////////////////////////////// /// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. /// /// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set /// desired tempo/pitch/rate settings with the corresponding functions. /// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The /// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read +/// function 'putSamples', while the ready processed samples can be read /// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for /// processing, then they carry out the processing step and consequently /// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain +/// +/// - For the above reason, the processing routines introduce a certain /// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct /// relationship with the amount of previously input samples. /// /// - The tempo/pitch/rate control parameters can be altered during processing. @@ -30,8 +30,8 @@ /// required. /// /// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control /// 'pitch' (change pitch but maintain tempo) is produced by a combination of /// combining the two other controls. /// @@ -41,10 +41,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-05-19 07:57:30 +0300 (Tue, 19 May 2009) $ +// Last changed : $Date: 2012-06-13 16:29:53 -0300 (qua, 13 jun 2012) $ // File revision : $Revision: 4 $ // -// $Id: SoundTouch.cpp 73 2009-05-19 04:57:30Z oparviai $ +// $Id: SoundTouch.cpp 143 2012-06-13 19:29:53Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -73,7 +73,6 @@ #include #include #include -#include #include #include "SoundTouch.h" @@ -82,7 +81,7 @@ #include "cpu_detect.h" using namespace soundtouch; - + /// test if two floating point numbers are equal #define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10) @@ -91,7 +90,7 @@ using namespace soundtouch; extern "C" void soundtouch_ac_test() { printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); -} +} SoundTouch::SoundTouch() @@ -105,8 +104,8 @@ SoundTouch::SoundTouch() rate = tempo = 0; - virtualPitch = - virtualRate = + virtualPitch = + virtualRate = virtualTempo = 1.0; calcEffectiveRateAndTempo(); @@ -144,9 +143,9 @@ uint SoundTouch::getVersionId() // Sets the number of channels, 1 = mono, 2 = stereo void SoundTouch::setChannels(uint numChannels) { - if (numChannels != 1 && numChannels != 2) + if (numChannels != 1 && numChannels != 2) { - throw std::runtime_error("Illegal number of channels"); + ST_THROW_RT_ERROR("Illegal number of channels"); } channels = numChannels; pRateTransposer->setChannels((int)numChannels); @@ -243,10 +242,10 @@ void SoundTouch::calcEffectiveRateAndTempo() if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); -#ifndef PREVENT_CLICK_AT_RATE_CROSSOVER - if (rate <= 1.0f) +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + if (rate <= 1.0f) { - if (output != pTDStretch) + if (output != pTDStretch) { FIFOSamplePipe *tempoOut; @@ -263,7 +262,7 @@ void SoundTouch::calcEffectiveRateAndTempo() else #endif { - if (output != pRateTransposer) + if (output != pRateTransposer) { FIFOSamplePipe *transOut; @@ -276,7 +275,7 @@ void SoundTouch::calcEffectiveRateAndTempo() output = pRateTransposer; } - } + } } @@ -293,42 +292,42 @@ void SoundTouch::setSampleRate(uint srate) // the input of the object. void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) { - if (bSrateSet == FALSE) + if (bSrateSet == FALSE) { - throw std::runtime_error("SoundTouch : Sample rate not defined"); - } - else if (channels == 0) + ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) { - throw std::runtime_error("SoundTouch : Number of channels not defined"); + ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined"); } // Transpose the rate of the new samples if necessary /* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value... - if (rate == 1.0f) + if (rate == 1.0f) { - // The rate value is same as the original, simply evaluate the tempo changer. + // The rate value is same as the original, simply evaluate the tempo changer. assert(output == pTDStretch); - if (pRateTransposer->isEmpty() == 0) + if (pRateTransposer->isEmpty() == 0) { // yet flush the last samples in the pitch transposer buffer // (may happen if 'rate' changes from a non-zero value to zero) pTDStretch->moveSamples(*pRateTransposer); } pTDStretch->putSamples(samples, nSamples); - } + } */ -#ifndef PREVENT_CLICK_AT_RATE_CROSSOVER - else if (rate <= 1.0f) +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + else if (rate <= 1.0f) { // transpose the rate down, output the transposed sound to tempo changer buffer assert(output == pTDStretch); pRateTransposer->putSamples(samples, nSamples); pTDStretch->moveSamples(*pRateTransposer); - } - else + } + else #endif { - // evaluate the tempo changer, then transpose the rate up, + // evaluate the tempo changer, then transpose the rate up, assert(output == pRateTransposer); pTDStretch->putSamples(samples, nSamples); pRateTransposer->moveSamples(*pTDStretch); @@ -346,20 +345,36 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) void SoundTouch::flush() { int i; - uint nOut; - SAMPLETYPE buff[128]; + int nUnprocessed; + int nOut; + SAMPLETYPE buff[64*2]; // note: allocate 2*64 to cater 64 sample frames of stereo sound - nOut = numSamples(); + // check how many samples still await processing, and scale + // that by tempo & rate to get expected output sample count + nUnprocessed = numUnprocessedSamples(); + nUnprocessed = (int)((double)nUnprocessed / (tempo * rate) + 0.5); - memset(buff, 0, 128 * sizeof(SAMPLETYPE)); + nOut = numSamples(); // ready samples currently in buffer ... + nOut += nUnprocessed; // ... and how many we expect there to be in the end + + memset(buff, 0, 64 * channels * sizeof(SAMPLETYPE)); // "Push" the last active samples out from the processing pipeline by - // feeding blank samples into the processing pipeline until new, - // processed samples appear in the output (not however, more than + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than // 8ksamples in any case) - for (i = 0; i < 128; i ++) + for (i = 0; i < 128; i ++) { putSamples(buff, 64); - if (numSamples() != nOut) break; // new samples have appeared in the output! + if ((int)numSamples() >= nOut) + { + // Enough new samples have appeared into the output! + // As samples come from processing with bigger chunks, now truncate it + // back to maximum "nOut" samples to improve duration accuracy + adjustAmountOfSamples(nOut); + + // finish + break; + } } // Clear working buffers @@ -379,7 +394,7 @@ BOOL SoundTouch::setSetting(int settingId, int value) // read current tdstretch routine parameters pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); - switch (settingId) + switch (settingId) { case SETTING_USE_AA_FILTER : // enables / disabless anti-alias filter @@ -425,7 +440,7 @@ int SoundTouch::getSetting(int settingId) const { int temp; - switch (settingId) + switch (settingId) { case SETTING_USE_AA_FILTER : return (uint)pRateTransposer->isAAFilterEnabled(); @@ -448,7 +463,13 @@ int SoundTouch::getSetting(int settingId) const pTDStretch->getParameters(NULL, NULL, NULL, &temp); return temp; - default : + case SETTING_NOMINAL_INPUT_SEQUENCE : + return pTDStretch->getInputSampleReq(); + + case SETTING_NOMINAL_OUTPUT_SEQUENCE : + return pTDStretch->getOutputBatchSize(); + + default : return 0; } } diff --git a/3rdparty/SoundTouch/SoundTouch.h b/3rdparty/SoundTouch/SoundTouch.h index 9d82886aa9..6ae0e4a829 100644 --- a/3rdparty/SoundTouch/SoundTouch.h +++ b/3rdparty/SoundTouch/SoundTouch.h @@ -1,27 +1,27 @@ ////////////////////////////////////////////////////////////////////////////// /// -/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. /// /// Notes: -/// - Initialize the SoundTouch object instance by setting up the sound stream -/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set /// desired tempo/pitch/rate settings with the corresponding functions. /// -/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The /// samples that are to be processed are fed into one of the pipe by calling -/// function 'putSamples', while the ready processed samples can be read +/// function 'putSamples', while the ready processed samples can be read /// from the other end of the pipeline with function 'receiveSamples'. -/// -/// - The SoundTouch processing classes require certain sized 'batches' of -/// samples in order to process the sound. For this reason the classes buffer -/// incoming samples until there are enough of samples available for +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for /// processing, then they carry out the processing step and consequently /// make the processed samples available for outputting. -/// -/// - For the above reason, the processing routines introduce a certain +/// +/// - For the above reason, the processing routines introduce a certain /// 'latency' between the input and output, so that the samples input to -/// SoundTouch may not be immediately available in the output, and neither -/// the amount of outputtable samples may not immediately be in direct +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct /// relationship with the amount of previously input samples. /// /// - The tempo/pitch/rate control parameters can be altered during processing. @@ -30,8 +30,8 @@ /// required. /// /// - This class utilizes classes 'TDStretch' for tempo change (without modifying -/// pitch) and 'RateTransposer' for changing the playback rate (that is, both -/// tempo and pitch in the same ratio) of the sound. The third available control +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control /// 'pitch' (change pitch but maintain tempo) is produced by a combination of /// combining the two other controls. /// @@ -41,10 +41,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-12-28 22:10:14 +0200 (Mon, 28 Dec 2009) $ +// Last changed : $Date: 2012-12-28 17:32:59 -0200 (sex, 28 dez 2012) $ // File revision : $Revision: 4 $ // -// $Id: SoundTouch.h 78 2009-12-28 20:10:14Z oparviai $ +// $Id: SoundTouch.h 163 2012-12-28 19:32:59Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -79,10 +79,10 @@ namespace soundtouch { /// Soundtouch library version string -#define SOUNDTOUCH_VERSION "1.5.0" +#define SOUNDTOUCH_VERSION "1.7.1" /// SoundTouch library version id -#define SOUNDTOUCH_VERSION_ID (10500) +#define SOUNDTOUCH_VERSION_ID (10701) // // Available setting IDs for the 'setSetting' & 'get_setting' functions: @@ -98,24 +98,49 @@ namespace soundtouch /// quality compromising) #define SETTING_USE_QUICKSEEK 2 -/// Time-stretch algorithm single processing sequence length in milliseconds. This determines -/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. /// See "STTypes.h" or README for more information. #define SETTING_SEQUENCE_MS 3 -/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the -/// best possible overlapping location. This determines from how wide window the algorithm -/// may look for an optimal joining location when mixing the sound sequences back together. +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. /// See "STTypes.h" or README for more information. #define SETTING_SEEKWINDOW_MS 4 -/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences -/// are mixed back together, to form a continuous sound stream, this parameter defines over -/// how long period the two consecutive sequences are let to overlap each other. +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. /// See "STTypes.h" or README for more information. #define SETTING_OVERLAP_MS 5 +/// Call "getSetting" with this ID to query nominal average processing sequence +/// size in samples. This value tells approcimate value how many input samples +/// SoundTouch needs to gather before it does DSP processing run for the sample batch. +/// +/// Notices: +/// - This is read-only parameter, i.e. setSetting ignores this parameter +/// - Returned value is approximate average value, exact processing batch +/// size may wary from time to time +/// - This parameter value is not constant but may change depending on +/// tempo/pitch/rate/samplerate settings. +#define SETTING_NOMINAL_INPUT_SEQUENCE 6 + + +/// Call "getSetting" with this ID to query nominal average processing output +/// size in samples. This value tells approcimate value how many output samples +/// SoundTouch outputs once it does DSP processing run for a batch of input samples. +/// +/// Notices: +/// - This is read-only parameter, i.e. setSetting ignores this parameter +/// - Returned value is approximate average value, exact processing batch +/// size may wary from time to time +/// - This parameter value is not constant but may change depending on +/// tempo/pitch/rate/samplerate settings. +#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 + class SoundTouch : public FIFOProcessor { private: @@ -137,7 +162,7 @@ private: /// Flag: Has sample rate been set? BOOL bSrateSet; - /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and /// 'virtualPitch' parameters. void calcEffectiveRateAndTempo(); @@ -181,7 +206,7 @@ public: /// represent lower pitches, larger values higher pitch. void setPitch(float newPitch); - /// Sets pitch change in octaves compared to the original pitch + /// Sets pitch change in octaves compared to the original pitch /// (-1.00 .. +1.00) void setPitchOctaves(float newPitch); @@ -221,7 +246,7 @@ public: /// Changes a setting controlling the processing system behaviour. See the /// '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. int value ///< New setting value. @@ -242,7 +267,7 @@ public: /// classes 'FIFOProcessor' and 'FIFOSamplePipe') /// /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. - /// - numSamples() : Get number of 'ready' samples that can be received with + /// - numSamples() : Get number of 'ready' samples that can be received with /// function 'receiveSamples()' /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. /// - clear() : Clears all samples from ready/processing buffers. diff --git a/3rdparty/SoundTouch/TDStretch.cpp b/3rdparty/SoundTouch/TDStretch.cpp index e37a0f53b8..8fa598f61c 100644 --- a/3rdparty/SoundTouch/TDStretch.cpp +++ b/3rdparty/SoundTouch/TDStretch.cpp @@ -1,10 +1,10 @@ //////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like /// method with several performance-increasing tweaks. /// -/// Note : MMX optimized functions reside in a separate, platform-specific +/// Note : MMX optimized functions reside in a separate, platform-specific /// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// /// Author : Copyright (c) Olli Parviainen @@ -13,10 +13,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-12-28 21:27:04 +0200 (Mon, 28 Dec 2009) $ +// Last changed : $Date: 2012-11-08 16:53:01 -0200 (qui, 08 nov 2012) $ // File revision : $Revision: 1.12 $ // -// $Id: TDStretch.cpp 77 2009-12-28 19:27:04Z oparviai $ +// $Id: TDStretch.cpp 160 2012-11-08 18:53:01Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -46,7 +46,6 @@ #include #include #include -#include #include "STTypes.h" #include "cpu_detect.h" @@ -91,7 +90,7 @@ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) channels = 2; pMidBuffer = NULL; - pRefMidBufferUnaligned = NULL; + pMidBufferUnaligned = NULL; overlapLength = 0; bAutoSeqSetting = TRUE; @@ -101,7 +100,7 @@ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) skipFract = 0; tempo = 1.0f; - setParameters(48000, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); setTempo(1.0f); clear(); @@ -111,8 +110,7 @@ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) TDStretch::~TDStretch() { - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; + delete[] pMidBufferUnaligned; } @@ -122,11 +120,11 @@ TDStretch::~TDStretch() // // 'sampleRate' = sample rate of the sound // 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) -// 'seekwindowMS' = seeking window length for scanning the best overlapping +// 'seekwindowMS' = seeking window length for scanning the best overlapping // position (default = 28 ms) // 'overlapMS' = overlapping length (default = 12 ms) -void TDStretch::setParameters(int aSampleRate, int aSequenceMS, +void TDStretch::setParameters(int aSampleRate, int aSequenceMS, int aSeekWindowMS, int aOverlapMS) { // accept only positive parameter values - if zero or negative, use old values instead @@ -137,19 +135,19 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS, { this->sequenceMs = aSequenceMS; bAutoSeqSetting = FALSE; - } + } else if (aSequenceMS == 0) { // if zero, use automatic setting bAutoSeqSetting = TRUE; } - if (aSeekWindowMS > 0) + if (aSeekWindowMS > 0) { this->seekWindowMs = aSeekWindowMS; bAutoSeekSetting = FALSE; - } - else if (aSeekWindowMS == 0) + } + else if (aSeekWindowMS == 0) { // if zero, use automatic setting bAutoSeekSetting = TRUE; @@ -196,12 +194,17 @@ void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWind // Overlaps samples in 'midBuffer' with the samples in 'pInput' void TDStretch::overlapMono(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput) const { - int i, itemp; + int i; + SAMPLETYPE m1, m2; - for (i = 0; i < overlapLength ; i ++) + m1 = (SAMPLETYPE)0; + m2 = (SAMPLETYPE)overlapLength; + + for (i = 0; i < overlapLength ; i ++) { - itemp = overlapLength - i; - pOutput[i] = (pInput[i] * i + pMidBuffer[i] * itemp ) / overlapLength; // >> overlapDividerBits; + pOutput[i] = (pInput[i] * m1 + pMidBuffer[i] * m2 ) / overlapLength; + m1 += 1; + m2 -= 1; } } @@ -247,40 +250,22 @@ BOOL TDStretch::isQuickSeekEnabled() const // Seeks for the optimal overlap-mixing position. int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) { - if (channels == 2) + if (bQuickSeek) { - // stereo sound - if (bQuickSeek) - { - return seekBestOverlapPositionStereoQuick(refPos); - } - else - { - return seekBestOverlapPositionStereo(refPos); - } - } - else + return seekBestOverlapPositionQuick(refPos); + } + else { - // mono sound - if (bQuickSeek) - { - return seekBestOverlapPositionMonoQuick(refPos); - } - else - { - return seekBestOverlapPositionMono(refPos); - } + return seekBestOverlapPositionFull(refPos); } } - - // Overlaps samples in 'midBuffer' with the samples in 'pInputBuffer' at position // of 'ovlPos'. inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, uint ovlPos) const { - if (channels == 2) + if (channels == 2) { // stereo sound overlapStereo(pOutput, pInput + 2 * ovlPos); @@ -292,38 +277,34 @@ inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, ui - // Seeks for the optimal overlap-mixing position. The 'stereo' version of the // routine // // The best position is determined as the position where the two overlapped // sample sequences are 'most alike', in terms of the highest cross-correlation // value over the overlapping period -int TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) +int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) { int bestOffs; double bestCorr, corr; int i; - // Slopes the amplitudes of the 'midBuffer' samples - precalcCorrReferenceStereo(); - bestCorr = FLT_MIN; bestOffs = 0; // Scans for the best correlation value by testing each possible position // over the permitted range. - for (i = 0; i < seekLength; i ++) + for (i = 0; i < seekLength; i ++) { // Calculates correlation value for the mixing position corresponding // to 'i' - corr = (double)calcCrossCorrStereo(refPos + 2 * i, pRefMidBuffer); + corr = calcCrossCorr(refPos + channels * i, pMidBuffer); // 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)); // Checks for the highest correlation value - if (corr > bestCorr) + if (corr > bestCorr) { bestCorr = corr; bestOffs = i; @@ -342,16 +323,13 @@ int TDStretch::seekBestOverlapPositionStereo(const SAMPLETYPE *refPos) // The best position is determined as the position where the two overlapped // sample sequences are 'most alike', in terms of the highest cross-correlation // value over the overlapping period -int TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) +int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) { int j; int bestOffs; double bestCorr, corr; int scanCount, corrOffset, tempOffset; - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceStereo(); - bestCorr = FLT_MIN; bestOffs = _scanOffsets[0][0]; corrOffset = 0; @@ -360,26 +338,26 @@ int TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) // Scans for the best correlation value using four-pass hierarchical search. // // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with + // In first pass the routine searhes for the highest correlation with // relatively coarse steps, then rescans the neighbourhood of the highest // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) + for (scanCount = 0;scanCount < 4; scanCount ++) { j = 0; - while (_scanOffsets[scanCount][j]) + while (_scanOffsets[scanCount][j]) { tempOffset = corrOffset + _scanOffsets[scanCount][j]; if (tempOffset >= seekLength) break; // Calculates correlation value for the mixing position corresponding // to 'tempOffset' - corr = (double)calcCrossCorrStereo(refPos + 2 * tempOffset, pRefMidBuffer); + corr = (double)calcCrossCorr(refPos + channels * tempOffset, pMidBuffer); // 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)); // Checks for the highest correlation value - if (corr > bestCorr) + if (corr > bestCorr) { bestCorr = corr; bestOffs = tempOffset; @@ -396,112 +374,7 @@ int TDStretch::seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos) -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -int TDStretch::seekBestOverlapPositionMono(const SAMPLETYPE *refPos) -{ - int bestOffs; - double bestCorr, corr; - int tempOffset; - const SAMPLETYPE *compare; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = FLT_MIN; - bestOffs = 0; - - // Scans for the best correlation value by testing each possible position - // over the permitted range. - for (tempOffset = 0; tempOffset < seekLength; tempOffset ++) - { - compare = refPos + tempOffset; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = (double)calcCrossCorrMono(pRefMidBuffer, compare); - // 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)); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -// Seeks for the optimal overlap-mixing position. The 'mono' version of the -// routine -// -// The best position is determined as the position where the two overlapped -// sample sequences are 'most alike', in terms of the highest cross-correlation -// value over the overlapping period -int TDStretch::seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos) -{ - int j; - int bestOffs; - double bestCorr, corr; - int scanCount, corrOffset, tempOffset; - - // Slopes the amplitude of the 'midBuffer' samples - precalcCorrReferenceMono(); - - bestCorr = FLT_MIN; - bestOffs = _scanOffsets[0][0]; - corrOffset = 0; - tempOffset = 0; - - // Scans for the best correlation value using four-pass hierarchical search. - // - // The look-up table 'scans' has hierarchical position adjusting steps. - // In first pass the routine searhes for the highest correlation with - // relatively coarse steps, then rescans the neighbourhood of the highest - // correlation with better resolution and so on. - for (scanCount = 0;scanCount < 4; scanCount ++) - { - j = 0; - while (_scanOffsets[scanCount][j]) - { - tempOffset = corrOffset + _scanOffsets[scanCount][j]; - if (tempOffset >= seekLength) break; - - // Calculates correlation value for the mixing position corresponding - // to 'tempOffset' - corr = (double)calcCrossCorrMono(refPos + tempOffset, pRefMidBuffer); - // 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)); - - // Checks for the highest correlation value - if (corr > bestCorr) - { - bestCorr = corr; - bestOffs = tempOffset; - } - j ++; - } - corrOffset = bestOffs; - } - // clear cross correlation routine state if necessary (is so e.g. in MMX routines). - clearCrossCorrState(); - - return bestOffs; -} - - -/// clear cross correlation routine state if necessary +/// clear cross correlation routine state if necessary void TDStretch::clearCrossCorrState() { // default implementation is empty. @@ -531,7 +404,7 @@ void TDStretch::calcSeqParameters() #define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x))) double seq, seek; - + if (bAutoSeqSetting) { seq = AUTOSEQ_C + AUTOSEQ_K * tempo; @@ -548,7 +421,7 @@ void TDStretch::calcSeqParameters() // Update seek window lengths seekWindowLength = (sampleRate * sequenceMs) / 1000; - if (seekWindowLength < 2 * overlapLength) + if (seekWindowLength < 2 * overlapLength) { seekWindowLength = 2 * overlapLength; } @@ -557,7 +430,7 @@ void TDStretch::calcSeqParameters() -// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower // tempo, larger faster tempo. void TDStretch::setTempo(float newTempo) { @@ -568,11 +441,11 @@ void TDStretch::setTempo(float newTempo) // Calculate new sequence duration calcSeqParameters(); - // Calculate ideal skip length (according to tempo value) + // Calculate ideal skip length (according to tempo value) nominalSkip = tempo * (seekWindowLength - overlapLength); intskip = (int)(nominalSkip + 0.5f); - // Calculate how many samples are needed in the 'inputBuffer' to + // Calculate how many samples are needed in the 'inputBuffer' to // process another batch of samples //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2; sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength; @@ -600,18 +473,18 @@ void TDStretch::processNominalTempo() { assert(tempo == 1.0f); - if (bMidBufferDirty) + if (bMidBufferDirty) { // If there are samples in pMidBuffer waiting for overlapping, - // do a single sliding overlapping with them in order to prevent a + // do a single sliding overlapping with them in order to prevent a // clicking distortion in the output sound - if (inputBuffer.numSamples() < overlapLength) + if (inputBuffer.numSamples() < overlapLength) { // wait until we've got overlapLength input samples return; } - // Mix the samples in the beginning of 'inputBuffer' with the - // samples in 'midBuffer' using sliding overlapping + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); outputBuffer.putSamples(overlapLength); inputBuffer.receiveSamples(overlapLength); @@ -636,7 +509,7 @@ void TDStretch::processSamples() /* Removed this small optimization - can introduce a click to sound when tempo setting crosses the nominal value - if (tempo == 1.0f) + if (tempo == 1.0f) { // tempo not changed from the original, so bypass the processing processNominalTempo(); @@ -646,14 +519,13 @@ void TDStretch::processSamples() // Process samples as long as there are enough samples in 'inputBuffer' // to form a processing frame. -// while ((int)inputBuffer.numSamples() >= sampleReq - (outDebt / 4)) - while ((int)inputBuffer.numSamples() >= sampleReq) + while ((int)inputBuffer.numSamples() >= sampleReq) { // If tempo differs from the normal ('SCALE'), scan for the best overlapping // position offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); - // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // Mix the samples in the 'inputBuffer' at position of 'offset' with the // samples in 'midBuffer' using sliding overlapping // ... first partially overlap with the end of the previous sequence // (that's in 'midBuffer') @@ -661,16 +533,8 @@ void TDStretch::processSamples() outputBuffer.putSamples((uint)overlapLength); // ... then copy sequence samples from 'inputBuffer' to output: - temp = (seekLength / 2 - offset); - - // compensate cumulated output length diff vs. ideal output -// temp -= outDebt / 4; - - // update ideal vs. true output difference -// outDebt += temp; // length of sequence -// temp += (seekWindowLength - 2 * overlapLength); temp = (seekWindowLength - 2 * overlapLength); // crosscheck that we don't have buffer overflow... @@ -681,11 +545,11 @@ void TDStretch::processSamples() outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), (uint)temp); - // Copies the end of the current sequence from 'inputBuffer' to - // 'midBuffer' for being mixed with the beginning of the next + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next // processing sequence and so on assert((offset + temp + overlapLength * 2) <= (int)inputBuffer.numSamples()); - memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp + overlapLength), + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp + overlapLength), channels * sizeof(SAMPLETYPE) * overlapLength); // Remove the processed samples from the input buffer. Update @@ -722,26 +586,24 @@ void TDStretch::acceptNewOverlapLength(int newOverlapLength) if (overlapLength > prevOvl) { - delete[] pMidBuffer; - delete[] pRefMidBufferUnaligned; + delete[] pMidBufferUnaligned; + + pMidBufferUnaligned = new SAMPLETYPE[overlapLength * 2 + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pMidBuffer' is aligned to 16 byte boundary for efficiency + pMidBuffer = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(pMidBufferUnaligned); - pMidBuffer = new SAMPLETYPE[overlapLength * 2]; clearMidBuffer(); - - pRefMidBufferUnaligned = new SAMPLETYPE[2 * overlapLength + 16 / sizeof(SAMPLETYPE)]; - // ensure that 'pRefMidBuffer' is aligned to 16 byte boundary for efficiency - pRefMidBuffer = (SAMPLETYPE *)((((ulong)pRefMidBufferUnaligned) + 15) & (ulong)-16); } } -// Operator 'new' is overloaded so that it automatically creates a suitable instance +// 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 * TDStretch::operator new(size_t s) { // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! - throw std::runtime_error("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"); - return NULL; + ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"); + return newInstance(); } @@ -751,36 +613,26 @@ TDStretch * TDStretch::newInstance() uExtensions = detectCPUextensions(); - // Check if MMX/SSE/3DNow! instruction set extensions supported by CPU + // Check if MMX/SSE instruction set extensions supported by CPU -#ifdef ALLOW_MMX +#ifdef SOUNDTOUCH_ALLOW_MMX // MMX routines available only with integer sample types if (uExtensions & SUPPORT_MMX) { return ::new TDStretchMMX; } else -#endif // ALLOW_MMX +#endif // SOUNDTOUCH_ALLOW_MMX -#ifdef ALLOW_SSE +#ifdef SOUNDTOUCH_ALLOW_SSE if (uExtensions & SUPPORT_SSE) { // SSE support return ::new TDStretchSSE; } else -#endif // ALLOW_SSE - - -#ifdef ALLOW_3DNOW - if (uExtensions & SUPPORT_3DNOW) - { - // 3DNow! support - return ::new TDStretch3DNow; - } - else -#endif // ALLOW_3DNOW +#endif // SOUNDTOUCH_ALLOW_SSE { // ISA optimizations not supported, use plain C version @@ -795,46 +647,9 @@ TDStretch * TDStretch::newInstance() // ////////////////////////////////////////////////////////////////////////////// -#ifdef INTEGER_SAMPLES +#ifdef SOUNDTOUCH_INTEGER_SAMPLES -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - int temp, temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - cnt2 = i * 2; - - temp2 = (pMidBuffer[cnt2] * temp) / slopingDivider; - pRefMidBuffer[cnt2] = (short)(temp2); - temp2 = (pMidBuffer[cnt2 + 1] * temp) / slopingDivider; - pRefMidBuffer[cnt2 + 1] = (short)(temp2); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - long temp; - long temp2; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = i * (overlapLength - i); - temp2 = (pMidBuffer[i] * temp) / slopingDivider; - pRefMidBuffer[i] = (short)temp2; - } -} - - -// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' // version of the routine. void TDStretch::overlapStereo(short *poutput, const short *input) const { @@ -842,7 +657,7 @@ void TDStretch::overlapStereo(short *poutput, const short *input) const short temp; int cnt2; - for (i = 0; i < overlapLength ; i ++) + for (i = 0; i < overlapLength ; i ++) { temp = (short)(overlapLength - i); cnt2 = 2 * i; @@ -868,8 +683,8 @@ void TDStretch::calculateOverlapLength(int aoverlapMs) assert(aoverlapMs >= 0); // calculate overlap length so that it's power of 2 - thus it's easy to do - // integer division by right-shifting. Term "-1" at end is to account for - // the extra most significatnt bit left unused in result by signed multiplication + // integer division by right-shifting. Term "-1" at end is to account for + // the extra most significatnt bit left unused in result by signed multiplication overlapDividerBits = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1; if (overlapDividerBits > 9) overlapDividerBits = 9; if (overlapDividerBits < 3) overlapDividerBits = 3; @@ -877,113 +692,70 @@ void TDStretch::calculateOverlapLength(int aoverlapMs) acceptNewOverlapLength(newOvl); - // calculate sloping divider so that crosscorrelation operation won't - // overflow 32-bit register. Max. sum of the crosscorrelation sum without + // calculate sloping divider so that crosscorrelation operation won't + // overflow 32-bit register. Max. sum of the crosscorrelation sum without // divider would be 2^30*(N^3-N)/3, where N = overlap length slopingDivider = (newOvl * newOvl - 1) / 3; } -long TDStretch::calcCrossCorrMono(const short *mixingPos, const short *compare) const +double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare) const { long corr; long norm; int i; corr = norm = 0; - for (i = 1; i < overlapLength; i ++) + // 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]) >> overlapDividerBits; - norm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBits; + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1] + + 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; } - // Normalize result by dividing by sqrt(norm) - this step is easiest + // 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 (long)((double)corr * SHRT_MAX / sqrt((double)norm)); + return (double)corr / sqrt((double)norm); } - -long TDStretch::calcCrossCorrStereo(const short *mixingPos, const short *compare) const -{ - long corr; - long norm; - int i; - - corr = norm = 0; - for (i = 2; i < 2 * overlapLength; i += 2) - { - corr += (mixingPos[i] * compare[i] + - mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBits; - norm += (mixingPos[i] * mixingPos[i] + mixingPos[i + 1] * mixingPos[i + 1]) >> 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 (long)((double)corr * SHRT_MAX / sqrt((double)norm)); -} - -#endif // INTEGER_SAMPLES +#endif // SOUNDTOUCH_INTEGER_SAMPLES ////////////////////////////////////////////////////////////////////////////// // // Floating point arithmetics specific algorithm implementations. // -#ifdef FLOAT_SAMPLES - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceStereo() -{ - int i, cnt2; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - cnt2 = i * 2; - pRefMidBuffer[cnt2] = (float)(pMidBuffer[cnt2] * temp); - pRefMidBuffer[cnt2 + 1] = (float)(pMidBuffer[cnt2 + 1] * temp); - } -} - - -// Slopes the amplitude of the 'midBuffer' samples so that cross correlation -// is faster to calculate -void TDStretch::precalcCorrReferenceMono() -{ - int i; - float temp; - - for (i=0 ; i < (int)overlapLength ;i ++) - { - temp = (float)i * (float)(overlapLength - i); - pRefMidBuffer[i] = (float)(pMidBuffer[i] * temp); - } -} - +#ifdef SOUNDTOUCH_FLOAT_SAMPLES // Overlaps samples in 'midBuffer' with the samples in 'pInput' void TDStretch::overlapStereo(float *pOutput, const float *pInput) const { int i; - int cnt2; - float fTemp; float fScale; - float fi; + float f1; + float f2; fScale = 1.0f / (float)overlapLength; - for (i = 0; i < (int)overlapLength ; i ++) + f1 = 0; + f2 = 1.0f; + + for (i = 0; i < 2 * (int)overlapLength ; i += 2) { - fTemp = (float)(overlapLength - i) * fScale; - fi = (float)i * fScale; - cnt2 = 2 * i; - pOutput[cnt2 + 0] = pInput[cnt2 + 0] * fi + pMidBuffer[cnt2 + 0] * fTemp; - pOutput[cnt2 + 1] = pInput[cnt2 + 1] * fi + pMidBuffer[cnt2 + 1] * fTemp; + pOutput[i + 0] = pInput[i + 0] * f1 + pMidBuffer[i + 0] * f2; + pOutput[i + 1] = pInput[i + 1] * f1 + pMidBuffer[i + 1] * f2; + + f1 += fScale; + f2 -= fScale; } } @@ -1004,42 +776,33 @@ void TDStretch::calculateOverlapLength(int overlapInMsec) } - -double TDStretch::calcCrossCorrMono(const float *mixingPos, const float *compare) const +double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare) const { double corr; double norm; int i; corr = norm = 0; - for (i = 1; i < overlapLength; i ++) - { - corr += mixingPos[i] * compare[i]; - norm += mixingPos[i] * mixingPos[i]; - } - - if (norm < 1e-9) norm = 1.0; // to avoid div by zero - return corr / sqrt(norm); -} - - -double TDStretch::calcCrossCorrStereo(const float *mixingPos, const float *compare) const -{ - double corr; - double norm; - int i; - - corr = norm = 0; - for (i = 2; i < 2 * overlapLength; i += 2) + // 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]; - norm += mixingPos[i] * mixingPos[i] + + + norm += mixingPos[i] * mixingPos[i] + mixingPos[i + 1] * mixingPos[i + 1]; + + // unroll the loop for better CPU efficiency: + corr += mixingPos[i + 2] * compare[i + 2] + + mixingPos[i + 3] * compare[i + 3]; + + norm += mixingPos[i + 2] * mixingPos[i + 2] + + mixingPos[i + 3] * mixingPos[i + 3]; } if (norm < 1e-9) norm = 1.0; // to avoid div by zero return corr / sqrt(norm); } -#endif // FLOAT_SAMPLES +#endif // SOUNDTOUCH_FLOAT_SAMPLES diff --git a/3rdparty/SoundTouch/TDStretch.h b/3rdparty/SoundTouch/TDStretch.h index 1962d818a1..6861251014 100644 --- a/3rdparty/SoundTouch/TDStretch.h +++ b/3rdparty/SoundTouch/TDStretch.h @@ -1,10 +1,10 @@ //////////////////////////////////////////////////////////////////////////////// -/// -/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo -/// while maintaining the original pitch by using a time domain WSOLA-like method +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method /// with several performance-increasing tweaks. /// -/// Note : MMX/SSE optimized functions reside in separate, platform-specific files +/// Note : MMX/SSE optimized functions reside in separate, platform-specific files /// 'mmx_optimized.cpp' and 'sse_optimized.cpp' /// /// Author : Copyright (c) Olli Parviainen @@ -13,10 +13,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-05-17 14:35:13 +0300 (Sun, 17 May 2009) $ +// Last changed : $Date: 2012-04-01 16:49:30 -0300 (dom, 01 abr 2012) $ // File revision : $Revision: 4 $ // -// $Id: TDStretch.h 71 2009-05-17 11:35:13Z oparviai $ +// $Id: TDStretch.h 137 2012-04-01 19:49:30Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -53,14 +53,14 @@ namespace soundtouch { /// Default values for sound processing parameters: -/// Notice that the default parameters are tuned for contemporary popular music +/// Notice that the default parameters are tuned for contemporary popular music /// processing. For speech processing applications these parameters suit better: /// #define DEFAULT_SEQUENCE_MS 40 /// #define DEFAULT_SEEKWINDOW_MS 15 /// #define DEFAULT_OVERLAP_MS 8 /// -/// Default length of a single processing sequence, in milliseconds. This determines to how +/// Default length of a single processing sequence, in milliseconds. This determines to how /// long sequences the original sound is chopped in the time-stretch algorithm. /// /// The larger this value is, the lesser sequences are used in processing. In principle @@ -75,15 +75,15 @@ namespace soundtouch /// according to tempo setting (recommended) #define USE_AUTO_SEQUENCE_LEN 0 -/// Seeking window default length in milliseconds for algorithm that finds the best possible -/// overlapping location. This determines from how wide window the algorithm may look for an -/// optimal joining location when mixing the sound sequences back together. +/// Seeking window default length in milliseconds for algorithm that finds the best possible +/// overlapping location. This determines from how wide window the algorithm may look for an +/// optimal joining location when mixing the sound sequences back together. /// /// The bigger this window setting is, the higher the possibility to find a better mixing /// position will become, but at the same time large values may cause a "drifting" artifact /// because consequent sequences will be taken at more uneven intervals. /// -/// If there's a disturbing artifact that sounds as if a constant frequency was drifting +/// If there's a disturbing artifact that sounds as if a constant frequency was drifting /// around, try reducing this setting. /// /// Increasing this value increases computational burden & vice versa. @@ -94,11 +94,11 @@ namespace soundtouch /// according to tempo setting (recommended) #define USE_AUTO_SEEKWINDOW_LEN 0 -/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, -/// to form a continuous sound stream, this parameter defines over how long period the two -/// consecutive sequences are let to overlap each other. +/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, +/// to form a continuous sound stream, this parameter defines over how long period the two +/// consecutive sequences are let to overlap each other. /// -/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting +/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting /// by a large amount, you might wish to try a smaller value on this. /// /// Increasing this value increases computational burden & vice versa. @@ -115,8 +115,7 @@ protected: float tempo; SAMPLETYPE *pMidBuffer; - SAMPLETYPE *pRefMidBuffer; - SAMPLETYPE *pRefMidBufferUnaligned; + SAMPLETYPE *pMidBufferUnaligned; int overlapLength; int seekLength; int seekWindowLength; @@ -127,8 +126,6 @@ protected: FIFOSampleBuffer outputBuffer; FIFOSampleBuffer inputBuffer; BOOL bQuickSeek; -// int outDebt; -// BOOL bMidBufferDirty; int sampleRate; int sequenceMs; @@ -142,13 +139,10 @@ protected: virtual void clearCrossCorrState(); void calculateOverlapLength(int overlapMs); - virtual LONG_SAMPLETYPE calcCrossCorrStereo(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - virtual LONG_SAMPLETYPE calcCrossCorrMono(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; + virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const; - virtual int seekBestOverlapPositionStereo(const SAMPLETYPE *refPos); - virtual int seekBestOverlapPositionStereoQuick(const SAMPLETYPE *refPos); - virtual int seekBestOverlapPositionMono(const SAMPLETYPE *refPos); - virtual int seekBestOverlapPositionMonoQuick(const SAMPLETYPE *refPos); + virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos); + virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos); int seekBestOverlapPosition(const SAMPLETYPE *refPos); virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; @@ -157,9 +151,6 @@ protected: void clearMidBuffer(); void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; - void precalcCorrReferenceMono(); - void precalcCorrReferenceStereo(); - void calcSeqParameters(); /// Changes the tempo of the given sound samples. @@ -167,27 +158,27 @@ protected: /// The maximum amount of samples that can be returned at a time is set by /// the 'set_returnBuffer_size' function. void processSamples(); - + public: TDStretch(); virtual ~TDStretch(); - /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// 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. static void *operator new(size_t s); - /// Use this function instead of "new" operator to create a new instance of this class. + /// Use this function instead of "new" operator to create a new instance of this class. /// This function automatically chooses a correct feature set depending on if the CPU /// supports MMX/SSE/etc extensions. static TDStretch *newInstance(); - + /// Returns the output buffer object FIFOSamplePipe *getOutput() { return &outputBuffer; }; /// Returns the input buffer object FIFOSamplePipe *getInput() { return &inputBuffer; }; - /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower /// tempo, larger faster tempo. void setTempo(float newTempo); @@ -200,7 +191,7 @@ public: /// Sets the number of channels, 1 = mono, 2 = stereo void setChannels(int numChannels); - /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// Enables/disables the quick position seeking algorithm. Zero to disable, /// nonzero to enable void enableQuickSeek(BOOL enable); @@ -212,7 +203,7 @@ public: // /// 'sampleRate' = sample rate of the sound /// 'sequenceMS' = one processing sequence length in milliseconds - /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// 'seekwindowMS' = seeking window length for scanning the best overlapping /// position /// 'overlapMS' = overlapping length void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz) @@ -233,43 +224,45 @@ public: uint numSamples ///< Number of samples in 'samples' so that one sample ///< contains both channels if stereo ); + + /// return nominal input sample requirement for triggering a processing batch + int getInputSampleReq() const + { + return (int)(nominalSkip + 0.5); + } + + /// return nominal output sample amount when running a processing batch + int getOutputBatchSize() const + { + return seekWindowLength - overlapLength; + } }; // Implementation-specific class declarations: -#ifdef ALLOW_MMX +#ifdef SOUNDTOUCH_ALLOW_MMX /// Class that implements MMX optimized routines for 16bit integer samples type. class TDStretchMMX : public TDStretch { protected: - long calcCrossCorrStereo(const short *mixingPos, const short *compare) const; + double calcCrossCorr(const short *mixingPos, const short *compare) const; virtual void overlapStereo(short *output, const short *input) const; virtual void clearCrossCorrState(); }; -#endif /// ALLOW_MMX +#endif /// SOUNDTOUCH_ALLOW_MMX -#ifdef ALLOW_3DNOW - /// Class that implements 3DNow! optimized routines for floating point samples type. - class TDStretch3DNow : public TDStretch - { - protected: - double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; - }; -#endif /// ALLOW_3DNOW - - -#ifdef ALLOW_SSE +#ifdef SOUNDTOUCH_ALLOW_SSE /// Class that implements SSE optimized routines for floating point samples type. class TDStretchSSE : public TDStretch { protected: - double calcCrossCorrStereo(const float *mixingPos, const float *compare) const; + double calcCrossCorr(const float *mixingPos, const float *compare) const; }; -#endif /// ALLOW_SSE +#endif /// SOUNDTOUCH_ALLOW_SSE } #endif /// TDStretch_H diff --git a/3rdparty/SoundTouch/cpu_detect.h b/3rdparty/SoundTouch/cpu_detect.h index 33c5026ce0..809f841b3d 100644 --- a/3rdparty/SoundTouch/cpu_detect.h +++ b/3rdparty/SoundTouch/cpu_detect.h @@ -2,8 +2,8 @@ /// /// A header file for detecting the Intel MMX instructions set extension. /// -/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the -/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 /// platforms, respectively. /// /// Author : Copyright (c) Olli Parviainen @@ -12,7 +12,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ +// Last changed : $Date: 2008-02-10 14:26:55 -0200 (dom, 10 fev 2008) $ // File revision : $Revision: 4 $ // // $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $ diff --git a/3rdparty/SoundTouch/cpu_detect_x86.cpp b/3rdparty/SoundTouch/cpu_detect_x86.cpp new file mode 100644 index 0000000000..4b09dba20b --- /dev/null +++ b/3rdparty/SoundTouch/cpu_detect_x86.cpp @@ -0,0 +1,137 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Generic version of the x86 CPU extension detection routine. +/// +/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' +/// for the Microsoft compiler version. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// Last changed : $Date: 2012-11-08 16:44:37 -0200 (qui, 08 nov 2012) $ +// File revision : $Revision: 4 $ +// +// $Id: cpu_detect_x86.cpp 159 2012-11-08 18:44:37Z 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 "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 + #define bit_MMX (1 << 23) + #define bit_SSE (1 << 25) + #define bit_SSE2 (1 << 26) + #endif + +#endif + + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +/// If building for a 64bit system (no Itanium) and the user wants optimizations. +/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19. +/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). +#if ((defined(__GNUC__) && defined(__x86_64__)) \ + || defined(_M_X64)) \ + && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) + return 0x19 & ~_dwDisabledISA; + +/// If building for a 32bit system and the user wants optimizations. +/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). +#elif ((defined(__GNUC__) && defined(__i386__)) \ + || defined(_M_IX86)) \ + && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) + + if (_dwDisabledISA == 0xffffffff) return 0; + + uint res = 0; + +#if defined(__GNUC__) + // GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support. + uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable. + + // Check if no cpuid support. + if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions. + + if (edx & bit_MMX) res = res | SUPPORT_MMX; + if (edx & bit_SSE) res = res | SUPPORT_SSE; + if (edx & bit_SSE2) res = res | SUPPORT_SSE2; + +#else + // Window / VS version of cpuid. Notice that Visual Studio 2005 or later required + // for __cpuid intrinsic support. + int reg[4] = {-1}; + + // Check if no cpuid support. + __cpuid(reg,0); + if ((unsigned int)reg[0] == 0) return 0; // always disable extensions. + + __cpuid(reg,1); + if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX; + if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE; + if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2; + +#endif + + return res & ~_dwDisabledISA; + +#else + +/// One of these is true: +/// 1) We don't want optimizations. +/// 2) Using an unsupported compiler. +/// 3) Running on a non-x86 platform. + return 0; + +#endif +} diff --git a/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp b/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp index 806de7f288..dbb79236bc 100644 --- a/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp +++ b/3rdparty/SoundTouch/cpu_detect_x86_gcc.cpp @@ -2,7 +2,7 @@ /// /// Generic version of the x86 CPU extension detection routine. /// -/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' +/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' /// for the Microsoft compiler version. /// /// Author : Copyright (c) Olli Parviainen @@ -11,10 +11,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-25 19:13:51 +0200 (Wed, 25 Feb 2009) $ +// Last changed : $Date: 2011-09-02 15:56:11 -0300 (sex, 02 set 2011) $ // File revision : $Revision: 4 $ // -// $Id: cpu_detect_x86_gcc.cpp 67 2009-02-25 17:13:51Z oparviai $ +// $Id: cpu_detect_x86_gcc.cpp 131 2011-09-02 18:56:11Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -39,15 +39,9 @@ // //////////////////////////////////////////////////////////////////////////////// -#include -#include #include "cpu_detect.h" #include "STTypes.h" -using namespace std; - -#include - ////////////////////////////////////////////////////////////////////////////// // // processor instructions extension detection routines @@ -68,7 +62,7 @@ void disableExtensions(uint dwDisableMask) /// Checks which instruction set extensions are supported by the CPU. uint detectCPUextensions(void) { -#if (!(ALLOW_X86_OPTIMIZATIONS) || !(__GNUC__)) +#if (!(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) || !(__GNUC__)) return 0; // always disable extensions on non-x86 platforms. @@ -78,8 +72,11 @@ uint detectCPUextensions(void) if (_dwDisabledISA == 0xffffffff) return 0; asm volatile( +#ifndef __x86_64__ + // Check if 'cpuid' instructions is available by toggling eflags bit 21. + // Skip this for x86-64 as they always have cpuid while stack manipulation + // differs from 16/32bit ISA. "\n\txor %%esi, %%esi" // clear %%esi = result register - // check if 'cpuid' instructions is available by toggling eflags bit 21 "\n\tpushf" // save eflags to stack "\n\tmovl (%%esp), %%eax" // load eax from stack (with eflags) @@ -93,6 +90,8 @@ uint detectCPUextensions(void) "\n\txor %%edx, %%edx" // clear edx for defaulting no mmx "\n\tcmp %%ecx, %%eax" // compare to original eflags values "\n\tjz end" // jumps to 'end' if cpuid not present +#endif // __x86_64__ + // cpuid instruction available, test for presence of mmx instructions "\n\tmovl $1, %%eax" @@ -129,7 +128,7 @@ uint detectCPUextensions(void) : "=r" (res) : /* no inputs */ : "%edx", "%eax", "%ecx", "%esi" ); - + return res & ~_dwDisabledISA; #endif } diff --git a/3rdparty/SoundTouch/cpu_detect_x86_win.cpp b/3rdparty/SoundTouch/cpu_detect_x86_win.cpp index 883a3accc0..666c7b0700 100644 --- a/3rdparty/SoundTouch/cpu_detect_x86_win.cpp +++ b/3rdparty/SoundTouch/cpu_detect_x86_win.cpp @@ -2,8 +2,8 @@ /// /// Win32 version of the x86 CPU detect routine. /// -/// This file is to be compiled in Windows platform with Microsoft Visual C++ -/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version +/// This file is to be compiled in Windows platform with Microsoft Visual C++ +/// Compiler. Please see 'cpu_detect_x86_gcc.cpp' for the gcc compiler version /// for all GNU platforms. /// /// Author : Copyright (c) Olli Parviainen @@ -12,10 +12,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-02-13 18:22:48 +0200 (Fri, 13 Feb 2009) $ +// Last changed : $Date: 2011-07-17 07:58:40 -0300 (dom, 17 jul 2011) $ // File revision : $Revision: 4 $ // -// $Id: cpu_detect_x86_win.cpp 62 2009-02-13 16:22:48Z oparviai $ +// $Id: cpu_detect_x86_win.cpp 127 2011-07-17 10:58:40Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -42,9 +42,7 @@ #include "cpu_detect.h" -#ifndef WIN32 -#error wrong platform - this source code file is exclusively for Win32 platform -#endif +#include "STTypes.h" ////////////////////////////////////////////////////////////////////////////// // @@ -71,7 +69,9 @@ uint detectCPUextensions(void) if (_dwDisabledISA == 0xffffffff) return 0; - _asm +#ifndef _M_X64 + // 32bit compilation, detect CPU capabilities with inline assembler. + __asm { ; check if 'cpuid' instructions is available by toggling eflags bit 21 ; @@ -92,7 +92,7 @@ uint detectCPUextensions(void) cmp eax, ecx ; compare to original eflags values jz end ; jumps to 'end' if cpuid not present - ; cpuid instruction available, test for presence of mmx instructions + ; cpuid instruction available, test for presence of mmx instructions mov eax, 1 cpuid test edx, 0x00800000 @@ -125,5 +125,13 @@ uint detectCPUextensions(void) mov res, esi } +#else + + // Visual C++ 64bit compilation doesn't support inline assembler. However, + // all x64 compatible CPUs support MMX & SSE extensions. + res = SUPPORT_MMX | SUPPORT_SSE | SUPPORT_SSE2; + +#endif + return res & ~_dwDisabledISA; } diff --git a/3rdparty/SoundTouch/mmx_optimized.cpp b/3rdparty/SoundTouch/mmx_optimized.cpp index 477119529a..15d8af1b76 100644 --- a/3rdparty/SoundTouch/mmx_optimized.cpp +++ b/3rdparty/SoundTouch/mmx_optimized.cpp @@ -1,15 +1,15 @@ //////////////////////////////////////////////////////////////////////////////// /// -/// MMX optimized routines. All MMX optimized functions have been gathered into -/// this single source code file, regardless to their class or original source -/// code file, in order to ease porting the library to other compiler and +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and /// processor platforms. /// /// The MMX-optimizations are programmed using MMX compiler intrinsics that /// are supported both by Microsoft Visual C++ and GCC compilers, so this file /// should compile with both toolsets. /// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ /// 6.0 processor pack" update to support compiler intrinsic syntax. The update /// is available for download at Microsoft Developers Network, see here: /// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx @@ -20,10 +20,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-10-31 16:53:23 +0200 (Sat, 31 Oct 2009) $ +// Last changed : $Date: 2012-11-08 16:53:01 -0200 (qui, 08 nov 2012) $ // File revision : $Revision: 4 $ // -// $Id: mmx_optimized.cpp 75 2009-10-31 14:53:23Z oparviai $ +// $Id: mmx_optimized.cpp 160 2012-11-08 18:53:01Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -50,13 +50,9 @@ #include "STTypes.h" -#ifdef ALLOW_MMX +#ifdef SOUNDTOUCH_ALLOW_MMX // MMX routines available only with integer sample type -#if !(WIN32 || __i386__ || __x86_64__) -#error "wrong platform - this source code file is exclusively for x86 platforms" -#endif - using namespace soundtouch; ////////////////////////////////////////////////////////////////////////////// @@ -72,23 +68,23 @@ using namespace soundtouch; // Calculates cross correlation of two buffers -long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const +double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2) const { const __m64 *pVec1, *pVec2; __m64 shifter; __m64 accu, normaccu; long corr, norm; int i; - + pVec1 = (__m64*)pV1; pVec2 = (__m64*)pV2; shifter = _m_from_int(overlapDividerBits); normaccu = accu = _mm_setzero_si64(); - // Process 4 parallel sets of 2 * stereo samples each during each - // round to improve CPU-level parallellization. - for (i = 0; i < overlapLength / 8; i ++) + // 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, temp2; @@ -127,10 +123,11 @@ long TDStretchMMX::calcCrossCorrStereo(const short *pV1, const short *pV2) const // Clear MMS state _m_empty(); - // Normalize result by dividing by sqrt(norm) - this step is easiest + // 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 (long)((double)corr * USHRT_MAX / sqrt((double)norm)); + + return (double)corr / sqrt((double)norm); // Note: Warning about the missing EMMS instruction is harmless // as it'll be called elsewhere. } @@ -161,7 +158,7 @@ void TDStretchMMX::overlapStereo(short *output, const short *input) const // mix1 = mixer values for 1st stereo sample // mix1 = mixer values for 2nd stereo sample // adder = adder for updating mixer values after each round - + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); adder = _mm_set_pi16(1, -1, 1, -1); mix2 = _mm_add_pi16(mix1, adder); @@ -174,7 +171,7 @@ void TDStretchMMX::overlapStereo(short *output, const short *input) const for (i = 0; i < overlapLength / 4; i ++) { __m64 temp1, temp2; - + // load & shuffle data so that input & mixbuffer data samples are paired temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r @@ -242,10 +239,10 @@ void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uRe // Ensure that filter coeffs array is aligned to 16-byte boundary delete[] filterCoeffsUnalign; filterCoeffsUnalign = new short[2 * newLength + 8]; - filterCoeffsAlign = (short *)(((ulong)filterCoeffsUnalign + 15) & -16); + filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); - // rearrange the filter coefficients for mmx routines - for (i = 0;i < length; i += 4) + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) { filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; @@ -317,4 +314,4 @@ uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numS return (numSamples & 0xfffffffe) - length; } -#endif // ALLOW_MMX +#endif // SOUNDTOUCH_ALLOW_MMX diff --git a/3rdparty/SoundTouch/sse_optimized.cpp b/3rdparty/SoundTouch/sse_optimized.cpp index 7edd1cb79e..3566252cad 100644 --- a/3rdparty/SoundTouch/sse_optimized.cpp +++ b/3rdparty/SoundTouch/sse_optimized.cpp @@ -1,20 +1,20 @@ //////////////////////////////////////////////////////////////////////////////// /// -/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE -/// optimized functions have been gathered into this single source -/// code file, regardless to their class or original source code file, in order +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order /// to ease porting the library to other compiler and processor platforms. /// /// The SSE-optimizations are programmed using SSE compiler intrinsics that /// are supported both by Microsoft Visual C++ and GCC compilers, so this file /// should compile with both toolsets. /// -/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ -/// 6.0 processor pack" update to support SSE instruction set. The update is +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is /// available for download at Microsoft Developers Network, see here: /// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx /// -/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and /// perform a search with keywords "processor pack". /// /// Author : Copyright (c) Olli Parviainen @@ -23,10 +23,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2009-12-28 22:32:57 +0200 (Mon, 28 Dec 2009) $ +// Last changed : $Date: 2012-11-08 16:53:01 -0200 (qui, 08 nov 2012) $ // File revision : $Revision: 4 $ // -// $Id: sse_optimized.cpp 80 2009-12-28 20:32:57Z oparviai $ +// $Id: sse_optimized.cpp 160 2012-11-08 18:53:01Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -56,9 +56,9 @@ using namespace soundtouch; -#ifdef ALLOW_SSE +#ifdef SOUNDTOUCH_ALLOW_SSE -// SSE routines available only with float sample type +// SSE routines available only with float sample type ////////////////////////////////////////////////////////////////////////////// // @@ -71,35 +71,35 @@ using namespace soundtouch; #include // Calculates cross correlation of two buffers -double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) const +double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2) const { int i; const float *pVec1; const __m128 *pVec2; __m128 vSum, vNorm; - // Note. It means a major slow-down if the routine needs to tolerate - // unaligned __m128 memory accesses. It's way faster if we can skip + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. // This can mean up to ~ 10-fold difference (incl. part of which is // due to skipping every second round for stereo sound though). // - // Compile-time define ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided // for choosing if this little cheating is allowed. -#ifdef ALLOW_NONEXACT_SIMD_OPTIMIZATION - // Little cheating allowed, return valid correlation only for +#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION + // Little cheating allowed, return valid correlation only for // aligned locations, meaning every second round for stereo sound. #define _MM_LOAD _mm_load_ps - if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations + if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations #else // No cheating allowed, use unaligned load & take the resulting // performance hit. #define _MM_LOAD _mm_loadu_ps -#endif +#endif // ensure overlapLength is divisible by 8 assert((overlapLength % 8) == 0); @@ -110,8 +110,9 @@ double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) con pVec2 = (const __m128*)pV2; vSum = vNorm = _mm_setzero_ps(); - // Unroll the loop by factor of 4 * 4 operations - for (i = 0; i < overlapLength / 8; i ++) + // Unroll the loop by factor of 4 * 4 operations. Use same routine for + // stereo & mono, for mono it just means twice the amount of unrolling. + for (i = 0; i < channels * overlapLength / 16; i ++) { __m128 vTemp; // vSum += pV1[0..3] * pV2[0..3] @@ -152,7 +153,7 @@ double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) con // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors corr = norm = 0.0; - for (i = 0; i < overlapLength / 8; i ++) + for (i = 0; i < channels * overlapLength / 16; i ++) { corr += pV1[0] * pV2[0] + pV1[1] * pV2[1] + @@ -171,81 +172,13 @@ double TDStretchSSE::calcCrossCorrStereo(const float *pV1, const float *pV2) con pV1[14] * pV2[14] + pV1[15] * pV2[15]; - for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j]; + for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j]; pV1 += 16; pV2 += 16; } return corr / sqrt(norm); */ - - /* This is a bit outdated, corresponding routine in assembler. This may be teeny-weeny bit - faster than intrinsic version, but more difficult to maintain & get compiled on multiple - platforms. - - uint overlapLengthLocal = overlapLength; - float corr; - - _asm - { - // Very important note: data in 'pV2' _must_ be aligned to - // 16-byte boundary! - - // give prefetch hints to CPU of what data are to be needed soonish - // give more aggressive hints on pV1 as that changes while pV2 stays - // same between runs - prefetcht0 [pV1] - prefetcht0 [pV2] - prefetcht0 [pV1 + 32] - - mov eax, dword ptr pV1 - mov ebx, dword ptr pV2 - - xorps xmm0, xmm0 - - mov ecx, overlapLengthLocal - shr ecx, 3 // div by eight - - loop1: - prefetcht0 [eax + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 32] // give a prefetch hint to CPU what data are to be needed soonish - movups xmm1, [eax] - mulps xmm1, [ebx] - addps xmm0, xmm1 - - movups xmm2, [eax + 16] - mulps xmm2, [ebx + 16] - addps xmm0, xmm2 - - prefetcht0 [eax + 96] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [ebx + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm3, [eax + 32] - mulps xmm3, [ebx + 32] - addps xmm0, xmm3 - - movups xmm4, [eax + 48] - mulps xmm4, [ebx + 48] - addps xmm0, xmm4 - - add eax, 64 - add ebx, 64 - - dec ecx - jnz loop1 - - // add the four floats of xmm0 together and return the result. - - movhlps xmm1, xmm0 // move 3 & 4 of xmm0 to 1 & 2 of xmm1 - addps xmm1, xmm0 - movaps xmm2, xmm1 - shufps xmm2, xmm2, 0x01 // move 2 of xmm2 as 1 of xmm2 - addss xmm2, xmm1 - movss corr, xmm2 - } - - return (double)corr; - */ } @@ -281,15 +214,15 @@ void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uRe FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); // Scale the filter coefficients so that it won't be necessary to scale the filtering result - // also rearrange coefficients suitably for 3DNow! + // also rearrange coefficients suitably for SSE // Ensure that filter coeffs array is aligned to 16-byte boundary delete[] filterCoeffsUnalign; filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & (ulong)-16); + filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); fDivider = (float)resultDivider; - // rearrange the filter coefficients for mmx routines + // rearrange the filter coefficients for mmx routines for (i = 0; i < newLength; i ++) { filterCoeffsAlign[2 * i + 0] = @@ -313,7 +246,7 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n assert(dest != NULL); assert((length % 8) == 0); assert(filterCoeffsAlign != NULL); - assert(((ulong)filterCoeffsAlign) % 16 == 0); + assert(((ulongptr)filterCoeffsAlign) % 16 == 0); // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' for (j = 0; j < count; j += 2) @@ -324,13 +257,13 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n uint i; pSrc = (const float*)source; // source audio data - pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients // are aligned to 16-byte boundary sum1 = sum2 = _mm_setzero_ps(); - for (i = 0; i < length / 8; i ++) + for (i = 0; i < length / 8; i ++) { - // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples // at each pass // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset @@ -365,14 +298,14 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n } // Ideas for further improvement: - // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte // boundary, a faster aligned '_mm_load_ps' instruction could be used. - // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte // boundary, a faster '_mm_store_ps' instruction could be used. return (uint)count; - /* original routine in C-language. please notice the C-version has differently + /* original routine in C-language. please notice the C-version has differently organized coefficients though. double suml1, suml2; double sumr1, sumr2; @@ -387,26 +320,26 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n suml2 = sumr2 = 0.0; ptr = src; pFil = filterCoeffs; - for (i = 0; i < lengthLocal; i ++) + for (i = 0; i < lengthLocal; i ++) { // unroll loop for efficiency. - suml1 += ptr[0] * pFil[0] + + suml1 += ptr[0] * pFil[0] + ptr[2] * pFil[2] + ptr[4] * pFil[4] + ptr[6] * pFil[6]; - sumr1 += ptr[1] * pFil[1] + + sumr1 += ptr[1] * pFil[1] + ptr[3] * pFil[3] + ptr[5] * pFil[5] + ptr[7] * pFil[7]; - suml2 += ptr[8] * pFil[0] + + suml2 += ptr[8] * pFil[0] + ptr[10] * pFil[2] + ptr[12] * pFil[4] + ptr[14] * pFil[6]; - sumr2 += ptr[9] * pFil[1] + + sumr2 += ptr[9] * pFil[1] + ptr[11] * pFil[3] + ptr[13] * pFil[5] + ptr[15] * pFil[7]; @@ -423,88 +356,6 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n dest += 4; } */ - - - /* Similar routine in assembly, again obsoleted due to maintainability - _asm - { - // Very important note: data in 'src' _must_ be aligned to - // 16-byte boundary! - mov edx, count - mov ebx, dword ptr src - mov eax, dword ptr dest - shr edx, 1 - - loop1: - // "outer loop" : during each round 2*2 output samples are calculated - - // give prefetch hints to CPU of what data are to be needed soonish - prefetcht0 [ebx] - prefetcht0 [filterCoeffsLocal] - - mov esi, ebx - mov edi, filterCoeffsLocal - xorps xmm0, xmm0 - xorps xmm1, xmm1 - mov ecx, lengthLocal - - loop2: - // "inner loop" : during each round eight FIR filter taps are evaluated for 2*2 samples - prefetcht0 [esi + 32] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 32] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm2, [esi] // possibly unaligned load - movups xmm3, [esi + 8] // possibly unaligned load - mulps xmm2, [edi] - mulps xmm3, [edi] - addps xmm0, xmm2 - addps xmm1, xmm3 - - movups xmm4, [esi + 16] // possibly unaligned load - movups xmm5, [esi + 24] // possibly unaligned load - mulps xmm4, [edi + 16] - mulps xmm5, [edi + 16] - addps xmm0, xmm4 - addps xmm1, xmm5 - - prefetcht0 [esi + 64] // give a prefetch hint to CPU what data are to be needed soonish - prefetcht0 [edi + 64] // give a prefetch hint to CPU what data are to be needed soonish - - movups xmm6, [esi + 32] // possibly unaligned load - movups xmm7, [esi + 40] // possibly unaligned load - mulps xmm6, [edi + 32] - mulps xmm7, [edi + 32] - addps xmm0, xmm6 - addps xmm1, xmm7 - - movups xmm4, [esi + 48] // possibly unaligned load - movups xmm5, [esi + 56] // possibly unaligned load - mulps xmm4, [edi + 48] - mulps xmm5, [edi + 48] - addps xmm0, xmm4 - addps xmm1, xmm5 - - add esi, 64 - add edi, 64 - dec ecx - jnz loop2 - - // Now xmm0 and xmm1 both have a filtered 2-channel sample each, but we still need - // to sum the two hi- and lo-floats of these registers together. - - movhlps xmm2, xmm0 // xmm2 = xmm2_3 xmm2_2 xmm0_3 xmm0_2 - movlhps xmm2, xmm1 // xmm2 = xmm1_1 xmm1_0 xmm0_3 xmm0_2 - shufps xmm0, xmm1, 0xe4 // xmm0 = xmm1_3 xmm1_2 xmm0_1 xmm0_0 - addps xmm0, xmm2 - - movaps [eax], xmm0 - add ebx, 16 - add eax, 16 - - dec edx - jnz loop1 - } - */ } -#endif // ALLOW_SSE +#endif // SOUNDTOUCH_ALLOW_SSE