Update SoundTouch lib to v2.0.0

This commit is contained in:
Christian Kenny 2017-09-26 19:34:13 -04:00 committed by Jonathan Li
parent 96b412ebb8
commit 574e0a7531
24 changed files with 311 additions and 197 deletions

View File

@ -26,10 +26,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2012-08-30 22:53:44 +0300 (Thu, 30 Aug 2012) $ // Last changed : $Date: 2016-01-12 19:24:46 +0200 (ti, 12 tammi 2016) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: BPMDetect.h 150 2012-08-30 19:53:44Z oparviai $ // $Id: BPMDetect.h 239 2016-01-12 17:24:46Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -77,12 +77,6 @@ protected:
/// Auto-correlation accumulator bins. /// Auto-correlation accumulator bins.
float *xcorr; float *xcorr;
/// Amplitude envelope sliding average approximation level accumulator
double envelopeAccu;
/// RMS volume sliding average approximation level accumulator
double RMSVolumeAccu;
/// Sample average counter. /// Sample average counter.
int decimateCount; int decimateCount;

View File

@ -15,7 +15,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $ // Last changed : $Date: 2014-01-05 23:40:22 +0200 (su, 05 tammi 2014) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: FIFOSampleBuffer.h 177 2014-01-05 21:40:22Z oparviai $ // $Id: FIFOSampleBuffer.h 177 2014-01-05 21:40:22Z oparviai $

View File

@ -17,7 +17,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2012-06-13 22:29:53 +0300 (Wed, 13 Jun 2012) $ // Last changed : $Date: 2012-06-13 22:29:53 +0300 (ke, 13 kesä 2012) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $ // $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $

View File

@ -8,10 +8,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-05-18 18:25:07 +0300 (Mon, 18 May 2015) $ // Last changed : $Date: 2017-07-30 12:28:06 +0300 (su, 30 heinä 2017) $
// File revision : $Revision: 3 $ // File revision : $Revision: 3 $
// //
// $Id: STTypes.h 215 2015-05-18 15:25:07Z oparviai $ // $Id: STTypes.h 252 2017-07-30 09:28:06Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -143,8 +143,10 @@ namespace soundtouch
#endif // SOUNDTOUCH_FLOAT_SAMPLES #endif // SOUNDTOUCH_FLOAT_SAMPLES
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow MMX optimizations // Allow MMX optimizations (not available in X64 mode)
#define SOUNDTOUCH_ALLOW_MMX 1 #if (!_M_X64)
#define SOUNDTOUCH_ALLOW_MMX 1
#endif
#endif #endif
#else #else

View File

