From: <rel...@us...> - 2009-02-14 19:45:25
|
Revision: 250 http://modplug.svn.sourceforge.net/modplug/?rev=250&view=rev Author: relabsoluness Date: 2009-02-14 19:45:18 +0000 (Sat, 14 Feb 2009) Log Message: ----------- / SoundTouch: Updated to SoundTouch 1.4.0 Modified Paths: -------------- trunk/OpenMPT/soundtouch/3dnow_win.cpp trunk/OpenMPT/soundtouch/AAFilter.cpp trunk/OpenMPT/soundtouch/AAFilter.h trunk/OpenMPT/soundtouch/BPMDetect.h trunk/OpenMPT/soundtouch/FIFOSampleBuffer.cpp trunk/OpenMPT/soundtouch/FIFOSampleBuffer.h trunk/OpenMPT/soundtouch/FIFOSamplePipe.h trunk/OpenMPT/soundtouch/FIRFilter.cpp trunk/OpenMPT/soundtouch/FIRFilter.h trunk/OpenMPT/soundtouch/README.html trunk/OpenMPT/soundtouch/RateTransposer.cpp trunk/OpenMPT/soundtouch/RateTransposer.h trunk/OpenMPT/soundtouch/STTypes.h trunk/OpenMPT/soundtouch/SoundTouch.cpp trunk/OpenMPT/soundtouch/SoundTouch.h trunk/OpenMPT/soundtouch/TDStretch.cpp trunk/OpenMPT/soundtouch/TDStretch.h trunk/OpenMPT/soundtouch/cpu_detect.h trunk/OpenMPT/soundtouch/cpu_detect_x86_win.cpp trunk/OpenMPT/soundtouch/mmx_optimized.cpp trunk/OpenMPT/soundtouch/soundtouch.vcproj trunk/OpenMPT/soundtouch/sse_optimized.cpp Added Paths: ----------- trunk/OpenMPT/soundtouch/BPMDetect.cpp trunk/OpenMPT/soundtouch/PeakFinder.cpp trunk/OpenMPT/soundtouch/PeakFinder.h Removed Paths: ------------- trunk/OpenMPT/soundtouch/soundtouch-1.3.1.zip Modified: trunk/OpenMPT/soundtouch/3dnow_win.cpp =================================================================== --- trunk/OpenMPT/soundtouch/3dnow_win.cpp 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/3dnow_win.cpp 2009-02-14 19:45:18 UTC (rev 250) @@ -24,7 +24,7 @@ /// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ /// 6.0 processor pack" update to support 3DNow! instruction set. The update is /// available for download at Microsoft Developers Network, see here: -/// http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx +/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx /// /// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and /// perform a search with keywords "processor pack". @@ -35,10 +35,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ +// Last changed : $Date: 2009-01-25 16:13:39 +0200 (Sun, 25 Jan 2009) $ +// File revision : $Revision: 4 $ // -// $Id: 3dnow_win.cpp,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// $Id: 3dnow_win.cpp 51 2009-01-25 14:13:39Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -82,10 +82,10 @@ ////////////////////////////////////////////////////////////////////////////// #include "TDStretch.h" -#include <limits.h> +//#include <limits.h> // these are declared in 'TDStretch.cpp' -extern int scanOffsets[4][24]; +// extern int scanOffsets[4][24]; // Calculates cross correlation of two buffers @@ -181,12 +181,15 @@ FIRFilter3DNow::FIRFilter3DNow() : FIRFilter() { filterCoeffsUnalign = NULL; + filterCoeffsAlign = NULL; } FIRFilter3DNow::~FIRFilter3DNow() { delete[] filterCoeffsUnalign; + filterCoeffsUnalign = NULL; + filterCoeffsAlign = NULL; } @@ -203,7 +206,7 @@ // Ensure that filter coeffs array is aligned to 16-byte boundary delete[] filterCoeffsUnalign; filterCoeffsUnalign = new float[2 * newLength + 4]; - filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & -16); + filterCoeffsAlign = (float *)(((uint)filterCoeffsUnalign + 15) & (uint)-16); fDivider = (float)resultDivider; @@ -217,10 +220,10 @@ // 3DNow!-optimized version of the filter routine for stereo sound -uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, const uint numSamples) const +uint FIRFilter3DNow::evaluateFilterStereo(float *dest, const float *src, uint numSamples) const { float *filterCoeffsLocal = filterCoeffsAlign; - uint count = (numSamples - length) & -2; + uint count = (numSamples - length) & (uint)-2; uint lengthLocal = length / 4; assert(length != 0); Modified: trunk/OpenMPT/soundtouch/AAFilter.cpp =================================================================== --- trunk/OpenMPT/soundtouch/AAFilter.cpp 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/AAFilter.cpp 2009-02-14 19:45:18 UTC (rev 250) @@ -12,10 +12,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ +// Last changed : $Date: 2009-01-11 13:34:24 +0200 (Sun, 11 Jan 2009) $ +// File revision : $Revision: 4 $ // -// $Id: AAFilter.cpp,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// $Id: AAFilter.cpp 45 2009-01-11 11:34:24Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -58,11 +58,11 @@ * *****************************************************************************/ -AAFilter::AAFilter(const uint length) +AAFilter::AAFilter(uint len) { pFIR = FIRFilter::newInstance(); cutoffFreq = 0.5; - setLength(length); + setLength(len); } @@ -77,7 +77,7 @@ // Sets new anti-alias filter cut-off edge frequency, scaled to // sampling frequency (nyquist frequency = 0.5). // The filter will cut frequencies higher than the given frequency. -void AAFilter::setCutoffFreq(const double newCutoffFreq) +void AAFilter::setCutoffFreq(double newCutoffFreq) { cutoffFreq = newCutoffFreq; calculateCoeffs(); @@ -86,7 +86,7 @@ // Sets number of FIR filter taps -void AAFilter::setLength(const uint newLength) +void AAFilter::setLength(uint newLength) { length = newLength; calculateCoeffs(); @@ -104,7 +104,7 @@ double *work; SAMPLETYPE *coeffs; - assert(length > 0); + assert(length >= 2); assert(length % 4 == 0); assert(cutoffFreq >= 0); assert(cutoffFreq <= 0.5); Modified: trunk/OpenMPT/soundtouch/AAFilter.h =================================================================== --- trunk/OpenMPT/soundtouch/AAFilter.h 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/AAFilter.h 2009-02-14 19:45:18 UTC (rev 250) @@ -13,10 +13,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.10 $ +// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ +// File revision : $Revision: 4 $ // -// $Id: AAFilter.h,v 1.10 2006/02/05 16:44:06 Olli Exp $ +// $Id: AAFilter.h 11 2008-02-10 16:26:55Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // Added: trunk/OpenMPT/soundtouch/BPMDetect.cpp =================================================================== --- trunk/OpenMPT/soundtouch/BPMDetect.cpp (rev 0) +++ trunk/OpenMPT/soundtouch/BPMDetect.cpp 2009-02-14 19:45:18 UTC (rev 250) @@ -0,0 +1,311 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// 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: 2008-12-25 19:54:41 +0200 (Thu, 25 Dec 2008) $ +// File revision : $Revision: 4 $ +// +// $Id: BPMDetect.cpp 43 2008-12-25 17:54:41Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <math.h> +#include <assert.h> +#include <string.h> +#include "FIFOSampleBuffer.h" +#include "PeakFinder.h" +#include "BPMDetect.h" + +using namespace soundtouch; + +#define INPUT_BLOCK_SAMPLES 2048 +#define DECIMATED_BLOCK_SAMPLES 256 + +typedef unsigned short ushort; + +/// 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); + + + +BPMDetect::BPMDetect(int numChannels, int sampleRate) +{ + xcorr = NULL; + + buffer = new FIFOSampleBuffer(); + + decimateSum = 0; + decimateCount = 0; + decimateBy = 0; + + this->sampleRate = sampleRate; + this->channels = numChannels; + + envelopeAccu = 0; + + // Initialize RMS volume accumulator to RMS level of 3000 (out of 32768) that's + // a typical RMS signal level value for song data. This value is then adapted + // to the actual level during processing. +#ifdef INTEGER_SAMPLES + // integer samples + RMSVolumeAccu = (3000 * 3000) / avgnorm; +#else + // float samples, scaled to range [-1..+1[ + RMSVolumeAccu = (0.092f * 0.092f) / avgnorm; +#endif + + init(numChannels, sampleRate); +} + + + +BPMDetect::~BPMDetect() +{ + delete[] xcorr; + delete buffer; +} + + +/// 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(decimateBy != 0); + outcount = 0; + for (count = 0; count < numsamples; count ++) + { + decimateSum += src[count]; + + decimateCount ++; + if (decimateCount >= decimateBy) + { + // Store every Nth sample only + out = (LONG_SAMPLETYPE)(decimateSum / decimateBy); + decimateSum = 0; + decimateCount = 0; +#ifdef INTEGER_SAMPLES + // check ranges for sure (shouldn't actually be necessary) + if (out > 32767) + { + out = 32767; + } + else if (out < -32768) + { + out = -32768; + } +#endif // 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 float decay = 0.7f; // decay constant for smoothing the envelope + const float norm = (1 - decay); + + int i; + LONG_SAMPLETYPE out; + float 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 2 times average RMS volume + // (we're interested in peak values, not the silent moments) + val -= 2 * (float)sqrt(RMSVolumeAccu * avgnorm); + val = (val > 0) ? val : 0; + + // smooth amplitude envelope + envelopeAccu *= decay; + envelopeAccu += val; + out = (LONG_SAMPLETYPE)(envelopeAccu * norm); + +#ifdef INTEGER_SAMPLES + // cut peaks (shouldn't be necessary though) + if (out > 32767) out = 32767; +#endif // INTEGER_SAMPLES + samples[i] = (SAMPLETYPE)out; + } +} + + + +void BPMDetect::inputSamples(SAMPLETYPE *samples, int numSamples) +{ + SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES]; + + // convert from stereo to mono if necessary + if (channels == 2) + { + int i; + + for (i = 0; i < numSamples; i ++) + { + samples[i] = (samples[i * 2] + samples[i * 2 + 1]) / 2; + } + } + + // decimate + numSamples = decimate(decimated, samples, numSamples); + + // envelope new samples and add them to buffer + calcEnvelope(decimated, numSamples); + buffer->putSamples(decimated, numSamples); + + // when the buffer has enought samples for processing... + if ((int)buffer->numSamples() > windowLen) + { + int processLength; + + // how many samples are processed + processLength = buffer->numSamples() - windowLen; + + // ... calculate autocorrelations for oldest samples... + updateXCorr(processLength); + // ... and remove them from the buffer + buffer->receiveSamples(processLength); + } +} + + +void BPMDetect::init(int numChannels, int sampleRate) +{ + this->sampleRate = sampleRate; + + // choose decimation factor so that result is approx. 500 Hz + decimateBy = sampleRate / 500; + 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)); + + // we do processing in mono mode + buffer->setChannels(1); + buffer->clear(); +} + + + +float BPMDetect::getBpm() +{ + double peakPos; + PeakFinder peakFinder; + + // find peak position + peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen); + + assert(decimateBy != 0); + if (peakPos < 1e-6) return 0.0; // detection failed. + + // calculate BPM + return (float)(60.0 * (((double)sampleRate / (double)decimateBy) / peakPos)); +} Modified: trunk/OpenMPT/soundtouch/BPMDetect.h =================================================================== --- trunk/OpenMPT/soundtouch/BPMDetect.h 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/BPMDetect.h 2009-02-14 19:45:18 UTC (rev 250) @@ -26,10 +26,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.5 $ +// Last changed : $Date: 2008-12-25 14:20:01 +0200 (Thu, 25 Dec 2008) $ +// File revision : $Revision: 4 $ // -// $Id: BPMDetect.h,v 1.5 2006/02/05 16:44:06 Olli Exp $ +// $Id: BPMDetect.h 33 2008-12-25 12:20:01Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -60,8 +60,11 @@ #include "STTypes.h" #include "FIFOSampleBuffer.h" +namespace soundtouch +{ + /// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. -#define MIN_BPM 45 +#define MIN_BPM 29 /// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit. #define MAX_BPM 230 @@ -156,4 +159,6 @@ float getBpm(); }; +} + #endif // _BPMDetect_H_ Modified: trunk/OpenMPT/soundtouch/FIFOSampleBuffer.cpp =================================================================== --- trunk/OpenMPT/soundtouch/FIFOSampleBuffer.cpp 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/FIFOSampleBuffer.cpp 2009-02-14 19:45:18 UTC (rev 250) @@ -15,10 +15,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.11 $ +// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ +// File revision : $Revision: 4 $ // -// $Id: FIFOSampleBuffer.cpp,v 1.11 2006/02/05 16:44:06 Olli Exp $ +// $Id: FIFOSampleBuffer.cpp 11 2008-02-10 16:26:55Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -54,14 +54,15 @@ using namespace soundtouch; // Constructor -FIFOSampleBuffer::FIFOSampleBuffer(uint numChannels) +FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) { + assert(numChannels > 0); sizeInBytes = 0; // reasonable initial value - buffer = NULL; //new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE)]; + buffer = NULL; bufferUnaligned = NULL; samplesInBuffer = 0; bufferPos = 0; - channels = numChannels; + channels = (uint)numChannels; } @@ -69,16 +70,19 @@ FIFOSampleBuffer::~FIFOSampleBuffer() { delete[] bufferUnaligned; + bufferUnaligned = NULL; + buffer = NULL; } // Sets number of channels, 1 = mono, 2 = stereo -void FIFOSampleBuffer::setChannels(const uint numChannels) +void FIFOSampleBuffer::setChannels(int numChannels) { uint usedBytes; + assert(numChannels > 0); usedBytes = channels * samplesInBuffer; - channels = numChannels; + channels = (uint)numChannels; samplesInBuffer = usedBytes / channels; } @@ -88,7 +92,7 @@ // location on to the beginning of the buffer. void FIFOSampleBuffer::rewind() { - if (bufferPos) + if (buffer && bufferPos) { memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); bufferPos = 0; @@ -98,10 +102,10 @@ // Adds 'numSamples' pcs of samples from the 'samples' memory position to // the sample buffer. -void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint numSamples) +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) { - memcpy(ptrEnd(numSamples), samples, sizeof(SAMPLETYPE) * numSamples * channels); - samplesInBuffer += numSamples; + memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); + samplesInBuffer += nSamples; } @@ -111,13 +115,13 @@ // This function is used to update the number of samples in the sample buffer // when accessing the buffer directly with 'ptrEnd' function. Please be // careful though! -void FIFOSampleBuffer::putSamples(uint numSamples) +void FIFOSampleBuffer::putSamples(uint nSamples) { uint req; - req = samplesInBuffer + numSamples; + req = samplesInBuffer + nSamples; ensureCapacity(req); - samplesInBuffer += numSamples; + samplesInBuffer += nSamples; } @@ -164,14 +168,14 @@ if (capacityRequirement > getCapacity()) { // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) - sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & -4096; + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; assert(sizeInBytes % 2 == 0); tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; if (tempUnaligned == NULL) { throw std::runtime_error("Couldn't allocate memory!\n"); } - temp = (SAMPLETYPE *)(((ulong)tempUnaligned + 15) & -16); + temp = (SAMPLETYPE *)(((ulong)tempUnaligned + 15) & (ulong)-16); memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); delete[] bufferUnaligned; buffer = temp; Modified: trunk/OpenMPT/soundtouch/FIFOSampleBuffer.h =================================================================== --- trunk/OpenMPT/soundtouch/FIFOSampleBuffer.h 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/FIFOSampleBuffer.h 2009-02-14 19:45:18 UTC (rev 250) @@ -15,10 +15,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.9 $ +// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ +// File revision : $Revision: 4 $ // -// $Id: FIFOSampleBuffer.h,v 1.9 2006/02/05 16:44:06 Olli Exp $ +// $Id: FIFOSampleBuffer.h 11 2008-02-10 16:26:55Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -85,7 +85,7 @@ void rewind(); /// Ensures that the buffer has capacity for at least this many samples. - void ensureCapacity(const uint capacityRequirement); + void ensureCapacity(uint capacityRequirement); /// Returns current capacity. uint getCapacity() const; @@ -93,7 +93,7 @@ public: /// Constructor - FIFOSampleBuffer(uint numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. ///< Default is stereo. ); @@ -160,7 +160,7 @@ virtual uint numSamples() const; /// Sets number of channels, 1 = mono, 2 = stereo. - void setChannels(uint numChannels); + void setChannels(int numChannels); /// Returns nonzero if there aren't any samples available for outputting. virtual int isEmpty() const; Modified: trunk/OpenMPT/soundtouch/FIFOSamplePipe.h =================================================================== --- trunk/OpenMPT/soundtouch/FIFOSamplePipe.h 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/FIFOSamplePipe.h 2009-02-14 19:45:18 UTC (rev 250) @@ -26,11 +26,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.8 $ // -// $Id: FIFOSamplePipe.h,v 1.8 2006/02/05 16:44:06 Olli Exp $ -// //////////////////////////////////////////////////////////////////////////////// // // License : @@ -81,7 +77,7 @@ /// Adds 'numSamples' pcs of samples from the 'samples' memory position to /// the sample buffer. virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. - uint numSamples ///< Number of samples to insert. + uint numSamples ///< Number of samples to insert. ) = 0; Modified: trunk/OpenMPT/soundtouch/FIRFilter.cpp =================================================================== --- trunk/OpenMPT/soundtouch/FIRFilter.cpp 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/FIRFilter.cpp 2009-02-14 19:45:18 UTC (rev 250) @@ -20,11 +20,7 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.16 $ // -// $Id: FIRFilter.cpp,v 1.16 2006/02/05 16:44:06 Olli Exp $ -// //////////////////////////////////////////////////////////////////////////////// // // License : @@ -67,6 +63,7 @@ FIRFilter::FIRFilter() { resultDivFactor = 0; + resultDivider = 0; length = 0; lengthDiv8 = 0; filterCoeffs = NULL; @@ -90,6 +87,9 @@ #endif assert(length != 0); + assert(src != NULL); + assert(dest != NULL); + assert(filterCoeffs != NULL); end = 2 * (numSamples - length); @@ -186,8 +186,8 @@ assert(length == newLength); resultDivFactor = uResultDivFactor; - //OpenMPT_change--> Fix to ambiguous pow(). - //resultDivider = (SAMPLETYPE)pow(2, resultDivFactor); + //OpenMPT_change--> + //resultDivider = (SAMPLETYPE)::pow(2, resultDivFactor); resultDivider = (1 << resultDivFactor); // == 2^resultDivFactor //<-- @@ -215,7 +215,6 @@ assert(length > 0); assert(lengthDiv8 * 8 == length); if (numSamples < length) return 0; - assert(resultDivFactor >= 0); if (numChannels == 2) { return evaluateFilterStereo(dest, src, numSamples); @@ -231,7 +230,7 @@ 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("Don't use 'new FIRFilter', use 'newInstance' member instead!"); + throw std::runtime_error("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); return NULL; } Modified: trunk/OpenMPT/soundtouch/FIRFilter.h =================================================================== --- trunk/OpenMPT/soundtouch/FIRFilter.h 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/FIRFilter.h 2009-02-14 19:45:18 UTC (rev 250) @@ -11,10 +11,10 @@ /// //////////////////////////////////////////////////////////////////////////////// // -// Last changed : $Date: 2006/02/05 16:44:06 $ -// File revision : $Revision: 1.17 $ +// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ +// File revision : $Revision: 4 $ // -// $Id: FIRFilter.h,v 1.17 2006/02/05 16:44:06 Olli Exp $ +// $Id: FIRFilter.h 11 2008-02-10 16:26:55Z oparviai $ // //////////////////////////////////////////////////////////////////////////////// // @@ -77,7 +77,7 @@ /// 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 * operator new(size_t s); + static void * operator new(size_t s); static FIRFilter *newInstance(); Added: trunk/OpenMPT/soundtouch/PeakFinder.cpp =================================================================== --- trunk/OpenMPT/soundtouch/PeakFinder.cpp (rev 0) +++ trunk/OpenMPT/soundtouch/PeakFinder.cpp 2009-02-14 19:45:18 UTC (rev 250) @@ -0,0 +1,236 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// 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: 2008-12-25 19:54:41 +0200 (Thu, 25 Dec 2008) $ +// File revision : $Revision: 4 $ +// +// $Id: PeakFinder.cpp 43 2008-12-25 17:54:41Z oparviai $ +// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <math.h> +#include <assert.h> + +#include "PeakFinder.h" + +using namespace soundtouch; + +#define max(x, y) (((x) > (y)) ? (x) : (y)) + + +PeakFinder::PeakFinder() +{ +} + + +// 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 +{ + float refvalue; + int lowpos; + int pos; + int climb_count; + float delta; + + climb_count = 0; + refvalue = data[peakpos]; + lowpos = peakpos; + + pos = peakpos; + + while ((pos > minPos) && (pos < maxPos)) + { + 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]; + } + 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) +{ + 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 = max(data[gp1], data[gp2]); + peakLevel = data[peakpos]; + + if (groundLevel < 1e-6) return 0; // ground level too small => detection failed + if ((peakLevel / groundLevel) < 1.3) return 0; // peak less than 30% of the ground level => no good peak detected + + // 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 minPos, int maxPos) +{ + + int i; + int peakpos; // position of peak level + double highPeak, peak; + + this->minPos = minPos; + this->maxPos = maxPos; + + // 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 = 2; i < 10; i ++) + { + double peaktmp, tmp; + int i1,i2; + + peakpos = (int)(highPeak / (double)i + 0.5f); + if (peakpos < minPos) break; + + // calculate mass-center of possible base peak + peaktmp = getPeakCenter(data, peakpos); + + // now compare to highest detected peak + i1 = (int)(highPeak + 0.5); + i2 = (int)(peaktmp + 0.5); + tmp = 2 * (data[i2] - data[i1]) / (data[i2] + data[i1]); + if (fabs(tmp) < 0.1) + { + // The highest peak is harmonic of almost as high base peak, + // thus use the base peak instead + peak = peaktmp; + } + } + + return peak; +} + + Added: trunk/OpenMPT/soundtouch/PeakFinder.h =================================================================== --- trunk/OpenMPT/soundtouch/PeakFinder.h (rev 0) +++ trunk/OpenMPT/soundtouch/PeakFinder.h 2009-02-14 19:45:18 UTC (rev 250) @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// 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: 2008-12-25 19:54:41 +0200 (Thu, 25 Dec 2008) $ +// File revision : $Revision: 4 $ +// +// $Id: PeakFinder.h 43 2008-12-25 17:54:41Z 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 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); + +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_ Modified: trunk/OpenMPT/soundtouch/README.html =================================================================== --- trunk/OpenMPT/soundtouch/README.html 2009-02-14 16:22:07 UTC (rev 249) +++ trunk/OpenMPT/soundtouch/README.html 2009-02-14 19:45:18 UTC (rev 250) @@ -18,14 +18,13 @@ </head> <body class="normal"> <hr> -<font color=red><h4>NOTE: SoundTouch used with OpenMPT is slightly modified version. - The file soundtouch-1.3.1.zip, and this readme excluding this - note, are the original SoundTouch files. +<font color=red><h4>Note: Some of the SoundTouch files included in OpenMPT repository are modified versions +of the original SoundTouch files. This readme, excluding this note, is the original SoundTouch readme. </h4></font> -<h1>SoundTouch audio processing library v1.3.1 +<h1>SoundTouch audio processing library v1.4.0 </h1> <p class="normal">SoundTouch library Copyright (c) Olli -Parviainen 2002-2006 </p> +Parviainen 2002-2009 </p> <hr> <h2>1. Introduction </h2> <p>SoundTouch is an open-source audio @@ -51,37 +50,27 @@ for more information.</p> <h3>2.1. Building in Microsoft Windows</h3> <p>Project files for Microsoft Visual C++ 6.0 and Visual C++ .NET are -supplied with the source code package. Please notice that SoundTouch +supplied with the source code package. </p> +<p> Please notice that SoundTouch library uses processor-specific optimizations for Pentium III and AMD -processors that require a processor pack upgrade for -the Visual Studio 6.0 to be installed in order to support these -optimizations. The processor pack upgrade can be downloaded from +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:</p> -<p><a - href="http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx"> -http://msdn.microsoft.com/vstudio/downloads/tools/ppack/default.aspx</a></p> +<p><a href="http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx">http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx</a></p> <p>If the above URL is unavailable or removed, go to <a href="http://msdn.microsoft.com/">http://msdn.microsoft.com</a> -and perform a search with keywords processor pack. </p> -<p>Visual Studio .NET supports required -instructions by default and thus doesn't require installing the -processor pack.</p> -<p>To build the binaries with Visual C++ 6.0 -compiler, either run "make-win.bat" script or open the +and perform a search with keywords "processor pack". </p> +<p>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 have to be created manually to the SoundTouch +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. </p> -<p>Also other C++ compilers than Visual C++ can be -used, but project or makefiles then have to be adapted accordingly. -Performance optimizations are written in Visual C++ compatible -syntax, they may or may not be compatible with other compilers. If -using GCC (Gnu C Compiler) compiler package such as DJGPP or Cygwin, -please see next chapter for instructions. </p> <h3>2.2. Building in Gnu platforms</h3> <p>The SoundTouch library can be compiled in practically any platform supporting GNU compiler (GCC) tools. @@ -91,7 +80,7 @@ x86 platforms only, they are automatically disabled and replaced with standard C routines in other processor platforms.</p> <p>To build and install the binaries, run the -following commands in SoundTouch/ directory:</p> +following commands in the SoundTouch/ directory:</p> <table border="0" cellpadding="0" cellspacing="4"> <tbody> <tr valign="top"> @@ -125,14 +114,13 @@ </tr> </tbody> </table> -<p><b>NOTE:</b> At the time of release the SoundTouch package has been +<p><b>NOTE:</b> 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 setttings used in the optimized routines. <b>If you have problems getting the -SoundTouch library compiled, try the workaround of disabling the -optimizations</b> by editing the file "include/STTypes.h" and removing +SoundTouch library compiled, try the workaround of disabling the optimizations</b> by editing the file "include/STTypes.h" and removing the following definition there:</p> <blockquote> <pre>#define ALLOW_OPTIMIZATIONS 1</pre> @@ -146,7 +134,7 @@ <p> In Windows environment, the sample data format is chosen -in file "STTypes.h" by choosing one of the following +in file "STTypes.h" by choosing one of the following defines:</p> <ul> <li><span style="font-weight: bold;">#define INTEGER_SAMPLES</span> @@ -171,7 +159,7 @@ recommended because processing the channels separately would result in losing the phase coherency between the channels, which consequently would ruin the stereo effect.</p> -<p>Sample rates between 8000-48000Hz are +<p>Sample rates between 8000-48000H are supported.</p> <h3>3.2. Processing latency</h3> <p>The processing and latency constraints of @@ -183,8 +171,8 @@ requirement is much shorter, see section 'About algorithms'.</li> <li>Processing CD-quality sound (16bit stereo -sound with 44100Hz sample rate) in real-time or faster is possible -starting from processors equivalent to Intel Pentium 133Mhz or better, +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 @@ -198,8 +186,7 @@ <p><em>Sample rate transposing</em> 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 +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 @@ -240,10 +227,10 @@ sound the default parameter set may result into a sub-optimal result.</p> <p>The time-stretch algorithm default -parameter values are set by these #defines in file "TDStretch.h":</p> +parameter values are set by these #defines in file "TDStretch.h":</p> <blockquote> - <pre>#define DEFAULT_SEQUENCE_MS 82 -#define DEFAULT_SEEKWINDOW_MS 28 + <pre>#define DEFAULT_SEQUENCE_MS AUTOMATIC +#define DEFAULT_SEEKWINDOW_MS AUTOMATIC #define DEFAULT_OVERLAP_MS 12</pre> </blockquote> <p>These parameters affect to the time-stretch @@ -255,13 +242,16 @@ 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.<br> +versa. <br> + <br> + By default, this setting value is calculated automatically according to + tempo value.<br> </li> <li><strong>DEFAULT_SEEKWINDOW_MS</strong>: 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.<br> +location when the sound sequences are to be linked back together. <br> <br> 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 @@ -269,6 +259,9 @@ 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.<br> + <br> + By default, this setting value is calculated automatically according to + tempo value.<br> </li> <li><strong>DEFAULT_OVERLAP_MS</strong>: Overlap length in milliseconds. When the sound sequences are mixed back @@ -282,7 +275,7 @@ <p>Notice that these parameters can also be set during execution time with functions "<strong>TDStretch::setParameters()</strong>" and "<strong>SoundTouch::setSetting()</strong>".</p> -<p>The table below summarizes how the +<p>The table below summaries how the parameters can be adjusted for different applications:</p> <table border="1"> <tbody> @@ -294,9 +287,7 @@ affects...</strong></td> <td valign="top"><strong>Smaller value affects...</strong></td> - <td valign="top"><strong>Music</strong></td> - <td valign="top"><strong>Speech</strong></td> - <td valign="top"><strong>Effect in CPU burden</strong></td> + <td valign="top"><strong>Effect to CPU burden</strong></td> </tr> <tr> <td valign="top"> @@ -310,9 +301,6 @@ <td valign="top">Smaller value might be better for speeding up tempo. Reducing the value accelerates the "echoing" artifact when slowing down the tempo </td> - <td valign="top">Default value usually good</td> - <td valign="top">A smaller value than default -might be better</td> <td valign="top">Increasing the parameter value reduces computation burden</td> </tr> @@ -326,9 +314,6 @@ good mixing position, but may cause a "drifting" artifact</td> <td valign="top">Smaller reduce possibility to find a good mixing position, but reduce the "drifting" artifact.</td> - <td valign="top">Default value usually good, -unless a "drifting" artifact is disturbing.</td> - <td valign="top">Default value usually good</td> <td valign="top">Increasing the parameter value increases computation burden</td> </tr> @@ -341,8 +326,6 @@ <td valign="top"> </td> <td valign="top">If you reduce the "sequence ms" setting, you might wish to try a smaller value.</td> - <td valign="top"> </td> - <td valign="top"> </td> <td valign="top">Increasing the parameter value increases computation burden</td> </tr> @@ -361,13 +344,11 @@ <p><strong>CPU-specific optimizations:</strong></p> <ul> <li>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 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. </li> <li>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. +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. </li> <li>AMD 3DNow! optimized routines are used with @@ -377,41 +358,67 @@ AMD K6-2 and Athlon (classic) CPU's; better performing SSE routines are used with AMD processor starting from Athlon XP. </li> </ul> +<h3>3.6 GNU compilation issues </h3> +<h4><b>3.6.1 Required GNU tools</b> </h4> +<p> 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:</p> +<pre><b>sudo apt-get install <font SIZE="2">automake autoconf libtool build-essential</font></b></pre> +<h4><b>3.6.2 Problems with configure script or build process</b> </h4> +<p>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. </p> +<p>To resolve the issue, regenerate the configure scripts with your local tool +set by running +the "<b>./bootstrap</b>" script included in the SoundTouch source code +kit. After that, run the <b>configure</b> script and <b>make</b> as usually.</p> +<h4><b>3.6.3 Compiler issues with non-x86 processors</b></h4> +<p>SoundTouch library works also on non-x86 processors.</p> +<p>However, in case that you get compiler errors when trying to compile for non-Intel processor, edit the file +"<b>source\SoundTouch\Makefile.am</b>" and remove the "<b>-msse2</b>" +flag on the <b>AM_CXXFLAGS </b>line:</p> +<pre><b>AM_CXXFLAGS=-O3 -fcheck-new -I../../include # Note: -msse2 flag removed!</b></pre> +<p>After that, run "<b>./bootstrap</b>" script, and then run <b>configure</b> +and <b>make</b> again.</p> <hr> <h2><a name="SoundStretch"></a>4. SoundStretch audio processing utility </h2> <p>SoundStretch audio processing utility<br> -Copyright (c) Olli Parviainen 2002-2005</p> +Copyright (c) Olli Parviainen 2002-2009</p> <p>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 +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.</p> <h3>4.1. SoundStretch Usage Instructions</h3> <p>SoundStretch Usage syntax:</p> <blockquote> - <pre>soundstretch infile.wav outfile.wav [switches]</pre> + <pre>soundstretch infilename outfilename [switches]</pre> </blockquote> <p>Where: </p> <table border="0" cellpadding="2" width="100%"> <tbody> <tr> <td valign="top"> - <pre>"infile.wav"</pre> + <pre>"infilename"</pre> </td> - <td valign="top">is the name of the input sound -data file (in .WAV audio file format). </td> + <td valign="top">Name of the input sound +data file (in .WAV audio file format). Give "stdin" as filename to use + standard input pipe. </td> </tr> <tr> <td valign="top"> - <pre>"outfile.wav"</pre> + <pre>"outfilename"</pre> </td> - <td valign="top">is the name of the output sound + <td valign="top">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).</td> +(e.g. when only calculating BPM rate with '-bpm' switch). Give "stdout" + as filename to use standard output pipe.</td> </tr> <tr> <td valign="top"> @@ -450,11 +457,11 @@ <td valign="top"> <pre>-bpm=n</pre> </td> - <td valign="top">Detect the Beats-Per-Minute -(BPM) rate of the sound and adjust the tempo to meet 'n' BPMs. If this -switch is defined, the "-tempo=n" switch value is ignored. If "=n" is -omitted, i.e. switch "-bpm" is used alone, the program just calculates -and displays the BPM rate but doesn't adjust tempo according to the BPM + <td valign="top">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. </td> </tr> <tr> @@ -483,57 +490,69 @@ </table> <p>Notes:</p> <ul> - <li>The numerical switch values can be entered -using either integer (e.g. "-tempo=123") or decimal (e.g. + <li>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.</li> + <li>The numerical switches allow both integer (e.g. "-tempo=123") and decimal (e.g. "-tempo=123.45") numbers.</li> <li>The "-naa" and/or "-quick" switches can be used to reduce CPU usage while compromising some sound quality </li> <li>The BPM detection algorithm works by detecting -repeating low-frequency (<250Hz) sound patterns and thus works -mostly with most rock/pop music with bass or drum beat. The BPM -detection doesn't work on pieces such as classical music without -distinct, repeating bass frequency patterns. Also pieces with varying -tempo, varying bass patterns or very complex bass patterns (jazz, hiphop) may produce odd BPM readings. <br> - <br> -In cases when the bass pattern drifts a bit around a nominal beat rate -(e.g. drummer is again drunken :), the BPM algorithm may report -incorrect harmonic one-halft to one-thirdth of the correct BPM value; -in such case the system could for example report BPM value of 50 or 100 -instead of correct BPM value of 150. </li> +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. </li> </ul> <h3>4.2. SoundStretch usage examples </h3> <p><strong>Example 1</strong></p> <p>The following command increases tempo of -the sound file "originalfile.wav" by 12.5% and saves -result to file "destinationfile.wav":</p> +the sound file "originalfile.wav" by 12.5% and stores result to file "destinationfile.wav":</p> <blockquote> <pre>soundstretch originalfile.wav destinationfile.wav -tempo=12.5</pre> </blockquote> <p><strong>Example 2</strong></p> <p>The following command decreases the sound pitch (key) of the sound file "orig.wav" by two -semitones and saves the result to file "dest.wav":</p> +semitones and stores the result to file "dest.wav":</p> <blockquote> <pre>soundstretch orig.wav dest.wav -pitch=-2</pre> </blockquote> <p><strong>Example 3</strong></p> <p>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. Result is -saved to file "dest.wav":</p> +increasing the sound pitch (key) by 1.5 semitones. Resulting .wav audio data is +directed to standard output pipe:</p> <blockquote> - <pre>soundstretch orig.wav dest.wav -tempo=-25.3 -pitch=1.5</pre> + <pre>soundstretch orig.wav stdout -tempo=-25.3 -pitch=1.5</pre> </blockquote> <p><strong>Example 4</strong></p> <p>The following command detects the BPM rate of the file "orig.wav" and adjusts the tempo to match -100 beats per minute. Result is saved to file "dest.wav":</p> +100 beats per minute. Result is stored to file "dest.wav":</p> <blockquote> <pre>soundstretch orig.wav dest.wav -bpm=100</pre> </blockquote> +<p><strong>Example 5</strong></p> +<p>The following command reads .wav sound data from standard input pipe and +estimates the BPM rate:</p> +<blockquote> + <pre>soundstretch stdin -bpm</pre> +</blockquote> <hr> <h2>5. Change History</h2> <h3>5.1. SoundTouch library Change History </h3> +<p><strong>1.4.0:</strong></p> +<ul> +<li>Improved sound quality by automatic calculation of time stretch algorithm + processing parameters according to tempo settin... [truncated message content] |