@ -41,10 +41,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-09-20 10:38:32 +0300 (Sun, 20 Sep 2015) $ // Last changed : $Date: 2017-07-30 12:35:00 +0300 (su, 30 heinä 2017) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: SoundTouch.h 230 2015-09-20 07:38:32Z oparviai $ // $Id: SoundTouch.h 253 2017-07-30 09:35:00Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -79,10 +79,10 @@ namespace soundtouch
{ {
/// Soundtouch library version string /// Soundtouch library version string
#define SOUNDTOUCH_VERSION "1.9.2" #define SOUNDTOUCH_VERSION "2.0.0"
/// SoundTouch library version id /// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (10902) #define SOUNDTOUCH_VERSION_ID (20000)
// //
// Available setting IDs for the 'setSetting' & 'get_setting' functions: // Available setting IDs for the 'setSetting' & 'get_setting' functions:
@ -116,17 +116,19 @@ namespace soundtouch
#define SETTING_OVERLAP_MS 5 #define SETTING_OVERLAP_MS 5
/// Call "getSetting" with this ID to query nominal average processing sequence /// Call "getSetting" with this ID to query processing sequence size in samples.
/// size in samples. This value tells approcimate value how many input samples /// This value gives approximate value of how many input samples you'll need to
/// SoundTouch needs to gather before it does DSP processing run for the sample batch. /// feed into SoundTouch after initial buffering to get out a new batch of
/// output samples.
///
/// This value does not include initial buffering at beginning of a new processing
/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size.
/// ///
/// Notices: /// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter /// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - Returned value is approximate average value, exact processing batch /// - This parameter value is not constant but change depending on
/// size may wary from time to time
/// - This parameter value is not constant but may change depending on
/// tempo/pitch/rate/samplerate settings. /// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_INPUT_SEQUENCE 6 #define SETTING_NOMINAL_INPUT_SEQUENCE 6
/// Call "getSetting" with this ID to query nominal average processing output /// Call "getSetting" with this ID to query nominal average processing output
@ -135,11 +137,40 @@ namespace soundtouch
/// ///
/// Notices: /// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter /// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - Returned value is approximate average value, exact processing batch /// - This parameter value is not constant but change depending on
/// size may wary from time to time
/// - This parameter value is not constant but may change depending on
/// tempo/pitch/rate/samplerate settings. /// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 #define SETTING_NOMINAL_OUTPUT_SEQUENCE 7
/// Call "getSetting" with this ID to query initial processing latency, i.e.
/// approx. how many samples you'll need to enter to SoundTouch pipeline before
/// you can expect to get first batch of ready output samples out.
///
/// After the first output batch, you can then expect to get approx.
/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every
/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch.
///
/// Example:
/// processing with parameter -tempo=5
/// => initial latency = 5509 samples
/// input sequence = 4167 samples
/// output sequence = 3969 samples
///
/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of
/// the stream, and then you'll get out the first 3969 samples. After that, for
/// every approx. 4167 samples that you'll put in, you'll receive again approx.
/// 3969 samples out.
///
/// This also means that average latency during stream processing is
/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2
/// = 3524 samples
///
/// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings.
#define SETTING_INITIAL_LATENCY 8
class SoundTouch : public FIFOProcessor class SoundTouch : public FIFOProcessor
{ {
@ -228,6 +259,24 @@ public:
/// Sets sample rate. /// Sets sample rate.
void setSampleRate(uint srate); void setSampleRate(uint srate);
/// Get ratio between input and output audio durations, useful for calculating
/// processed output duration: if you'll process a stream of N samples, then
/// you can expect to get out N * getInputOutputSampleRatio() samples.
///
/// This ratio will give accurate target duration ratio for a full audio track,
/// given that the the whole track is processed with same processing parameters.
///
/// If this ratio is applied to calculate intermediate offsets inside a processing
/// stream, then this ratio is approximate and can deviate +- some tens of milliseconds
/// from ideal offset, yet by end of the audio stream the duration ratio will become
/// exact.
///
/// Example: if processing with parameters "-tempo=15 -pitch=-3", the function
/// will return value 0.8695652... Now, if processing an audio stream whose duration
/// is exactly one million audio samples, then you can expect the processed
/// output duration be 0.869565 * 1000000 = 869565 samples.
double getInputOutputSampleRatio();
/// Flushes the last samples from the processing pipeline to the output. /// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers. /// Clears also the internal processing buffers.
// //
@ -286,6 +335,11 @@ public:
/// Returns number of samples currently unprocessed. /// Returns number of samples currently unprocessed.
virtual uint numUnprocessedSamples() const; virtual uint numUnprocessedSamples() const;
/// Return number of channels
uint numChannels() const
{
return channels;
}
/// Other handy functions that are implemented in the ancestor classes (see /// Other handy functions that are implemented in the ancestor classes (see
/// classes 'FIFOProcessor' and 'FIFOSamplePipe') /// classes 'FIFOProcessor' and 'FIFOSamplePipe')

View File

@ -17,7 +17,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2014-10-05 19:20:24 +0300 (Sun, 05 Oct 2014) $ // Last changed : $Date: 2014-10-05 19:20:24 +0300 (su, 05 loka 2014) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: WavFile.cpp 200 2014-10-05 16:20:24Z oparviai $ // $Id: WavFile.cpp 200 2014-10-05 16:20:24Z oparviai $

View File

@ -16,7 +16,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2014-10-05 19:20:24 +0300 (Sun, 05 Oct 2014) $ // Last changed : $Date: 2014-10-05 19:20:24 +0300 (su, 05 loka 2014) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: WavFile.h 200 2014-10-05 16:20:24Z oparviai $ // $Id: WavFile.h 200 2014-10-05 16:20:24Z oparviai $

View File

@ -12,10 +12,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2014-01-05 23:40:22 +0200 (Sun, 05 Jan 2014) $ // Last changed : $Date: 2016-01-12 19:26:21 +0200 (ti, 12 tammi 2016) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: AAFilter.cpp 177 2014-01-05 21:40:22Z oparviai $ // $Id: AAFilter.cpp 240 2016-01-12 17:26:21Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -49,7 +49,7 @@
using namespace soundtouch; using namespace soundtouch;
#define PI 3.141592655357989 #define PI 3.14159265358979323846
#define TWOPI (2 * PI) #define TWOPI (2 * PI)
// define this to save AA filter coefficients to a file // define this to save AA filter coefficients to a file

View File

@ -13,7 +13,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2014-01-07 21:41:23 +0200 (Tue, 07 Jan 2014) $ // Last changed : $Date: 2014-01-07 21:41:23 +0200 (ti, 07 tammi 2014) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: AAFilter.h 187 2014-01-07 19:41:23Z oparviai $ // $Id: AAFilter.h 187 2014-01-07 19:41:23Z oparviai $

View File

@ -26,10 +26,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ // Last changed : $Date: 2016-01-05 22:59:57 +0200 (ti, 05 tammi 2016) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: BPMDetect.cpp 202 2015-02-21 21:24:29Z oparviai $ // $Id: BPMDetect.cpp 237 2016-01-05 20:59:57Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -67,13 +67,18 @@ using namespace soundtouch;
#define INPUT_BLOCK_SAMPLES 2048 #define INPUT_BLOCK_SAMPLES 2048
#define DECIMATED_BLOCK_SAMPLES 256 #define DECIMATED_BLOCK_SAMPLES 256
/// decay constant for calculating RMS volume sliding average approximation /// Target sample rate after decimation
/// (time constant is about 10 sec) const int target_srate = 1000;
const float avgdecay = 0.99986f;
/// Normalization coefficient for calculating RMS sliding average approximation. /// XCorr update sequence size, update in about 200msec chunks
const float avgnorm = (1 - avgdecay); const int xcorr_update_sequence = 200;
/// XCorr decay time constant, decay to half in 30 seconds
/// If it's desired to have the system adapt quicker to beat rate
/// changes within a continuing music stream, then the
/// 'xcorr_decay_time_constant' value can be reduced, yet that
/// can increase possibility of glitches in bpm detection.
const double xcorr_decay_time_constant = 30.0;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -115,21 +120,8 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate)
decimateSum = 0; decimateSum = 0;
decimateCount = 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 // choose decimation factor so that result is approx. 1000 Hz
decimateBy = sampleRate / 1000; decimateBy = sampleRate / target_srate;
assert(decimateBy > 0); assert(decimateBy > 0);
assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES); assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES);
@ -226,6 +218,10 @@ void BPMDetect::updateXCorr(int process_samples)
assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
pBuffer = buffer->ptrBegin(); pBuffer = buffer->ptrBegin();
// calculate decay factor for xcorr filtering
float xcorr_decay = (float)pow(0.5, 1.0 / (xcorr_decay_time_constant * target_srate / process_samples));
#pragma omp parallel for #pragma omp parallel for
for (offs = windowStart; offs < windowLen; offs ++) for (offs = windowStart; offs < windowLen; offs ++)
{ {
@ -237,51 +233,9 @@ void BPMDetect::updateXCorr(int process_samples)
{ {
sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
} }
// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable time constant.
// 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; xcorr[offs] += (float)fabs(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;
} }
} }
@ -304,23 +258,16 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
samples += block * channels; samples += block * channels;
numSamples -= block; numSamples -= block;
// envelope new samples and add them to buffer
calcEnvelope(decimated, decSamples);
buffer->putSamples(decimated, decSamples); buffer->putSamples(decimated, decSamples);
} }
// when the buffer has enought samples for processing... // when the buffer has enought samples for processing...
if ((int)buffer->numSamples() > windowLen) while ((int)buffer->numSamples() >= windowLen + xcorr_update_sequence)
{ {
int processLength;
// how many samples are processed
processLength = (int)buffer->numSamples() - windowLen;
// ... calculate autocorrelations for oldest samples... // ... calculate autocorrelations for oldest samples...
updateXCorr(processLength); updateXCorr(xcorr_update_sequence);
// ... and remove them from the buffer // ... and remove these from the buffer
buffer->receiveSamples(processLength); buffer->receiveSamples(xcorr_update_sequence);
} }
} }

View File

@ -15,7 +15,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2012-11-08 20:53:01 +0200 (Thu, 08 Nov 2012) $ // Last changed : $Date: 2012-11-08 20:53:01 +0200 (to, 08 marras 2012) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $ // $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $

View File

@ -2,19 +2,25 @@
/// ///
/// 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, /// Notes : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
/// ///
/// This source file contains OpenMP optimizations that allow speeding up the
/// corss-correlation algorithm by executing it in several threads / CPU cores
/// in parallel. See the following article link for more detailed discussion
/// about SoundTouch OpenMP optimizations:
/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch /// SoundTouch WWW: http://www.surina.net/soundtouch
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ // Last changed : $Date: 2015-11-05 19:46:08 +0200 (to, 05 marras 2015) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: FIRFilter.cpp 202 2015-02-21 21:24:29Z oparviai $ // $Id: FIRFilter.cpp 234 2015-11-05 17:46:08Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //

View File

@ -11,7 +11,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-02-21 23:24:29 +0200 (Sat, 21 Feb 2015) $ // Last changed : $Date: 2015-02-21 23:24:29 +0200 (la, 21 helmi 2015) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: FIRFilter.h 202 2015-02-21 21:24:29Z oparviai $ // $Id: FIRFilter.h 202 2015-02-21 21:24:29Z oparviai $

View File

@ -11,7 +11,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-05-18 18:22:02 +0300 (Mon, 18 May 2015) $ // Last changed : $Date: 2015-05-18 18:22:02 +0300 (ma, 18 touko 2015) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: PeakFinder.cpp 213 2015-05-18 15:22:02Z oparviai $ // $Id: PeakFinder.cpp 213 2015-05-18 15:22:02Z oparviai $

View File

@ -9,7 +9,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2011-12-30 22:33:46 +0200 (Fri, 30 Dec 2011) $ // Last changed : $Date: 2011-12-30 22:33:46 +0200 (pe, 30 joulu 2011) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: PeakFinder.h 132 2011-12-30 20:33:46Z oparviai $ // $Id: PeakFinder.h 132 2011-12-30 20:33:46Z oparviai $

View File

@ -10,10 +10,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ // Last changed : $Date: 2016-10-15 22:34:59 +0300 (la, 15 loka 2016) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: RateTransposer.cpp 225 2015-07-26 14:45:48Z oparviai $ // $Id: RateTransposer.cpp 243 2016-10-15 19:34:59Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -208,6 +208,13 @@ int RateTransposer::isEmpty() const
} }
/// Return approximate initial input-output latency
int RateTransposer::getLatency() const
{
return (bUseAAFilter) ? pAAFilter->getLength() : 0;
}
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// TransposerBase - Base class for interpolation // TransposerBase - Base class for interpolation

View File

@ -14,10 +14,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ // Last changed : $Date: 2016-10-15 22:34:59 +0300 (la, 15 loka 2016) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: RateTransposer.h 225 2015-07-26 14:45:48Z oparviai $ // $Id: RateTransposer.h 243 2016-10-15 19:34:59Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -172,6 +172,9 @@ public:
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
int isEmpty() const; int isEmpty() const;
/// Return approximate initial input-output latency
int getLatency() const;
}; };
} }

View File

@ -41,10 +41,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-07-26 17:45:48 +0300 (Sun, 26 Jul 2015) $ // Last changed : $Date: 2016-10-15 22:34:59 +0300 (la, 15 loka 2016) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: SoundTouch.cpp 225 2015-07-26 14:45:48Z oparviai $ // $Id: SoundTouch.cpp 243 2016-10-15 19:34:59Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -110,8 +110,8 @@ SoundTouch::SoundTouch()
calcEffectiveRateAndTempo(); calcEffectiveRateAndTempo();
samplesExpectedOut = 0; samplesExpectedOut = 0;
samplesOutput = 0; samplesOutput = 0;
channels = 0; channels = 0;
bSrateSet = false; bSrateSet = false;
@ -149,7 +149,7 @@ void SoundTouch::setChannels(uint numChannels)
/*if (numChannels != 1 && numChannels != 2) /*if (numChannels != 1 && numChannels != 2)
{ {
//ST_THROW_RT_ERROR("Illegal number of channels"); //ST_THROW_RT_ERROR("Illegal number of channels");
return; return;
}*/ }*/
channels = numChannels; channels = numChannels;
pRateTransposer->setChannels((int)numChannels); pRateTransposer->setChannels((int)numChannels);
@ -240,11 +240,11 @@ void SoundTouch::calcEffectiveRateAndTempo()
double oldTempo = tempo; double oldTempo = tempo;
double oldRate = rate; double oldRate = rate;
tempo = virtualTempo / virtualPitch; tempo = virtualTempo / virtualPitch;
rate = virtualPitch * virtualRate; rate = virtualPitch * virtualRate;
if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate);
if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo);
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
if (rate <= 1.0f) if (rate <= 1.0f)
@ -321,9 +321,9 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
} }
*/ */
// accumulate how many samples are expected out from processing, given the current // accumulate how many samples are expected out from processing, given the current
// processing setting // processing setting
samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo); samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo);
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
if (rate <= 1.0f) if (rate <= 1.0f)
@ -354,23 +354,24 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
void SoundTouch::flush() void SoundTouch::flush()
{ {
int i; int i;
int numStillExpected; int numStillExpected;
SAMPLETYPE *buff = new SAMPLETYPE[128 * channels]; SAMPLETYPE *buff = new SAMPLETYPE[128 * channels];
// how many samples are still expected to output // how many samples are still expected to output
numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput); numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput);
if (numStillExpected < 0) numStillExpected = 0;
memset(buff, 0, 128 * channels * sizeof(SAMPLETYPE)); memset(buff, 0, 128 * channels * sizeof(SAMPLETYPE));
// "Push" the last active samples out from the processing pipeline by // "Push" the last active samples out from the processing pipeline by
// feeding blank samples into the processing pipeline until new, // feeding blank samples into the processing pipeline until new,
// processed samples appear in the output (not however, more than // processed samples appear in the output (not however, more than
// 24ksamples in any case) // 24ksamples in any case)
for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i ++) for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i ++)
{ {
putSamples(buff, 128); putSamples(buff, 128);
} }
adjustAmountOfSamples(numStillExpected); adjustAmountOfSamples(numStillExpected);
delete[] buff; delete[] buff;
@ -446,7 +447,7 @@ int SoundTouch::getSetting(int settingId) const
return pRateTransposer->getAAFilter()->getLength(); return pRateTransposer->getAAFilter()->getLength();
case SETTING_USE_QUICKSEEK : case SETTING_USE_QUICKSEEK :
return (uint) pTDStretch->isQuickSeekEnabled(); return (uint)pTDStretch->isQuickSeekEnabled();
case SETTING_SEQUENCE_MS: case SETTING_SEQUENCE_MS:
pTDStretch->getParameters(NULL, &temp, NULL, NULL); pTDStretch->getParameters(NULL, &temp, NULL, NULL);
@ -460,23 +461,65 @@ int SoundTouch::getSetting(int settingId) const
pTDStretch->getParameters(NULL, NULL, NULL, &temp); pTDStretch->getParameters(NULL, NULL, NULL, &temp);
return temp; return temp;
case SETTING_NOMINAL_INPUT_SEQUENCE : case SETTING_NOMINAL_INPUT_SEQUENCE :
return pTDStretch->getInputSampleReq(); {
int size = pTDStretch->getInputSampleReq();
case SETTING_NOMINAL_OUTPUT_SEQUENCE : #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
return pTDStretch->getOutputBatchSize(); if (rate <= 1.0)
{
// transposing done before timestretch, which impacts latency
return (int)(size * rate + 0.5);
}
#endif
return size;
}
default : case SETTING_NOMINAL_OUTPUT_SEQUENCE :
{
int size = pTDStretch->getOutputBatchSize();
if (rate > 1.0)
{
// transposing done after timestretch, which impacts latency
return (int)(size / rate + 0.5);
}
return size;
}
case SETTING_INITIAL_LATENCY:
{
double latency = pTDStretch->getLatency();
int latency_tr = pRateTransposer->getLatency();
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
if (rate <= 1.0)
{
// transposing done before timestretch, which impacts latency
latency = (latency + latency_tr) * rate;
}
else
#endif
{
latency += (double)latency_tr / rate;
}
return (int)(latency + 0.5);
}
default :
return 0; return 0;
} }
} }
// Clears all the samples in the object's output and internal processing // Clears all the samples in the object's output and internal processing
// buffers. // buffers.
void SoundTouch::clear() void SoundTouch::clear()
{ {
samplesExpectedOut = 0; samplesExpectedOut = 0;
samplesOutput = 0;
pRateTransposer->clear(); pRateTransposer->clear();
pTDStretch->clear(); pTDStretch->clear();
} }
@ -507,9 +550,9 @@ uint SoundTouch::numUnprocessedSamples() const
/// \return Number of samples returned. /// \return Number of samples returned.
uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples) uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples)
{ {
uint ret = FIFOProcessor::receiveSamples(output, maxSamples); uint ret = FIFOProcessor::receiveSamples(output, maxSamples);
samplesOutput += (long)ret; samplesOutput += (long)ret;
return ret; return ret;
} }
@ -520,7 +563,16 @@ uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples)
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
uint SoundTouch::receiveSamples(uint maxSamples) uint SoundTouch::receiveSamples(uint maxSamples)
{ {
uint ret = FIFOProcessor::receiveSamples(maxSamples); uint ret = FIFOProcessor::receiveSamples(maxSamples);
samplesOutput += (long)ret; samplesOutput += (long)ret;
return ret; return ret;
}
/// Get ratio between input and output audio durations, useful for calculating
/// processed output duration: if you'll process a stream of N samples, then
/// you can expect to get out N * getInputOutputSampleRatio() samples.
double SoundTouch::getInputOutputSampleRatio()
{
return 1.0 / (tempo * rate);
} }

View File

@ -4,8 +4,14 @@
/// while maintaining the original pitch by using a time domain WSOLA-like /// while maintaining the original pitch by using a time domain WSOLA-like
/// method with several performance-increasing tweaks. /// method with several performance-increasing tweaks.
/// ///
/// Note : MMX optimized functions reside in a separate, platform-specific /// Notes : MMX optimized functions reside in a separate, platform-specific
/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'.
///
/// This source file contains OpenMP optimizations that allow speeding up the
/// corss-correlation algorithm by executing it in several threads / CPU cores
/// in parallel. See the following article link for more detailed discussion
/// about SoundTouch OpenMP optimizations:
/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi /// Author e-mail : oparviai 'at' iki.fi
@ -13,10 +19,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ // Last changed : $Date: 2017-04-07 22:01:22 +0300 (pe, 07 huhti 2017) $
// File revision : $Revision: 1.12 $ // File revision : $Revision: 1.12 $
// //
// $Id: TDStretch.cpp 226 2015-08-08 21:00:15Z oparviai $ // $Id: TDStretch.cpp 249 2017-04-07 19:01:22Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -219,6 +225,7 @@ void TDStretch::clearInput()
{ {
inputBuffer.clear(); inputBuffer.clear();
clearMidBuffer(); clearMidBuffer();
isBeginning = true;
} }
@ -297,12 +304,13 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
int i; int i;
double norm; double norm;
bestCorr = FLT_MIN; bestCorr = -FLT_MAX;
bestOffs = 0; bestOffs = 0;
// Scans for the best correlation value by testing each possible position // Scans for the best correlation value by testing each possible position
// over the permitted range. // over the permitted range.
bestCorr = calcCrossCorr(refPos, pMidBuffer, norm); bestCorr = calcCrossCorr(refPos, pMidBuffer, norm);
bestCorr = (bestCorr + 0.1) * 0.75;
#pragma omp parallel for #pragma omp parallel for
for (i = 1; i < seekLength; i ++) for (i = 1; i < seekLength; i ++)
@ -373,12 +381,10 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
// note: 'float' types used in this function in case that the platform would need to use software-fp // note: 'float' types used in this function in case that the platform would need to use software-fp
bestCorr = FLT_MIN; bestCorr =
bestOffs = SCANWIND; bestCorr2 = -FLT_MAX;
bestCorr2 = FLT_MIN; bestOffs =
bestOffs2 = 0; bestOffs2 = SCANWIND;
int best = 0;
// Scans for the best correlation value by testing each possible position // Scans for the best correlation value by testing each possible position
// over the permitted range. Look for two best matches on the first pass to // over the permitted range. Look for two best matches on the first pass to
@ -436,7 +442,6 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
{ {
bestCorr = corr; bestCorr = corr;
bestOffs = i; bestOffs = i;
best = 1;
} }
} }
@ -458,7 +463,6 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
{ {
bestCorr = corr; bestCorr = corr;
bestOffs = i; bestOffs = i;
best = 2;
} }
} }
@ -520,13 +524,13 @@ void TDStretch::calcSeqParameters()
#define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%) #define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%)
// sequence-ms setting values at above low & top tempo // sequence-ms setting values at above low & top tempo
#define AUTOSEQ_AT_MIN 125.0 #define AUTOSEQ_AT_MIN 90.0
#define AUTOSEQ_AT_MAX 50.0 #define AUTOSEQ_AT_MAX 40.0
#define AUTOSEQ_K ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) #define AUTOSEQ_K ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))
#define AUTOSEQ_C (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW)) #define AUTOSEQ_C (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW))
// seek-window-ms setting values at above low & top tempoq // seek-window-ms setting values at above low & top tempoq
#define AUTOSEEK_AT_MIN 25.0 #define AUTOSEEK_AT_MIN 20.0
#define AUTOSEEK_AT_MAX 15.0 #define AUTOSEEK_AT_MAX 15.0
#define AUTOSEEK_K ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) #define AUTOSEEK_K ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))
#define AUTOSEEK_C (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW)) #define AUTOSEEK_C (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW))
@ -637,7 +641,8 @@ void TDStretch::processNominalTempo()
// the result into 'outputBuffer' // the result into 'outputBuffer'
void TDStretch::processSamples() void TDStretch::processSamples()
{ {
int ovlSkip, offset; int ovlSkip;
int offset = 0;
int temp; int temp;
/* Removed this small optimization - can introduce a click to sound when tempo setting /* Removed this small optimization - can introduce a click to sound when tempo setting
@ -654,35 +659,61 @@ void TDStretch::processSamples()
// to form a processing frame. // to form a processing frame.
while ((int)inputBuffer.numSamples() >= sampleReq) while ((int)inputBuffer.numSamples() >= sampleReq)
{ {
// If tempo differs from the normal ('SCALE'), scan for the best overlapping if (isBeginning == false)
// position {
offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); // apart from the very beginning of the track,
// scan for the best overlapping position & do overlap-add
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 // samples in 'midBuffer' using sliding overlapping
// ... first partially overlap with the end of the previous sequence // ... first partially overlap with the end of the previous sequence
// (that's in 'midBuffer') // (that's in 'midBuffer')
overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset); overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset);
outputBuffer.putSamples((uint)overlapLength); outputBuffer.putSamples((uint)overlapLength);
offset += overlapLength;
}
else
{
// Adjust processing offset at beginning of track by not perform initial overlapping
// and compensating that in the 'input buffer skip' calculation
isBeginning = false;
int skip = (int)(tempo * overlapLength + 0.5);
#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION
#ifdef SOUNDTOUCH_ALLOW_SSE
// if SSE mode, round the skip amount to value corresponding to aligned memory address
if (channels == 1)
{
skip &= -4;
}
else if (channels == 2)
{
skip &= -2;
}
#endif
#endif
skipFract -= skip;
assert(nominalSkip >= -skipFract);
}
// ... then copy sequence samples from 'inputBuffer' to output: // ... then copy sequence samples from 'inputBuffer' to output:
// length of sequence
temp = (seekWindowLength - 2 * overlapLength);
// crosscheck that we don't have buffer overflow... // crosscheck that we don't have buffer overflow...
if ((int)inputBuffer.numSamples() < (offset + temp + overlapLength * 2)) if ((int)inputBuffer.numSamples() < (offset + seekWindowLength - overlapLength))
{ {
continue; // just in case, shouldn't really happen continue; // just in case, shouldn't really happen
} }
outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * (offset + overlapLength), (uint)temp); // length of sequence
temp = (seekWindowLength - 2 * overlapLength);
outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * offset, (uint)temp);
// Copies the end of the current sequence from 'inputBuffer' to // Copies the end of the current sequence from 'inputBuffer' to
// 'midBuffer' for being mixed with the beginning of the next // 'midBuffer' for being mixed with the beginning of the next
// processing sequence and so on // processing sequence and so on
assert((offset + temp + overlapLength * 2) <= (int)inputBuffer.numSamples()); assert((offset + temp + overlapLength) <= (int)inputBuffer.numSamples());
memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp + overlapLength), memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp),
channels * sizeof(SAMPLETYPE) * overlapLength); channels * sizeof(SAMPLETYPE) * overlapLength);
// Remove the processed samples from the input buffer. Update // Remove the processed samples from the input buffer. Update
@ -879,7 +910,12 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do
if (lnorm > maxnorm) if (lnorm > maxnorm)
{ {
maxnorm = lnorm; // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
#pragma omp critical
if (lnorm > maxnorm)
{
maxnorm = lnorm;
}
} }
// 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 // done using floating point operation

View File

@ -13,10 +13,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ // Last changed : $Date: 2016-10-20 19:30:11 +0300 (to, 20 loka 2016) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: TDStretch.h 226 2015-08-08 21:00:15Z oparviai $ // $Id: TDStretch.h 244 2016-10-20 16:30:11Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -134,6 +134,7 @@ protected:
bool bQuickSeek; bool bQuickSeek;
bool bAutoSeqSetting; bool bAutoSeqSetting;
bool bAutoSeekSetting; bool bAutoSeekSetting;
bool isBeginning;
SAMPLETYPE *pMidBuffer; SAMPLETYPE *pMidBuffer;
SAMPLETYPE *pMidBufferUnaligned; SAMPLETYPE *pMidBufferUnaligned;
@ -247,6 +248,13 @@ public:
{ {
return seekWindowLength - overlapLength; return seekWindowLength - overlapLength;
} }
/// return approximate initial input-output latency
int getLatency() const
{
return sampleReq;
}
}; };

View File

@ -12,7 +12,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2008-02-10 18:26:55 +0200 (Sun, 10 Feb 2008) $ // Last changed : $Date: 2008-02-10 18:26:55 +0200 (su, 10 helmi 2008) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $ // $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $

View File

@ -11,7 +11,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2014-01-07 20:24:28 +0200 (Tue, 07 Jan 2014) $ // Last changed : $Date: 2014-01-07 20:24:28 +0200 (ti, 07 tammi 2014) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: cpu_detect_x86.cpp 183 2014-01-07 18:24:28Z oparviai $ // $Id: cpu_detect_x86.cpp 183 2014-01-07 18:24:28Z oparviai $

View File

@ -20,10 +20,10 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ // Last changed : $Date: 2017-03-05 15:56:03 +0200 (su, 05 maalis 2017) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: mmx_optimized.cpp 226 2015-08-08 21:00:15Z oparviai $ // $Id: mmx_optimized.cpp 247 2017-03-05 13:56:03Z oparviai $
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -125,7 +125,12 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &d
if (norm > (long)maxnorm) if (norm > (long)maxnorm)
{ {
maxnorm = norm; // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
#pragma omp critical
if (norm > (long)maxnorm)
{
maxnorm = norm;
}
} }
// Normalize result by dividing by sqrt(norm) - this step is easiest // Normalize result by dividing by sqrt(norm) - this step is easiest

View File

@ -23,7 +23,7 @@
/// ///
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Last changed : $Date: 2015-08-09 00:00:15 +0300 (Sun, 09 Aug 2015) $ // Last changed : $Date: 2015-08-09 00:00:15 +0300 (su, 09 elo 2015) $
// File revision : $Revision: 4 $ // File revision : $Revision: 4 $
// //
// $Id: sse_optimized.cpp 226 2015-08-08 21:00:15Z oparviai $ // $Id: sse_optimized.cpp 226 2015-08-08 21:00:15Z oparviai $