3rdparty/soundtouch: Bump to v2.3.3

This commit is contained in:
JordanTheToaster 2024-08-06 03:23:12 +01:00 committed by lightningterror
parent 30e7de7555
commit ebc3923b35
32 changed files with 954 additions and 915 deletions

View File

@ -15,8 +15,8 @@
<body class="normal"> <body class="normal">
<hr> <hr>
<h1>SoundTouch audio processing library v2.3.1</h1> <h1>SoundTouch audio processing library v2.3.3</h1>
<p class="normal">SoundTouch library Copyright &copy; Olli Parviainen 2001-2021</p> <p class="normal">SoundTouch library Copyright &copy; Olli Parviainen 2001-2024</p>
<hr> <hr>
<h2>1. Introduction </h2> <h2>1. Introduction </h2>
<p>SoundTouch is an open-source audio processing library that allows <p>SoundTouch is an open-source audio processing library that allows
@ -35,7 +35,7 @@
<p>Author email: oparviai 'at' iki.fi </p> <p>Author email: oparviai 'at' iki.fi </p>
<p>SoundTouch WWW page: <a href="http://soundtouch.surina.net">http://soundtouch.surina.net</a></p> <p>SoundTouch WWW page: <a href="http://soundtouch.surina.net">http://soundtouch.surina.net</a></p>
<p>SoundTouch git repository: <a <p>SoundTouch git repository: <a
href="https://gitlab.com/soundtouch/soundtouch.git">https://gitlab.com/soundtouch/soundtouch.git</a></p> href="https://codeberg.org/soundtouch/soundtouch.git">https://codeberg.org/soundtouch/soundtouch.git</a></p>
<hr> <hr>
<h2>2. Compiling SoundTouch</h2> <h2>2. Compiling SoundTouch</h2>
<p>Before compiling, notice that you can choose the sample data format if it's <p>Before compiling, notice that you can choose the sample data format if it's
@ -131,10 +131,12 @@
</table> </table>
<b>Compiling portable Shared Library / DLL version</b> <b>Compiling portable Shared Library / DLL version</b>
<p> The GNU autotools compilation does not automatically create a shared-library version of <p> The GNU autotools compilation automatically builds an additional dynamic-link version
SoundTouch (.so or .dll) that features position-independent code and C-language of SoundTouch library that features position-independent code and "C"-style API that is
api that are more suitable for cross-language development than C++ libraries.</p> more suitable for calling the SoundTouch routines from other programming languages.</p>
<p> Use script "make-gnu-dll-sh" to build a portable dynamic library version if such is desired.</p> <p>This dynamic-link library is built under source/SoundTouchDLL directory, whose
subdirectories also comtain simple example apps that use the dynamic-link library.
</p>
<h4><b>2.2.2 Compiling with cmake</b></h4> <h4><b>2.2.2 Compiling with cmake</b></h4>
<p>'cmake' build scripts are provided as an alternative to the autotools toolchain.</p> <p>'cmake' build scripts are provided as an alternative to the autotools toolchain.</p>
@ -145,6 +147,9 @@
cmake . cmake .
make -j make -j
make install</pre> make install</pre>
<p>To list available build options:</p>
<pre>
cmake -LH</pre>
<p>To compile the additional portable Shared Library / DLL version with the native C-language API:</p> <p>To compile the additional portable Shared Library / DLL version with the native C-language API:</p>
<pre> <pre>
cmake . -DSOUNDTOUCH_DLL=ON cmake . -DSOUNDTOUCH_DLL=ON
@ -448,7 +453,7 @@
<h2><a name="SoundStretch"></a>4. SoundStretch audio processing utility <h2><a name="SoundStretch"></a>4. SoundStretch audio processing utility
</h2> </h2>
<p>SoundStretch audio processing utility<br> <p>SoundStretch audio processing utility<br>
Copyright (c) Olli Parviainen 2002-2015</p> Copyright (c) Olli Parviainen 2002-2024</p>
<p>SoundStretch is a simple command-line application that can change <p>SoundStretch is a simple command-line application that can change
tempo, pitch and playback rates of WAV sound files. This program is tempo, pitch and playback rates of WAV sound files. This program is
intended primarily to demonstrate how the "SoundTouch" library can be intended primarily to demonstrate how the "SoundTouch" library can be
@ -603,6 +608,18 @@
<hr> <hr>
<h2>5. Change History</h2> <h2>5. Change History</h2>
<h3>5.1. SoundTouch library Change History </h3> <h3>5.1. SoundTouch library Change History </h3>
<p><b>2.3.3:</b></p>
<ul class="current">
<li>Fixing compiler warnings, maintenance fixes to make/build files for various systems
</li>
</ul>
<p><b>2.3.2:</b></p>
<ul>
<li>Improve autotools makefiles to build the `SoundTouchDLL` dynamic-link link library with
C-style API. This library variation is easier to import and use from other programming
languages than the default C++ library.
</li>
</ul>
<p><b>2.3.1:</b></p> <p><b>2.3.1:</b></p>
<ul> <ul>
<li>Adjusted cmake build settings and header files that cmake installs</li> <li>Adjusted cmake build settings and header files that cmake installs</li>
@ -622,7 +639,7 @@
window. This ensures that with zero tempo change the output will be same as input. window. This ensures that with zero tempo change the output will be same as input.
</li> </li>
<li>Bugfix: Fix a bug in TDstrectch with too small initial skipFract value that occurred <li>Bugfix: Fix a bug in TDstrectch with too small initial skipFract value that occurred
with certain processing parameter settings: Replace assert with assignment that with certain processing parameter settings: Replace assert with assignment that
corrects the situation. corrects the situation.
</li> </li>
<li>Remove OpenMP "_init_threading" workaround from Android build as it's not needed with concurrent <li>Remove OpenMP "_init_threading" workaround from Android build as it's not needed with concurrent
@ -865,11 +882,14 @@
<li> Initial release</li> <li> Initial release</li>
</ul> </ul>
<h3>5.2. SoundStretch application Change History </h3> <h3>5.2. SoundStretch application Change History </h3>
<p><b>2.3.3:</b></p>
<ul class="current_soundstretch">
<li>Added support for Asian / non-latin filenames in Windows. Gnu platform has supported them already earlier.</li>
</ul>
<p><b>1.9:</b></p> <p><b>1.9:</b></p>
<ul> <ul>
<li>Added support for WAV file 'fact' information chunk.</li> <li>Added support for WAV file 'fact' information chunk.</li>
</ul> </ul>
<p><b>1.7.0:</b></p> <p><b>1.7.0:</b></p>
<ul> <ul>
<li>Bugfixes in Wavfile: exception string formatting, avoid getLengthMs() integer <li>Bugfixes in Wavfile: exception string formatting, avoid getLengthMs() integer
@ -966,6 +986,7 @@
<li> Michael Pruett</li> <li> Michael Pruett</li>
<li> Rajeev Puran</li> <li> Rajeev Puran</li>
<li> RJ Ryan</li> <li> RJ Ryan</li>
<li> Serge Sans Paille</li>
<li> John Sheehy</li> <li> John Sheehy</li>
<li> Tim Shuttleworth</li> <li> Tim Shuttleworth</li>
<li> Albert Sirvent</li> <li> Albert Sirvent</li>

View File

@ -14,10 +14,10 @@
/// taking absolute value that's smoothed by sliding average. Signal levels that /// 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 /// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there. /// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term /// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal. /// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is /// - 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 /// 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. /// function, calculates it's precise location and converts this reading to bpm's.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -137,8 +137,8 @@ namespace soundtouch
// 2nd order low-pass-filter // 2nd order low-pass-filter
IIR2_filter beat_lpf; IIR2_filter beat_lpf;
/// Updates auto-correlation function for given number of decimated samples that /// Updates auto-correlation function for given number of decimated samples that
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
/// though). /// though).
void updateXCorr(int process_samples /// How many samples are processed. void updateXCorr(int process_samples /// How many samples are processed.
); );
@ -175,9 +175,9 @@ namespace soundtouch
/// Inputs a block of samples for analyzing: Envelopes the samples and then /// Inputs a block of samples for analyzing: Envelopes the samples and then
/// updates the autocorrelation estimation. When whole song data has been input /// updates the autocorrelation estimation. When whole song data has been input
/// in smaller blocks using this function, read the resulting bpm with 'getBpm' /// in smaller blocks using this function, read the resulting bpm with 'getBpm'
/// function. /// function.
/// ///
/// Notice that data in 'samples' array can be disrupted in processing. /// Notice that data in 'samples' array can be disrupted in processing.
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
int numSamples ///< Number of samples in buffer int numSamples ///< Number of samples in buffer
@ -190,13 +190,13 @@ namespace soundtouch
/// \return Beats-per-minute rate, or zero if detection failed. /// \return Beats-per-minute rate, or zero if detection failed.
float getBpm(); float getBpm();
/// Get beat position arrays. Note: The array includes also really low beat detection values /// Get beat position arrays. Note: The array includes also really low beat detection values
/// in absence of clear strong beats. Consumer may wish to filter low values away. /// in absence of clear strong beats. Consumer may wish to filter low values away.
/// - "pos" receive array of beat positions /// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths /// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array. /// - max_num indicates max.size of "pos" and "values" array.
/// ///
/// You can query a suitable array sized by calling this with NULL in "pos" & "values". /// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
/// ///
/// \return number of beats in the arrays. /// \return number of beats in the arrays.
int getBeats(float *pos, float *strength, int max_num); int getBeats(float *pos, float *strength, int max_num);

View File

@ -1,12 +1,12 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// A buffer class for temporarily storaging sound samples, operates as a /// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe. /// first-in-first-out pipe.
/// ///
/// Samples are added to the end of the sample buffer with the 'putSamples' /// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling /// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the /// the 'receiveSamples' function. The class automatically removes the
/// output samples from the buffer as well as grows the storage size /// output samples from the buffer as well as grows the storage size
/// whenever necessary. /// whenever necessary.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -47,7 +47,7 @@ namespace soundtouch
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes /// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
/// care of storage size adjustment and data moving during input/output operations. /// care of storage size adjustment and data moving during input/output operations.
/// ///
/// Notice that in case of stereo audio, one sample is considered to consist of /// Notice that in case of stereo audio, one sample is considered to consist of
/// both channel data. /// both channel data.
class FIFOSampleBuffer : public FIFOSamplePipe class FIFOSampleBuffer : public FIFOSamplePipe
{ {
@ -68,12 +68,12 @@ private:
/// Channels, 1=mono, 2=stereo. /// Channels, 1=mono, 2=stereo.
uint channels; uint channels;
/// Current position pointer to the buffer. This pointer is increased when samples are /// Current position pointer to the buffer. This pointer is increased when samples are
/// removed from the pipe so that it's necessary to actually rewind buffer (move data) /// removed from the pipe so that it's necessary to actually rewind buffer (move data)
/// only new data when is put to the pipe. /// only new data when is put to the pipe.
uint bufferPos; uint bufferPos;
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
/// beginning of the buffer. /// beginning of the buffer.
void rewind(); void rewind();
@ -93,27 +93,27 @@ public:
/// destructor /// destructor
~FIFOSampleBuffer() override; ~FIFOSampleBuffer() override;
/// Returns a pointer to the beginning of the output samples. /// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly. /// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping! /// Please be careful for not to corrupt the book-keeping!
/// ///
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() override; virtual SAMPLETYPE *ptrBegin() override;
/// Returns a pointer to the end of the used part of the sample buffer (i.e. /// Returns a pointer to the end of the used part of the sample buffer (i.e.
/// where the new samples are to be inserted). This function may be used for /// where the new samples are to be inserted). This function may be used for
/// inserting new samples into the sample buffer directly. Please be careful /// inserting new samples into the sample buffer directly. Please be careful
/// not corrupt the book-keeping! /// not corrupt the book-keeping!
/// ///
/// When using this function as means for inserting new samples, also remember /// When using this function as means for inserting new samples, also remember
/// to increase the sample count afterwards, by calling the /// to increase the sample count afterwards, by calling the
/// 'putSamples(numSamples)' function. /// 'putSamples(numSamples)' function.
SAMPLETYPE *ptrEnd( SAMPLETYPE *ptrEnd(
uint slackCapacity ///< How much free capacity (in samples) there _at least_ uint slackCapacity ///< How much free capacity (in samples) there _at least_
///< should be so that the caller can successfully insert the ///< should be so that the caller can successfully insert the
///< desired samples to the buffer. If necessary, the function ///< desired samples to the buffer. If necessary, the function
///< grows the buffer size to comply with this requirement. ///< grows the buffer size to comply with this requirement.
); );
@ -123,17 +123,17 @@ public:
uint numSamples ///< Number of samples to insert. uint numSamples ///< Number of samples to insert.
) override; ) override;
/// Adjusts the book-keeping to increase number of samples in the buffer without /// Adjusts the book-keeping to increase number of samples in the buffer without
/// copying any actual samples. /// copying any actual samples.
/// ///
/// This function is used to update the number of samples in the sample buffer /// This function is used to update the number of samples in the sample buffer
/// when accessing the buffer directly with 'ptrEnd' function. Please be /// when accessing the buffer directly with 'ptrEnd' function. Please be
/// careful though! /// careful though!
virtual void putSamples(uint numSamples ///< Number of samples been inserted. virtual void putSamples(uint numSamples ///< Number of samples been inserted.
); );
/// Output samples from beginning of the sample buffer. Copies requested samples to /// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
@ -141,8 +141,8 @@ public:
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) override; ) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
@ -156,7 +156,7 @@ public:
void setChannels(int numChannels); void setChannels(int numChannels);
/// Get number of channels /// Get number of channels
int getChannels() int getChannels()
{ {
return channels; return channels;
} }

View File

@ -5,7 +5,7 @@
/// into one end of the pipe with the 'putSamples' function, and the processed /// into one end of the pipe with the 'putSamples' function, and the processed
/// samples are received from the other end with the 'receiveSamples' function. /// samples are received from the other end with the 'receiveSamples' function.
/// ///
/// 'FIFOProcessor' : A base class for classes the do signal processing with /// 'FIFOProcessor' : A base class for classes the do signal processing with
/// the samples while operating like a first-in-first-out pipe. When samples /// the samples while operating like a first-in-first-out pipe. When samples
/// are input with the 'putSamples' function, the class processes them /// are input with the 'putSamples' function, the class processes them
/// and moves the processed samples to the given 'output' pipe object, which /// and moves the processed samples to the given 'output' pipe object, which
@ -68,12 +68,12 @@ public:
virtual ~FIFOSamplePipe() {} virtual ~FIFOSamplePipe() {}
/// Returns a pointer to the beginning of the output samples. /// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly. /// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping! /// Please be careful for not to corrupt the book-keeping!
/// ///
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() = 0; virtual SAMPLETYPE *ptrBegin() = 0;
@ -88,14 +88,14 @@ public:
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
) )
{ {
int oNumSamples = other.numSamples(); const uint oNumSamples = other.numSamples();
putSamples(other.ptrBegin(), oNumSamples); putSamples(other.ptrBegin(), oNumSamples);
other.receiveSamples(oNumSamples); other.receiveSamples(oNumSamples);
}; }
/// Output samples from beginning of the sample buffer. Copies requested samples to /// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
@ -103,8 +103,8 @@ public:
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) = 0; ) = 0;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
@ -127,12 +127,12 @@ public:
}; };
/// Base-class for sound processing routines working in FIFO principle. With this base /// Base-class for sound processing routines working in FIFO principle. With this base
/// class it's easy to implement sound processing stages that can be chained together, /// class it's easy to implement sound processing stages that can be chained together,
/// so that samples that are fed into beginning of the pipe automatically go through /// so that samples that are fed into beginning of the pipe automatically go through
/// all the processing stages. /// all the processing stages.
/// ///
/// When samples are input to this class, they're first processed and then put to /// When samples are input to this class, they're first processed and then put to
/// the FIFO pipe that's defined as output of this class. This output pipe can be /// the FIFO pipe that's defined as output of this class. This output pipe can be
/// either other processing stage or a FIFO sample buffer. /// either other processing stage or a FIFO sample buffer.
class FIFOProcessor :public FIFOSamplePipe class FIFOProcessor :public FIFOSamplePipe
@ -144,16 +144,16 @@ protected:
/// Sets output pipe. /// Sets output pipe.
void setOutPipe(FIFOSamplePipe *pOutput) void setOutPipe(FIFOSamplePipe *pOutput)
{ {
assert(output == NULL); assert(output == nullptr);
assert(pOutput != NULL); assert(pOutput != nullptr);
output = pOutput; output = pOutput;
} }
/// Constructor. Doesn't define output pipe; it has to be set be /// Constructor. Doesn't define output pipe; it has to be set be
/// 'setOutPipe' function. /// 'setOutPipe' function.
FIFOProcessor() FIFOProcessor()
{ {
output = NULL; output = nullptr;
} }
/// Constructor. Configures output pipe. /// Constructor. Configures output pipe.
@ -168,12 +168,12 @@ protected:
{ {
} }
/// Returns a pointer to the beginning of the output samples. /// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly. /// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping! /// Please be careful for not to corrupt the book-keeping!
/// ///
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() override virtual SAMPLETYPE *ptrBegin() override
{ {
@ -182,8 +182,8 @@ protected:
public: public:
/// Output samples from beginning of the sample buffer. Copies requested samples to /// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
@ -194,8 +194,8 @@ public:
return output->receiveSamples(outBuffer, maxSamples); return output->receiveSamples(outBuffer, maxSamples);
} }
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.

View File

@ -59,15 +59,15 @@ namespace soundtouch
/// Max allowed number of channels /// Max allowed number of channels
#define SOUNDTOUCH_MAX_CHANNELS 16 #define SOUNDTOUCH_MAX_CHANNELS 16
/// Activate these undef's to overrule the possible sampletype /// Activate these undef's to overrule the possible sampletype
/// setting inherited from some other header file: /// setting inherited from some other header file:
//#undef SOUNDTOUCH_INTEGER_SAMPLES //#undef SOUNDTOUCH_INTEGER_SAMPLES
//#undef SOUNDTOUCH_FLOAT_SAMPLES //#undef SOUNDTOUCH_FLOAT_SAMPLES
/// If following flag is defined, always uses multichannel processing /// If following flag is defined, always uses multichannel processing
/// routines also for mono and stero sound. This is for routine testing /// routines also for mono and stero sound. This is for routine testing
/// purposes; output should be same with either routines, yet disabling /// purposes; output should be same with either routines, yet disabling
/// the dedicated mono/stereo processing routines will result in slower /// the dedicated mono/stereo processing routines will result in slower
/// runtime performance so recommendation is to keep this off. /// runtime performance so recommendation is to keep this off.
// #define USE_MULTICH_ALWAYS // #define USE_MULTICH_ALWAYS
@ -79,31 +79,31 @@ namespace soundtouch
#endif #endif
#if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES) #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
/// Choose either 32bit floating point or 16bit integer sampletype /// Choose either 32bit floating point or 16bit integer sampletype
/// by choosing one of the following defines, unless this selection /// by choosing one of the following defines, unless this selection
/// has already been done in some other file. /// has already been done in some other file.
//// ////
/// Notes: /// Notes:
/// - In Windows environment, choose the sample format with the /// - In Windows environment, choose the sample format with the
/// following defines. /// following defines.
/// - In GNU environment, the floating point samples are used by /// - In GNU environment, the floating point samples are used by
/// default, but integer samples can be chosen by giving the /// default, but integer samples can be chosen by giving the
/// following switch to the configure script: /// following switch to the configure script:
/// ./configure --enable-integer-samples /// ./configure --enable-integer-samples
/// However, if you still prefer to select the sample format here /// However, if you still prefer to select the sample format here
/// also in GNU environment, then please #undef the INTEGER_SAMPLE /// also in GNU environment, then please #undef the INTEGER_SAMPLE
/// and FLOAT_SAMPLE defines first as in comments above. /// and FLOAT_SAMPLE defines first as in comments above.
//#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples //#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples
#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples #define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples
#endif #endif
#if (_M_IX86 || __i386__ || __x86_64__ || _M_X64) #if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)
/// Define this to allow X86-specific assembler/intrinsic optimizations. /// Define this to allow X86-specific assembler/intrinsic optimizations.
/// Notice that library contains also usual C++ versions of each of these /// Notice that library contains also usual C++ versions of each of these
/// these routines, so if you're having difficulties getting the optimized /// these routines, so if you're having difficulties getting the optimized
/// routines compiled for whatever reason, you may disable these optimizations /// routines compiled for whatever reason, you may disable these optimizations
/// to make the library compile. /// to make the library compile.
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
@ -181,9 +181,9 @@ namespace soundtouch
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);} #define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
#endif #endif
// When this #define is active, eliminates a clicking sound when the "rate" or "pitch" // When this #define is active, eliminates a clicking sound when the "rate" or "pitch"
// parameter setting crosses from value <1 to >=1 or vice versa during processing. // parameter setting crosses from value <1 to >=1 or vice versa during processing.
// Default is off as such crossover is untypical case and involves a slight sound // Default is off as such crossover is untypical case and involves a slight sound
// quality compromise. // quality compromise.
//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1 //#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1

View File

@ -1,27 +1,27 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// ///
/// SoundTouch - main class for tempo/pitch/rate adjusting routines. /// SoundTouch - main class for tempo/pitch/rate adjusting routines.
/// ///
/// Notes: /// Notes:
/// - Initialize the SoundTouch object instance by setting up the sound stream /// - Initialize the SoundTouch object instance by setting up the sound stream
/// parameters with functions 'setSampleRate' and 'setChannels', then set /// parameters with functions 'setSampleRate' and 'setChannels', then set
/// desired tempo/pitch/rate settings with the corresponding functions. /// desired tempo/pitch/rate settings with the corresponding functions.
/// ///
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The /// - The SoundTouch class behaves like a first-in-first-out pipeline: The
/// samples that are to be processed are fed into one of the pipe by calling /// samples that are to be processed are fed into one of the pipe by calling
/// function 'putSamples', while the ready processed samples can be read /// function 'putSamples', while the ready processed samples can be read
/// from the other end of the pipeline with function 'receiveSamples'. /// from the other end of the pipeline with function 'receiveSamples'.
/// ///
/// - The SoundTouch processing classes require certain sized 'batches' of /// - The SoundTouch processing classes require certain sized 'batches' of
/// samples in order to process the sound. For this reason the classes buffer /// samples in order to process the sound. For this reason the classes buffer
/// incoming samples until there are enough of samples available for /// incoming samples until there are enough of samples available for
/// processing, then they carry out the processing step and consequently /// processing, then they carry out the processing step and consequently
/// make the processed samples available for outputting. /// make the processed samples available for outputting.
/// ///
/// - For the above reason, the processing routines introduce a certain /// - For the above reason, the processing routines introduce a certain
/// 'latency' between the input and output, so that the samples input to /// 'latency' between the input and output, so that the samples input to
/// SoundTouch may not be immediately available in the output, and neither /// SoundTouch may not be immediately available in the output, and neither
/// the amount of outputtable samples may not immediately be in direct /// the amount of outputtable samples may not immediately be in direct
/// relationship with the amount of previously input samples. /// relationship with the amount of previously input samples.
/// ///
/// - The tempo/pitch/rate control parameters can be altered during processing. /// - The tempo/pitch/rate control parameters can be altered during processing.
@ -30,8 +30,8 @@
/// required. /// required.
/// ///
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying /// - This class utilizes classes 'TDStretch' for tempo change (without modifying
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both /// pitch) and 'RateTransposer' for changing the playback rate (that is, both
/// tempo and pitch in the same ratio) of the sound. The third available control /// tempo and pitch in the same ratio) of the sound. The third available control
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of /// 'pitch' (change pitch but maintain tempo) is produced by a combination of
/// combining the two other controls. /// combining the two other controls.
/// ///
@ -72,10 +72,10 @@ namespace soundtouch
{ {
/// Soundtouch library version string /// Soundtouch library version string
#define SOUNDTOUCH_VERSION "2.3.1" #define SOUNDTOUCH_VERSION "2.3.3"
/// SoundTouch library version id /// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (20301) #define SOUNDTOUCH_VERSION_ID (20303)
// //
// Available setting IDs for the 'setSetting' & 'get_setting' functions: // Available setting IDs for the 'setSetting' & 'get_setting' functions:
@ -91,55 +91,55 @@ namespace soundtouch
/// quality compromising) /// quality compromising)
#define SETTING_USE_QUICKSEEK 2 #define SETTING_USE_QUICKSEEK 2
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines /// Time-stretch algorithm single processing sequence length in milliseconds. This determines
/// to how long sequences the original sound is chopped in the time-stretch algorithm. /// to how long sequences the original sound is chopped in the time-stretch algorithm.
/// See "STTypes.h" or README for more information. /// See "STTypes.h" or README for more information.
#define SETTING_SEQUENCE_MS 3 #define SETTING_SEQUENCE_MS 3
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the /// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
/// best possible overlapping location. This determines from how wide window the algorithm /// best possible overlapping location. This determines from how wide window the algorithm
/// may look for an optimal joining location when mixing the sound sequences back together. /// may look for an optimal joining location when mixing the sound sequences back together.
/// See "STTypes.h" or README for more information. /// See "STTypes.h" or README for more information.
#define SETTING_SEEKWINDOW_MS 4 #define SETTING_SEEKWINDOW_MS 4
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences /// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
/// are mixed back together, to form a continuous sound stream, this parameter defines over /// are mixed back together, to form a continuous sound stream, this parameter defines over
/// how long period the two consecutive sequences are let to overlap each other. /// how long period the two consecutive sequences are let to overlap each other.
/// See "STTypes.h" or README for more information. /// See "STTypes.h" or README for more information.
#define SETTING_OVERLAP_MS 5 #define SETTING_OVERLAP_MS 5
/// Call "getSetting" with this ID to query processing sequence size in samples. /// Call "getSetting" with this ID to query processing sequence size in samples.
/// This value gives approximate value of how many input samples you'll need to /// This value gives approximate value of how many input samples you'll need to
/// feed into SoundTouch after initial buffering to get out a new batch of /// feed into SoundTouch after initial buffering to get out a new batch of
/// output samples. /// output samples.
/// ///
/// This value does not include initial buffering at beginning of a new processing /// This value does not include initial buffering at beginning of a new processing
/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size. /// 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
/// - This parameter value is not constant but change depending on /// - This parameter value is not constant but 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
/// size in samples. This value tells approcimate value how many output samples /// size in samples. This value tells approcimate value how many output samples
/// SoundTouch outputs once it does DSP processing run for a batch of input samples. /// SoundTouch outputs once it does DSP processing run for a batch of input samples.
/// ///
/// Notices: /// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter /// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on /// - This parameter value is not constant but 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. /// 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 /// 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. /// you can expect to get first batch of ready output samples out.
/// ///
/// After the first output batch, you can then expect to get approx. /// After the first output batch, you can then expect to get approx.
/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every /// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every
/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch. /// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch.
/// ///
@ -149,18 +149,18 @@ namespace soundtouch
/// input sequence = 4167 samples /// input sequence = 4167 samples
/// output sequence = 3969 samples /// output sequence = 3969 samples
/// ///
/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of /// 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 /// 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. /// every approx. 4167 samples that you'll put in, you'll receive again approx.
/// 3969 samples out. /// 3969 samples out.
/// ///
/// This also means that average latency during stream processing is /// This also means that average latency during stream processing is
/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2 /// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2
/// = 3524 samples /// = 3524 samples
/// ///
/// Notices: /// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter /// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on /// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings. /// tempo/pitch/rate/samplerate settings.
#define SETTING_INITIAL_LATENCY 8 #define SETTING_INITIAL_LATENCY 8
@ -193,7 +193,7 @@ private:
/// Accumulator for how many samples in total have been read out from the processing so far /// Accumulator for how many samples in total have been read out from the processing so far
long samplesOutput; long samplesOutput;
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
/// 'virtualPitch' parameters. /// 'virtualPitch' parameters.
void calcEffectiveRateAndTempo(); void calcEffectiveRateAndTempo();
@ -237,7 +237,7 @@ public:
/// represent lower pitches, larger values higher pitch. /// represent lower pitches, larger values higher pitch.
void setPitch(double newPitch); void setPitch(double newPitch);
/// Sets pitch change in octaves compared to the original pitch /// Sets pitch change in octaves compared to the original pitch
/// (-1.00 .. +1.00) /// (-1.00 .. +1.00)
void setPitchOctaves(double newPitch); void setPitchOctaves(double newPitch);
@ -253,20 +253,20 @@ public:
void setSampleRate(uint srate); void setSampleRate(uint srate);
/// Get ratio between input and output audio durations, useful for calculating /// Get ratio between input and output audio durations, useful for calculating
/// processed output duration: if you'll process a stream of N samples, then /// processed output duration: if you'll process a stream of N samples, then
/// you can expect to get out N * getInputOutputSampleRatio() samples. /// you can expect to get out N * getInputOutputSampleRatio() samples.
/// ///
/// This ratio will give accurate target duration ratio for a full audio track, /// 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. /// given that the the whole track is processed with same processing parameters.
/// ///
/// If this ratio is applied to calculate intermediate offsets inside a processing /// 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 /// 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 /// from ideal offset, yet by end of the audio stream the duration ratio will become
/// exact. /// exact.
/// ///
/// Example: if processing with parameters "-tempo=15 -pitch=-3", the function /// Example: if processing with parameters "-tempo=15 -pitch=-3", the function
/// will return value 0.8695652... Now, if processing an audio stream whose duration /// 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 /// is exactly one million audio samples, then you can expect the processed
/// output duration be 0.869565 * 1000000 = 869565 samples. /// output duration be 0.869565 * 1000000 = 869565 samples.
double getInputOutputSampleRatio(); double getInputOutputSampleRatio();
@ -289,8 +289,8 @@ public:
///< contains data for both channels. ///< contains data for both channels.
) override; ) override;
/// Output samples from beginning of the sample buffer. Copies requested samples to /// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
@ -298,8 +298,8 @@ public:
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) override; ) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
@ -312,7 +312,7 @@ public:
/// Changes a setting controlling the processing system behaviour. See the /// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's. /// 'SETTING_...' defines for available setting ID's.
/// ///
/// \return 'true' if the setting was successfully changed /// \return 'true' if the setting was successfully changed
bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
int value ///< New setting value. int value ///< New setting value.
@ -338,7 +338,7 @@ public:
/// classes 'FIFOProcessor' and 'FIFOSamplePipe') /// classes 'FIFOProcessor' and 'FIFOSamplePipe')
/// ///
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
/// - numSamples() : Get number of 'ready' samples that can be received with /// - numSamples() : Get number of 'ready' samples that can be received with
/// function 'receiveSamples()' /// function 'receiveSamples()'
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
/// - clear() : Clears all samples from ready/processing buffers. /// - clear() : Clears all samples from ready/processing buffers.

View File

@ -0,0 +1,52 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Char type for SoundStretch
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef SS_CHARTYPE_H
#define SS_CHARTYPE_H
#include <string>
namespace soundstretch
{
#if _WIN32
// wide-char types for supporting non-latin file paths in Windows
using CHARTYPE = wchar_t;
using STRING = std::wstring;
#define STRING_CONST(x) (L"" x)
#else
// gnu platform can natively support UTF-8 paths using "char*" set
using CHARTYPE = char;
using STRING = std::string;
#define STRING_CONST(x) (x)
#endif
}
#endif //SS_CHARTYPE_H

View File

@ -1,12 +1,12 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Classes for easy reading & writing of WAV sound files. /// Classes for easy reading & writing of WAV sound files.
/// ///
/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly /// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly
/// parse the WAV files with such processors. /// parse the WAV files with such processors.
/// ///
/// Admittingly, more complete WAV reader routines may exist in public domain, /// Admittingly, more complete WAV reader routines may exist in public domain,
/// but the reason for 'yet another' one is that those generic WAV reader /// but the reason for 'yet another' one is that those generic WAV reader
/// libraries are exhaustingly large and cumbersome! Wanted to have something /// libraries are exhaustingly large and cumbersome! Wanted to have something
/// simpler here, i.e. something that's not already larger than rest of the /// simpler here, i.e. something that's not already larger than rest of the
/// SoundTouch/SoundStretch program... /// SoundTouch/SoundStretch program...
@ -42,91 +42,100 @@
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <cstring> #include <cstring>
#include <assert.h> #include <cassert>
#include <limits.h> #include <climits>
#include "WavFile.h" #include "WavFile.h"
#include "STTypes.h" #include "STTypes.h"
using namespace std; using namespace std;
namespace soundstretch
{
#if _WIN32
#define FOPEN(name, mode) _wfopen(name, STRING_CONST(mode))
#else
#define FOPEN(name, mode) fopen(name, mode)
#endif
static const char riffStr[] = "RIFF"; static const char riffStr[] = "RIFF";
static const char waveStr[] = "WAVE"; static const char waveStr[] = "WAVE";
static const char fmtStr[] = "fmt "; static const char fmtStr[] = "fmt ";
static const char factStr[] = "fact"; static const char factStr[] = "fact";
static const char dataStr[] = "data"; static const char dataStr[] = "data";
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// Helper functions for swapping byte order to correctly read/write WAV files // Helper functions for swapping byte order to correctly read/write WAV files
// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to // with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to
// turn-on the conversion if it appears necessary. // turn-on the conversion if it appears necessary.
// //
// For example, Intel x86 is little-endian and doesn't require conversion, // For example, Intel x86 is little-endian and doesn't require conversion,
// while PowerPC of Mac's and many other RISC cpu's are big-endian. // while PowerPC of Mac's and many other RISC cpu's are big-endian.
#ifdef BYTE_ORDER #ifdef BYTE_ORDER
// In gcc compiler detect the byte order automatically // In gcc compiler detect the byte order automatically
#if BYTE_ORDER == BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
// big-endian platform. // big-endian platform.
#define _BIG_ENDIAN_ #define _BIG_ENDIAN_
#endif
#endif #endif
#endif
#ifdef _BIG_ENDIAN_ #ifdef _BIG_ENDIAN_
// big-endian CPU, swap bytes in 16 & 32 bit words // big-endian CPU, swap bytes in 16 & 32 bit words
// helper-function to swap byte-order of 32bit integer // helper-function to swap byte-order of 32bit integer
static inline int _swap32(int &dwData) static inline int _swap32(int& dwData)
{ {
dwData = ((dwData >> 24) & 0x000000FF) | dwData = ((dwData >> 24) & 0x000000FF) |
((dwData >> 8) & 0x0000FF00) | ((dwData >> 8) & 0x0000FF00) |
((dwData << 8) & 0x00FF0000) | ((dwData << 8) & 0x00FF0000) |
((dwData << 24) & 0xFF000000); ((dwData << 24) & 0xFF000000);
return dwData; return dwData;
} }
// helper-function to swap byte-order of 16bit integer // helper-function to swap byte-order of 16bit integer
static inline short _swap16(short &wData) static inline short _swap16(short& wData)
{
wData = ((wData >> 8) & 0x00FF) |
((wData << 8) & 0xFF00);
return wData;
}
// helper-function to swap byte-order of buffer of 16bit integers
static inline void _swap16Buffer(short* pData, int numWords)
{
int i;
for (i = 0; i < numWords; i++)
{ {
wData = ((wData >> 8) & 0x00FF) | pData[i] = _swap16(pData[i]);
((wData << 8) & 0xFF00);
return wData;
}
// helper-function to swap byte-order of buffer of 16bit integers
static inline void _swap16Buffer(short *pData, int numWords)
{
int i;
for (i = 0; i < numWords; i ++)
{
pData[i] = _swap16(pData[i]);
}
} }
}
#else // BIG_ENDIAN #else // BIG_ENDIAN
// little-endian CPU, WAV file is ok as such // little-endian CPU, WAV file is ok as such
// dummy helper-function // dummy helper-function
static inline int _swap32(int &dwData) static inline int _swap32(int& dwData)
{ {
// do nothing // do nothing
return dwData; return dwData;
} }
// dummy helper-function // dummy helper-function
static inline short _swap16(short &wData) static inline short _swap16(short& wData)
{ {
// do nothing // do nothing
return wData; return wData;
} }
// dummy helper-function // dummy helper-function
static inline void _swap16Buffer(short *pData, int numBytes) static inline void _swap16Buffer(short*, int)
{ {
// do nothing // do nothing
} }
#endif // BIG_ENDIAN #endif // BIG_ENDIAN
@ -138,7 +147,7 @@ static const char dataStr[] = "data";
WavFileBase::WavFileBase() WavFileBase::WavFileBase()
{ {
convBuff = NULL; convBuff = nullptr;
convBuffSize = 0; convBuffSize = 0;
} }
@ -151,7 +160,7 @@ WavFileBase::~WavFileBase()
/// Get pointer to conversion buffer of at min. given size /// Get pointer to conversion buffer of at min. given size
void *WavFileBase::getConvBuffer(int sizeBytes) void* WavFileBase::getConvBuffer(int sizeBytes)
{ {
if (convBuffSize < sizeBytes) if (convBuffSize < sizeBytes)
{ {
@ -169,32 +178,26 @@ void *WavFileBase::getConvBuffer(int sizeBytes)
// Class WavInFile // Class WavInFile
// //
WavInFile::WavInFile(const char *fileName) WavInFile::WavInFile(const STRING& fileName)
{ {
// Try to open the file for reading // Try to open the file for reading
fptr = fopen(fileName, "rb"); fptr = FOPEN(fileName.c_str(), "rb");
if (fptr == NULL) if (fptr == nullptr)
{ {
// didn't succeed ST_THROW_RT_ERROR("Error : Unable to open file for reading.");
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for reading.";
ST_THROW_RT_ERROR(msg.c_str());
} }
init(); init();
} }
WavInFile::WavInFile(FILE *file) WavInFile::WavInFile(FILE* file)
{ {
// Try to open the file for reading // Try to open the file for reading
fptr = file; fptr = file;
if (!file) if (!file)
{ {
// didn't succeed ST_THROW_RT_ERROR("Error : Unable to access input stream for reading");
string msg = "Error : Unable to access input stream for reading";
ST_THROW_RT_ERROR(msg.c_str());
} }
init(); init();
@ -211,19 +214,17 @@ void WavInFile::init()
// Read the file headers // Read the file headers
hdrsOk = readWavHeaders(); hdrsOk = readWavHeaders();
if (hdrsOk != 0) if (hdrsOk != 0)
{ {
// Something didn't match in the wav file headers
ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file"); ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file");
} }
// sanity check for format parameters // sanity check for format parameters
if ((header.format.channel_number < 1) || (header.format.channel_number > 9) || if ((header.format.channel_number < 1) || (header.format.channel_number > 9) ||
(header.format.sample_rate < 4000) || (header.format.sample_rate > 192000) || (header.format.sample_rate < 4000) || (header.format.sample_rate > 192000) ||
(header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) || (header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) ||
(header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32)) (header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32))
{ {
// Something didn't match in the wav file headers
ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters."); ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters.");
} }
@ -234,7 +235,7 @@ void WavInFile::init()
WavInFile::~WavInFile() WavInFile::~WavInFile()
{ {
if (fptr) fclose(fptr); if (fptr) fclose(fptr);
fptr = NULL; fptr = nullptr;
} }
@ -260,7 +261,7 @@ int WavInFile::checkCharTags() const
} }
int WavInFile::read(unsigned char *buffer, int maxElems) int WavInFile::read(unsigned char* buffer, int maxElems)
{ {
int numBytes; int numBytes;
uint afterDataRead; uint afterDataRead;
@ -274,7 +275,7 @@ int WavInFile::read(unsigned char *buffer, int maxElems)
numBytes = maxElems; numBytes = maxElems;
afterDataRead = dataRead + numBytes; afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len) if (afterDataRead > header.data.data_len)
{ {
// Don't read more samples than are marked available in header // Don't read more samples than are marked available in header
numBytes = (int)header.data.data_len - (int)dataRead; numBytes = (int)header.data.data_len - (int)dataRead;
@ -289,7 +290,7 @@ int WavInFile::read(unsigned char *buffer, int maxElems)
} }
int WavInFile::read(short *buffer, int maxElems) int WavInFile::read(short* buffer, int maxElems)
{ {
unsigned int afterDataRead; unsigned int afterDataRead;
int numBytes; int numBytes;
@ -298,62 +299,62 @@ int WavInFile::read(short *buffer, int maxElems)
assert(buffer); assert(buffer);
switch (header.format.bits_per_sample) switch (header.format.bits_per_sample)
{ {
case 8: case 8:
{ {
// 8 bit format // 8 bit format
unsigned char *temp = (unsigned char*)getConvBuffer(maxElems); unsigned char* temp = (unsigned char*)getConvBuffer(maxElems);
int i; int i;
numElems = read(temp, maxElems); numElems = read(temp, maxElems);
// convert from 8 to 16 bit // convert from 8 to 16 bit
for (i = 0; i < numElems; i ++) for (i = 0; i < numElems; i++)
{ {
buffer[i] = (short)(((short)temp[i] - 128) * 256); buffer[i] = (short)(((short)temp[i] - 128) * 256);
} }
break; break;
}
case 16:
{
// 16 bit format
assert(sizeof(short) == 2);
numBytes = maxElems * 2;
afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len)
{
// Don't read more samples than are marked available in header
numBytes = (int)header.data.data_len - (int)dataRead;
assert(numBytes >= 0);
} }
case 16: numBytes = (int)fread(buffer, 1, numBytes, fptr);
{ dataRead += numBytes;
// 16 bit format numElems = numBytes / 2;
assert(sizeof(short) == 2); // 16bit samples, swap byte order if necessary
_swap16Buffer((short*)buffer, numElems);
break;
}
numBytes = maxElems * 2; default:
afterDataRead = dataRead + numBytes; {
if (afterDataRead > header.data.data_len) stringstream ss;
{ ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";
// Don't read more samples than are marked available in header ss << (int)header.format.bits_per_sample;
numBytes = (int)header.data.data_len - (int)dataRead; ss << " bit sample format. ";
assert(numBytes >= 0); ST_THROW_RT_ERROR(ss.str().c_str());
} }
numBytes = (int)fread(buffer, 1, numBytes, fptr);
dataRead += numBytes;
numElems = numBytes / 2;
// 16bit samples, swap byte order if necessary
_swap16Buffer((short *)buffer, numElems);
break;
}
default:
{
stringstream ss;
ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";
ss << (int)header.format.bits_per_sample;
ss << " bit sample format. ";
ST_THROW_RT_ERROR(ss.str().c_str());
}
}; };
return numElems; return numElems;
} }
/// Read data in float format. Notice that when reading in float format /// Read data in float format. Notice that when reading in float format
/// 8/16/24/32 bit sample formats are supported /// 8/16/24/32 bit sample formats are supported
int WavInFile::read(float *buffer, int maxElems) int WavInFile::read(float* buffer, int maxElems)
{ {
unsigned int afterDataRead; unsigned int afterDataRead;
int numBytes; int numBytes;
@ -374,7 +375,7 @@ int WavInFile::read(float *buffer, int maxElems)
numBytes = maxElems * bytesPerSample; numBytes = maxElems * bytesPerSample;
afterDataRead = dataRead + numBytes; afterDataRead = dataRead + numBytes;
if (afterDataRead > header.data.data_len) if (afterDataRead > header.data.data_len)
{ {
// Don't read more samples than are marked available in header // Don't read more samples than are marked available in header
numBytes = (int)header.data.data_len - (int)dataRead; numBytes = (int)header.data.data_len - (int)dataRead;
@ -382,7 +383,7 @@ int WavInFile::read(float *buffer, int maxElems)
} }
// read raw data into temporary buffer // read raw data into temporary buffer
char *temp = (char*)getConvBuffer(numBytes); char* temp = (char*)getConvBuffer(numBytes);
numBytes = (int)fread(temp, 1, numBytes, fptr); numBytes = (int)fread(temp, 1, numBytes, fptr);
dataRead += numBytes; dataRead += numBytes;
@ -391,56 +392,56 @@ int WavInFile::read(float *buffer, int maxElems)
// swap byte ordert & convert to float, depending on sample format // swap byte ordert & convert to float, depending on sample format
switch (bytesPerSample) switch (bytesPerSample)
{ {
case 1: case 1:
{
unsigned char* temp2 = (unsigned char*)temp;
double conv = 1.0 / 128.0;
for (int i = 0; i < numElems; i++)
{ {
unsigned char *temp2 = (unsigned char*)temp; buffer[i] = (float)(temp2[i] * conv - 1.0);
double conv = 1.0 / 128.0;
for (int i = 0; i < numElems; i ++)
{
buffer[i] = (float)(temp2[i] * conv - 1.0);
}
break;
} }
break;
}
case 2: case 2:
{
short* temp2 = (short*)temp;
double conv = 1.0 / 32768.0;
for (int i = 0; i < numElems; i++)
{ {
short *temp2 = (short*)temp; short value = temp2[i];
double conv = 1.0 / 32768.0; buffer[i] = (float)(_swap16(value) * conv);
for (int i = 0; i < numElems; i ++)
{
short value = temp2[i];
buffer[i] = (float)(_swap16(value) * conv);
}
break;
} }
break;
}
case 3: case 3:
{
char* temp2 = (char*)temp;
double conv = 1.0 / 8388608.0;
for (int i = 0; i < numElems; i++)
{ {
char *temp2 = (char *)temp; int value = *((int*)temp2);
double conv = 1.0 / 8388608.0; value = _swap32(value) & 0x00ffffff; // take 24 bits
for (int i = 0; i < numElems; i ++) value |= (value & 0x00800000) ? 0xff000000 : 0; // extend minus sign bits
{ buffer[i] = (float)(value * conv);
int value = *((int*)temp2); temp2 += 3;
value = _swap32(value) & 0x00ffffff; // take 24 bits
value |= (value & 0x00800000) ? 0xff000000 : 0; // extend minus sign bits
buffer[i] = (float)(value * conv);
temp2 += 3;
}
break;
} }
break;
}
case 4: case 4:
{
int* temp2 = (int*)temp;
double conv = 1.0 / 2147483648.0;
assert(sizeof(int) == 4);
for (int i = 0; i < numElems; i++)
{ {
int *temp2 = (int *)temp; int value = temp2[i];
double conv = 1.0 / 2147483648.0; buffer[i] = (float)(_swap32(value) * conv);
assert(sizeof(int) == 4);
for (int i = 0; i < numElems; i ++)
{
int value = temp2[i];
buffer[i] = (float)(_swap32(value) * conv);
}
break;
} }
break;
}
} }
return numElems; return numElems;
@ -450,7 +451,7 @@ int WavInFile::read(float *buffer, int maxElems)
int WavInFile::eof() const int WavInFile::eof() const
{ {
// return true if all data has been read or file eof has reached // return true if all data has been read or file eof has reached
return (dataRead == header.data.data_len || feof(fptr)); return ((uint)dataRead == header.data.data_len || feof(fptr));
} }
@ -462,15 +463,15 @@ static int isAlpha(char c)
// test if all characters are between a white space ' ' and little 'z' // test if all characters are between a white space ' ' and little 'z'
static int isAlphaStr(const char *str) static int isAlphaStr(const char* str)
{ {
char c; char c;
c = str[0]; c = str[0];
while (c) while (c)
{ {
if (isAlpha(c) == 0) return 0; if (isAlpha(c) == 0) return 0;
str ++; str++;
c = str[0]; c = str[0];
} }
@ -483,7 +484,7 @@ int WavInFile::readRIFFBlock()
if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1; if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1;
// swap 32bit data byte order if necessary // swap 32bit data byte order if necessary
_swap32((int &)header.riff.package_len); _swap32((int&)header.riff.package_len);
// header.riff.riff_char should equal to 'RIFF'); // header.riff.riff_char should equal to 'RIFF');
if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1;
@ -500,7 +501,7 @@ int WavInFile::readHeaderBlock()
string sLabel; string sLabel;
// lead label string // lead label string
if (fread(label, 1, 4, fptr) !=4) return -1; if (fread(label, 1, 4, fptr) != 4) return -1;
label[4] = 0; label[4] = 0;
if (isAlphaStr(label) == 0) return -1; // not a valid label if (isAlphaStr(label) == 0) return -1; // not a valid label
@ -510,7 +511,7 @@ int WavInFile::readHeaderBlock()
{ {
int nLen, nDump; int nLen, nDump;
// 'fmt ' block // 'fmt ' block
memcpy(header.format.fmt, fmtStr, 4); memcpy(header.format.fmt, fmtStr, 4);
// read length of the format field // read length of the format field
@ -518,7 +519,7 @@ int WavInFile::readHeaderBlock()
// swap byte order if necessary // swap byte order if necessary
_swap32(nLen); _swap32(nLen);
// calculate how much length differs from expected // calculate how much length differs from expected
nDump = nLen - ((int)sizeof(header.format) - 8); nDump = nLen - ((int)sizeof(header.format) - 8);
// verify that header length isn't smaller than expected structure // verify that header length isn't smaller than expected structure
@ -536,12 +537,12 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1; if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary // swap byte order if necessary
_swap16((short &)header.format.fixed); // short int fixed; _swap16((short&)header.format.fixed); // short int fixed;
_swap16((short &)header.format.channel_number); // short int channel_number; _swap16((short&)header.format.channel_number); // short int channel_number;
_swap32((int &)header.format.sample_rate); // int sample_rate; _swap32((int&)header.format.sample_rate); // int sample_rate;
_swap32((int &)header.format.byte_rate); // int byte_rate; _swap32((int&)header.format.byte_rate); // int byte_rate;
_swap16((short &)header.format.byte_per_sample); // short int byte_per_sample; _swap16((short&)header.format.byte_per_sample); // short int byte_per_sample;
_swap16((short &)header.format.bits_per_sample); // short int bits_per_sample; _swap16((short&)header.format.bits_per_sample); // short int bits_per_sample;
// if format_len is larger than expected, skip the extra data // if format_len is larger than expected, skip the extra data
if (nDump > 0) if (nDump > 0)
@ -555,7 +556,7 @@ int WavInFile::readHeaderBlock()
{ {
int nLen, nDump; int nLen, nDump;
// 'fact' block // 'fact' block
memcpy(header.fact.fact_field, factStr, 4); memcpy(header.fact.fact_field, factStr, 4);
// read length of the fact field // read length of the fact field
@ -581,7 +582,7 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.fact.fact_sample_len), nLen, 1, fptr) != 1) return -1; if (fread(&(header.fact.fact_sample_len), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary // swap byte order if necessary
_swap32((int &)header.fact.fact_sample_len); // int sample_length; _swap32((int&)header.fact.fact_sample_len); // int sample_length;
// if fact_len is larger than expected, skip the extra data // if fact_len is larger than expected, skip the extra data
if (nDump > 0) if (nDump > 0)
@ -598,7 +599,7 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1; if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1;
// swap byte order if necessary // swap byte order if necessary
_swap32((int &)header.data.data_len); _swap32((int&)header.data.data_len);
return 1; return 1;
} }
@ -611,7 +612,7 @@ int WavInFile::readHeaderBlock()
// read length // read length
if (fread(&len, sizeof(len), 1, fptr) != 1) return -1; if (fread(&len, sizeof(len), 1, fptr) != 1) return -1;
// scan through the block // scan through the block
for (i = 0; i < len; i ++) for (i = 0; i < len; i++)
{ {
if (fread(&temp, 1, 1, fptr) != 1) return -1; if (fread(&temp, 1, 1, fptr) != 1) return -1;
if (feof(fptr)) return -1; // unexpected eof if (feof(fptr)) return -1; // unexpected eof
@ -703,17 +704,13 @@ uint WavInFile::getElapsedMS() const
// Class WavOutFile // Class WavOutFile
// //
WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) WavOutFile::WavOutFile(const STRING& fileName, int sampleRate, int bits, int channels)
{ {
bytesWritten = 0; bytesWritten = 0;
fptr = fopen(fileName, "wb"); fptr = FOPEN(fileName.c_str(), "wb");
if (fptr == NULL) if (fptr == nullptr)
{ {
string msg = "Error : Unable to open file \""; ST_THROW_RT_ERROR("Error : Unable to open file for writing.");
msg += fileName;
msg += "\" for writing.";
//pmsg = msg.c_str;
ST_THROW_RT_ERROR(msg.c_str());
} }
fillInHeader(sampleRate, bits, channels); fillInHeader(sampleRate, bits, channels);
@ -721,14 +718,13 @@ WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int chann
} }
WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels) WavOutFile::WavOutFile(FILE* file, int sampleRate, int bits, int channels)
{ {
bytesWritten = 0; bytesWritten = 0;
fptr = file; fptr = file;
if (fptr == NULL) if (fptr == nullptr)
{ {
string msg = "Error : Unable to access output file stream."; ST_THROW_RT_ERROR("Error : Unable to access output file stream.");
ST_THROW_RT_ERROR(msg.c_str());
} }
fillInHeader(sampleRate, bits, channels); fillInHeader(sampleRate, bits, channels);
@ -740,7 +736,7 @@ WavOutFile::~WavOutFile()
{ {
finishHeader(); finishHeader();
if (fptr) fclose(fptr); if (fptr) fclose(fptr);
fptr = NULL; fptr = nullptr;
} }
@ -788,8 +784,8 @@ void WavOutFile::finishHeader()
// supplement the file length into the header structure // supplement the file length into the header structure
header.riff.package_len = bytesWritten + sizeof(WavHeader) - sizeof(WavRiff) + 4; header.riff.package_len = bytesWritten + sizeof(WavHeader) - sizeof(WavRiff) + 4;
header.data.data_len = bytesWritten; header.data.data_len = bytesWritten;
header.fact.fact_sample_len = bytesWritten / header.format.byte_per_sample; header.fact.fact_sample_len = bytesWritten / header.format.byte_per_sample;
writeHeader(); writeHeader();
} }
@ -801,18 +797,18 @@ void WavOutFile::writeHeader()
// swap byte order if necessary // swap byte order if necessary
hdrTemp = header; hdrTemp = header;
_swap32((int &)hdrTemp.riff.package_len); _swap32((int&)hdrTemp.riff.package_len);
_swap32((int &)hdrTemp.format.format_len); _swap32((int&)hdrTemp.format.format_len);
_swap16((short &)hdrTemp.format.fixed); _swap16((short&)hdrTemp.format.fixed);
_swap16((short &)hdrTemp.format.channel_number); _swap16((short&)hdrTemp.format.channel_number);
_swap32((int &)hdrTemp.format.sample_rate); _swap32((int&)hdrTemp.format.sample_rate);
_swap32((int &)hdrTemp.format.byte_rate); _swap32((int&)hdrTemp.format.byte_rate);
_swap16((short &)hdrTemp.format.byte_per_sample); _swap16((short&)hdrTemp.format.byte_per_sample);
_swap16((short &)hdrTemp.format.bits_per_sample); _swap16((short&)hdrTemp.format.bits_per_sample);
_swap32((int &)hdrTemp.data.data_len); _swap32((int&)hdrTemp.data.data_len);
_swap32((int &)hdrTemp.fact.fact_len); _swap32((int&)hdrTemp.fact.fact_len);
_swap32((int &)hdrTemp.fact.fact_sample_len); _swap32((int&)hdrTemp.fact.fact_sample_len);
// write the supplemented header in the beginning of the file // write the supplemented header in the beginning of the file
fseek(fptr, 0, SEEK_SET); fseek(fptr, 0, SEEK_SET);
res = (int)fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr); res = (int)fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr);
@ -826,7 +822,7 @@ void WavOutFile::writeHeader()
} }
void WavOutFile::write(const unsigned char *buffer, int numElems) void WavOutFile::write(const unsigned char* buffer, int numElems)
{ {
int res; int res;
@ -837,7 +833,7 @@ void WavOutFile::write(const unsigned char *buffer, int numElems)
assert(sizeof(char) == 1); assert(sizeof(char) == 1);
res = (int)fwrite(buffer, 1, numElems, fptr); res = (int)fwrite(buffer, 1, numElems, fptr);
if (res != numElems) if (res != numElems)
{ {
ST_THROW_RT_ERROR("Error while writing to a wav file."); ST_THROW_RT_ERROR("Error while writing to a wav file.");
} }
@ -846,7 +842,7 @@ void WavOutFile::write(const unsigned char *buffer, int numElems)
} }
void WavOutFile::write(const short *buffer, int numElems) void WavOutFile::write(const short* buffer, int numElems)
{ {
int res; int res;
@ -855,47 +851,47 @@ void WavOutFile::write(const short *buffer, int numElems)
switch (header.format.bits_per_sample) switch (header.format.bits_per_sample)
{ {
case 8: case 8:
{
int i;
unsigned char* temp = (unsigned char*)getConvBuffer(numElems);
// convert from 16bit format to 8bit format
for (i = 0; i < numElems; i++)
{ {
int i; temp[i] = (unsigned char)(buffer[i] / 256 + 128);
unsigned char *temp = (unsigned char *)getConvBuffer(numElems);
// convert from 16bit format to 8bit format
for (i = 0; i < numElems; i ++)
{
temp[i] = (unsigned char)(buffer[i] / 256 + 128);
}
// write in 8bit format
write(temp, numElems);
break;
} }
// write in 8bit format
write(temp, numElems);
break;
}
case 16: case 16:
{
// 16bit format
// use temp buffer to swap byte order if necessary
short* pTemp = (short*)getConvBuffer(numElems * sizeof(short));
memcpy(pTemp, buffer, (size_t)numElems * 2L);
_swap16Buffer(pTemp, numElems);
res = (int)fwrite(pTemp, 2, numElems, fptr);
if (res != numElems)
{ {
// 16bit format ST_THROW_RT_ERROR("Error while writing to a wav file.");
// use temp buffer to swap byte order if necessary
short *pTemp = (short *)getConvBuffer(numElems * sizeof(short));
memcpy(pTemp, buffer, numElems * 2);
_swap16Buffer(pTemp, numElems);
res = (int)fwrite(pTemp, 2, numElems, fptr);
if (res != numElems)
{
ST_THROW_RT_ERROR("Error while writing to a wav file.");
}
bytesWritten += 2 * numElems;
break;
} }
bytesWritten += 2 * numElems;
break;
}
default: default:
{ {
stringstream ss; stringstream ss;
ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with "; ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";
ss << (int)header.format.bits_per_sample; ss << (int)header.format.bits_per_sample;
ss << " bit sample format. "; ss << " bit sample format. ";
ST_THROW_RT_ERROR(ss.str().c_str()); ST_THROW_RT_ERROR(ss.str().c_str());
} }
} }
} }
@ -903,10 +899,10 @@ void WavOutFile::write(const short *buffer, int numElems)
/// Convert from float to integer and saturate /// Convert from float to integer and saturate
inline int saturate(float fvalue, float minval, float maxval) inline int saturate(float fvalue, float minval, float maxval)
{ {
if (fvalue > maxval) if (fvalue > maxval)
{ {
fvalue = maxval; fvalue = maxval;
} }
else if (fvalue < minval) else if (fvalue < minval)
{ {
fvalue = minval; fvalue = minval;
@ -915,7 +911,7 @@ inline int saturate(float fvalue, float minval, float maxval)
} }
void WavOutFile::write(const float *buffer, int numElems) void WavOutFile::write(const float* buffer, int numElems)
{ {
int numBytes; int numBytes;
int bytesPerSample; int bytesPerSample;
@ -924,63 +920,65 @@ void WavOutFile::write(const float *buffer, int numElems)
bytesPerSample = header.format.bits_per_sample / 8; bytesPerSample = header.format.bits_per_sample / 8;
numBytes = numElems * bytesPerSample; numBytes = numElems * bytesPerSample;
void *temp = getConvBuffer(numBytes + 7); // round bit up to avoid buffer overrun with 24bit-value assignment void* temp = getConvBuffer(numBytes + 7); // round bit up to avoid buffer overrun with 24bit-value assignment
switch (bytesPerSample) switch (bytesPerSample)
{ {
case 1: case 1:
{
unsigned char* temp2 = (unsigned char*)temp;
for (int i = 0; i < numElems; i++)
{ {
unsigned char *temp2 = (unsigned char *)temp; temp2[i] = (unsigned char)saturate(buffer[i] * 128.0f + 128.0f, 0.0f, 255.0f);
for (int i = 0; i < numElems; i ++)
{
temp2[i] = (unsigned char)saturate(buffer[i] * 128.0f + 128.0f, 0.0f, 255.0f);
}
break;
} }
break;
}
case 2: case 2:
{
short* temp2 = (short*)temp;
for (int i = 0; i < numElems; i++)
{ {
short *temp2 = (short *)temp; short value = (short)saturate(buffer[i] * 32768.0f, -32768.0f, 32767.0f);
for (int i = 0; i < numElems; i ++) temp2[i] = _swap16(value);
{
short value = (short)saturate(buffer[i] * 32768.0f, -32768.0f, 32767.0f);
temp2[i] = _swap16(value);
}
break;
} }
break;
}
case 3: case 3:
{
char* temp2 = (char*)temp;
for (int i = 0; i < numElems; i++)
{ {
char *temp2 = (char *)temp; int value = saturate(buffer[i] * 8388608.0f, -8388608.0f, 8388607.0f);
for (int i = 0; i < numElems; i ++) *((int*)temp2) = _swap32(value);
{ temp2 += 3;
int value = saturate(buffer[i] * 8388608.0f, -8388608.0f, 8388607.0f);
*((int*)temp2) = _swap32(value);
temp2 += 3;
}
break;
} }
break;
}
case 4: case 4:
{
int* temp2 = (int*)temp;
for (int i = 0; i < numElems; i++)
{ {
int *temp2 = (int *)temp; int value = saturate(buffer[i] * 2147483648.0f, -2147483648.0f, 2147483647.0f);
for (int i = 0; i < numElems; i ++) temp2[i] = _swap32(value);
{
int value = saturate(buffer[i] * 2147483648.0f, -2147483648.0f, 2147483647.0f);
temp2[i] = _swap32(value);
}
break;
} }
break;
}
default: default:
assert(false); assert(false);
} }
int res = (int)fwrite(temp, 1, numBytes, fptr); int res = (int)fwrite(temp, 1, numBytes, fptr);
if (res != numBytes) if (res != numBytes)
{ {
ST_THROW_RT_ERROR("Error while writing to a wav file."); ST_THROW_RT_ERROR("Error while writing to a wav file.");
} }
bytesWritten += numBytes; bytesWritten += numBytes;
} }
}

View File

@ -4,10 +4,10 @@
/// ///
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly /// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
/// parse the WAV files with such processors. /// parse the WAV files with such processors.
/// ///
/// Admittingly, more complete WAV reader routines may exist in public domain, but /// Admittingly, more complete WAV reader routines may exist in public domain, but
/// the reason for 'yet another' one is that those generic WAV reader libraries are /// the reason for 'yet another' one is that those generic WAV reader libraries are
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. /// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
/// something that's not already larger than rest of the SoundTouch/SoundStretch program... /// something that's not already larger than rest of the SoundTouch/SoundStretch program...
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -40,15 +40,20 @@
#ifndef WAVFILE_H #ifndef WAVFILE_H
#define WAVFILE_H #define WAVFILE_H
#include <stdio.h> #include <cstdio>
#include <string>
#include "SS_CharTypes.h"
namespace soundstretch
{
#ifndef uint #ifndef uint
typedef unsigned int uint; typedef unsigned int uint;
#endif #endif
/// WAV audio file 'riff' section header /// WAV audio file 'riff' section header
typedef struct typedef struct
{ {
char riff_char[4]; char riff_char[4];
uint package_len; uint package_len;
@ -56,7 +61,7 @@ typedef struct
} WavRiff; } WavRiff;
/// WAV audio file 'format' section header /// WAV audio file 'format' section header
typedef struct typedef struct
{ {
char fmt[4]; char fmt[4];
unsigned int format_len; unsigned int format_len;
@ -69,7 +74,7 @@ typedef struct
} WavFormat; } WavFormat;
/// WAV audio file 'fact' section header /// WAV audio file 'fact' section header
typedef struct typedef struct
{ {
char fact_field[4]; char fact_field[4];
uint fact_len; uint fact_len;
@ -77,7 +82,7 @@ typedef struct
} WavFact; } WavFact;
/// WAV audio file 'data' section header /// WAV audio file 'data' section header
typedef struct typedef struct
{ {
char data_field[4]; char data_field[4];
uint data_len; uint data_len;
@ -85,7 +90,7 @@ typedef struct
/// WAV audio file header /// WAV audio file header
typedef struct typedef struct
{ {
WavRiff riff; WavRiff riff;
WavFormat format; WavFormat format;
@ -118,9 +123,6 @@ private:
/// File pointer. /// File pointer.
FILE *fptr; FILE *fptr;
/// Position within the audio stream
long position;
/// Counter of how many bytes of sample data have been read from the file. /// Counter of how many bytes of sample data have been read from the file.
long dataRead; long dataRead;
@ -148,7 +150,7 @@ private:
public: public:
/// Constructor: Opens the given WAV file. If the file can't be opened, /// Constructor: Opens the given WAV file. If the file can't be opened,
/// throws 'runtime_error' exception. /// throws 'runtime_error' exception.
WavInFile(const char *filename); WavInFile(const STRING& filename);
WavInFile(FILE *file); WavInFile(FILE *file);
@ -164,7 +166,7 @@ public:
/// Get number of bits per sample, i.e. 8 or 16. /// Get number of bits per sample, i.e. 8 or 16.
uint getNumBits() const; uint getNumBits() const;
/// Get sample data size in bytes. Ahem, this should return same information as /// Get sample data size in bytes. Ahem, this should return same information as
/// 'getBytesPerSample'... /// 'getBytesPerSample'...
uint getDataSizeInBytes() const; uint getDataSizeInBytes() const;
@ -173,7 +175,7 @@ public:
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample) /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
uint getBytesPerSample() const; uint getBytesPerSample() const;
/// Get number of audio channels in the file (1=mono, 2=stereo) /// Get number of audio channels in the file (1=mono, 2=stereo)
uint getNumChannels() const; uint getNumChannels() const;
@ -186,14 +188,14 @@ public:
uint getElapsedMS() const; uint getElapsedMS() const;
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples. /// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
/// Reads given number of elements from the file or if end-of-file reached, as many /// Reads given number of elements from the file or if end-of-file reached, as many
/// elements as are left in the file. /// elements as are left in the file.
/// ///
/// \return Number of 8-bit integers read from the file. /// \return Number of 8-bit integers read from the file.
int read(unsigned char *buffer, int maxElems); int read(unsigned char *buffer, int maxElems);
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
/// of elements from the file or if end-of-file reached, as many elements as are /// of elements from the file or if end-of-file reached, as many elements as are
/// left in the file. /// left in the file.
/// ///
/// \return Number of 16-bit integers read from the file. /// \return Number of 16-bit integers read from the file.
@ -201,7 +203,7 @@ public:
int maxElems ///< Size of 'buffer' array (number of array elements). int maxElems ///< Size of 'buffer' array (number of array elements).
); );
/// Reads audio samples from the WAV file to floating point format, converting /// Reads audio samples from the WAV file to floating point format, converting
/// sample values to range [-1,1[. Reads given number of elements from the file /// sample values to range [-1,1[. Reads given number of elements from the file
/// or if end-of-file reached, as many elements as are left in the file. /// or if end-of-file reached, as many elements as are left in the file.
/// Notice that reading in float format supports 8/16/24/32bit sample formats. /// Notice that reading in float format supports 8/16/24/32bit sample formats.
@ -242,9 +244,9 @@ private:
void writeHeader(); void writeHeader();
public: public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails. /// if file creation fails.
WavOutFile(const char *fileName, ///< Filename WavOutFile(const STRING& fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc) int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits) int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo) int channels ///< Number of channels (1=mono, 2=stereo)
@ -255,7 +257,7 @@ public:
/// Destructor: Finalizes & closes the WAV file. /// Destructor: Finalizes & closes the WAV file.
~WavOutFile(); ~WavOutFile();
/// Write data to WAV file. This function works only with 8bit samples. /// Write data to WAV file. This function works only with 8bit samples.
/// Throws a 'runtime_error' exception if writing to file fails. /// Throws a 'runtime_error' exception if writing to file fails.
void write(const unsigned char *buffer, ///< Pointer to sample data buffer. void write(const unsigned char *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file. int numElems ///< How many array items are to be written to file.
@ -274,4 +276,6 @@ public:
); );
}; };
}
#endif #endif

View File

@ -1,9 +1,9 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and /// FIR low-pass (anti-alias) filter with filter coefficient design routine and
/// MMX optimization. /// MMX optimization.
/// ///
/// Anti-alias filter is used to prevent folding of high frequencies when /// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation. /// transposing the sample rate with interpolation.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -54,7 +54,7 @@ using namespace soundtouch;
static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)
{ {
FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");
if (fptr == NULL) return; if (fptr == nullptr) return;
for (int i = 0; i < len; i ++) for (int i = 0; i < len; i ++)
{ {
@ -128,16 +128,16 @@ void AAFilter::calculateCoeffs()
tempCoeff = TWOPI / (double)length; tempCoeff = TWOPI / (double)length;
sum = 0; sum = 0;
for (i = 0; i < length; i ++) for (i = 0; i < length; i ++)
{ {
cntTemp = (double)i - (double)(length / 2); cntTemp = (double)i - (double)(length / 2);
temp = cntTemp * wc; temp = cntTemp * wc;
if (temp != 0) if (temp != 0)
{ {
h = sin(temp) / temp; // sinc function h = sin(temp) / temp; // sinc function
} }
else else
{ {
h = 1.0; h = 1.0;
} }
@ -146,7 +146,7 @@ void AAFilter::calculateCoeffs()
temp = w * h; temp = w * h;
work[i] = temp; work[i] = temp;
// calc net sum of coefficients // calc net sum of coefficients
sum += temp; sum += temp;
} }
@ -162,7 +162,7 @@ void AAFilter::calculateCoeffs()
// divided by 16384 // divided by 16384
scaleCoeff = 16384.0f / sum; scaleCoeff = 16384.0f / sum;
for (i = 0; i < length; i ++) for (i = 0; i < length; i ++)
{ {
temp = work[i] * scaleCoeff; temp = work[i] * scaleCoeff;
// scale & round to nearest integer // scale & round to nearest integer
@ -182,8 +182,8 @@ void AAFilter::calculateCoeffs()
} }
// Applies the filter to the given sequence of samples. // Applies the filter to the given sequence of samples.
// Note : The amount of outputted samples is by value of 'filter length' // Note : The amount of outputted samples is by value of 'filter length'
// smaller than the amount of input samples. // smaller than the amount of input samples.
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
{ {
@ -192,8 +192,8 @@ uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples
/// Applies the filter to the given src & dest pipes, so that processed amount of /// Applies the filter to the given src & dest pipes, so that processed amount of
/// samples get removed from src, and produced amount added to dest /// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length' /// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
{ {

View File

@ -1,10 +1,10 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method /// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks. /// with several performance-increasing tweaks.
/// ///
/// Anti-alias filter is used to prevent folding of high frequencies when /// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation. /// transposing the sample rate with interpolation.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -61,8 +61,8 @@ public:
~AAFilter(); ~AAFilter();
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
/// frequency (nyquist frequency = 0.5). The filter will cut off the /// frequency (nyquist frequency = 0.5). The filter will cut off the
/// frequencies than that. /// frequencies than that.
void setCutoffFreq(double newCutoffFreq); void setCutoffFreq(double newCutoffFreq);
@ -71,19 +71,19 @@ public:
uint getLength() const; uint getLength() const;
/// Applies the filter to the given sequence of samples. /// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter length' /// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
uint evaluate(SAMPLETYPE *dest, uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples, uint numSamples,
uint numChannels) const; uint numChannels) const;
/// Applies the filter to the given src & dest pipes, so that processed amount of /// Applies the filter to the given src & dest pipes, so that processed amount of
/// samples get removed from src, and produced amount added to dest /// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length' /// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
uint evaluate(FIFOSampleBuffer &dest, uint evaluate(FIFOSampleBuffer &dest,
FIFOSampleBuffer &src) const; FIFOSampleBuffer &src) const;
}; };

View File

@ -14,10 +14,10 @@
/// taking absolute value that's smoothed by sliding average. Signal levels that /// 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 /// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there. /// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term /// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal. /// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is /// - 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 /// 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. /// function, calculates it's precise location and converts this reading to bpm's.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -76,8 +76,8 @@ static const int XCORR_UPDATE_SEQUENCE = (int)(TARGET_SRATE / 5);
static const int MOVING_AVERAGE_N = 15; static const int MOVING_AVERAGE_N = 15;
/// XCorr decay time constant, decay to half in 30 seconds /// XCorr decay time constant, decay to half in 30 seconds
/// If it's desired to have the system adapt quicker to beat rate /// If it's desired to have the system adapt quicker to beat rate
/// changes within a continuing music stream, then the /// changes within a continuing music stream, then the
/// 'xcorr_decay_time_constant' value can be reduced, yet that /// 'xcorr_decay_time_constant' value can be reduced, yet that
/// can increase possibility of glitches in bpm detection. /// can increase possibility of glitches in bpm detection.
static const double XCORR_DECAY_TIME_CONSTANT = 30.0; static const double XCORR_DECAY_TIME_CONSTANT = 30.0;
@ -233,16 +233,16 @@ BPMDetect::~BPMDetect()
} }
/// convert to mono, low-pass filter & decimate to about 500 Hz. /// convert to mono, low-pass filter & decimate to about 500 Hz.
/// return number of outputted samples. /// return number of outputted samples.
/// ///
/// Decimation is used to remove the unnecessary frequencies and thus to reduce /// Decimation is used to remove the unnecessary frequencies and thus to reduce
/// the amount of data needed to be processed as calculating autocorrelation /// the amount of data needed to be processed as calculating autocorrelation
/// function is a very-very heavy operation. /// function is a very-very heavy operation.
/// ///
/// Anti-alias filtering is done simply by averaging the samples. This is really a /// 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 /// 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 /// (it'd also be difficult to design a high-quality filter with steep cut-off at very
/// narrow band) /// narrow band)
int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
{ {
@ -252,7 +252,7 @@ int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
assert(channels > 0); assert(channels > 0);
assert(decimateBy > 0); assert(decimateBy > 0);
outcount = 0; outcount = 0;
for (count = 0; count < numsamples; count ++) for (count = 0; count < numsamples; count ++)
{ {
int j; int j;
@ -264,7 +264,7 @@ int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
src += j; src += j;
decimateCount ++; decimateCount ++;
if (decimateCount >= decimateBy) if (decimateCount >= decimateBy)
{ {
// Store every Nth sample only // Store every Nth sample only
out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels)); out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels));
@ -272,11 +272,11 @@ int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
decimateCount = 0; decimateCount = 0;
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
// check ranges for sure (shouldn't actually be necessary) // check ranges for sure (shouldn't actually be necessary)
if (out > 32767) if (out > 32767)
{ {
out = 32767; out = 32767;
} }
else if (out < -32768) else if (out < -32768)
{ {
out = -32768; out = -32768;
} }
@ -294,7 +294,7 @@ void BPMDetect::updateXCorr(int process_samples)
{ {
int offs; int offs;
SAMPLETYPE *pBuffer; SAMPLETYPE *pBuffer;
assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
assert(process_samples == XCORR_UPDATE_SEQUENCE); assert(process_samples == XCORR_UPDATE_SEQUENCE);
@ -311,13 +311,13 @@ void BPMDetect::updateXCorr(int process_samples)
} }
#pragma omp parallel for #pragma omp parallel for
for (offs = windowStart; offs < windowLen; offs ++) for (offs = windowStart; offs < windowLen; offs ++)
{ {
float sum; float sum;
int i; int i;
sum = 0; sum = 0;
for (i = 0; i < process_samples; i ++) for (i = 0; i < process_samples; i ++)
{ {
sum += tmp[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary sum += tmp[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
} }
@ -376,8 +376,6 @@ void BPMDetect::updateBeatPos(int process_samples)
// detect beats // detect beats
for (int i = 0; i < skipstep; i++) for (int i = 0; i < skipstep; i++)
{ {
LONG_SAMPLETYPE max = 0;
float sum = beatcorr_ringbuff[beatcorr_ringbuffpos]; float sum = beatcorr_ringbuff[beatcorr_ringbuffpos];
sum -= beat_lpf.update(sum); sum -= beat_lpf.update(sum);
@ -433,7 +431,7 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
// when the buffer has enough samples for processing... // when the buffer has enough samples for processing...
int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE); int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE);
while ((int)buffer->numSamples() >= req) while ((int)buffer->numSamples() >= req)
{ {
// ... update autocorrelations... // ... update autocorrelations...
updateXCorr(XCORR_UPDATE_SEQUENCE); updateXCorr(XCORR_UPDATE_SEQUENCE);
@ -504,7 +502,7 @@ void MAFilter(float *dest, const float *source, int start, int end, int N)
double sum = 0; double sum = 0;
for (int j = i1; j < i2; j ++) for (int j = i1; j < i2; j ++)
{ {
sum += source[j]; sum += source[j];
} }
dest[i] = (float)(sum / (i2 - i1)); dest[i] = (float)(sum / (i2 - i1));
@ -550,19 +548,19 @@ float BPMDetect::getBpm()
} }
/// Get beat position arrays. Note: The array includes also really low beat detection values /// Get beat position arrays. Note: The array includes also really low beat detection values
/// in absence of clear strong beats. Consumer may wish to filter low values away. /// in absence of clear strong beats. Consumer may wish to filter low values away.
/// - "pos" receive array of beat positions /// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths /// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array. /// - max_num indicates max.size of "pos" and "values" array.
/// ///
/// You can query a suitable array sized by calling this with NULL in "pos" & "values". /// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
/// ///
/// \return number of beats in the arrays. /// \return number of beats in the arrays.
int BPMDetect::getBeats(float *pos, float *values, int max_num) int BPMDetect::getBeats(float *pos, float *values, int max_num)
{ {
int num = (int)beats.size(); int num = (int)beats.size();
if ((!pos) || (!values)) return num; // pos or values NULL, return just size if ((!pos) || (!values)) return num; // pos or values nullptr, return just size
for (int i = 0; (i < num) && (i < max_num); i++) for (int i = 0; (i < num) && (i < max_num); i++)
{ {

View File

@ -1,12 +1,12 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// A buffer class for temporarily storaging sound samples, operates as a /// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe. /// first-in-first-out pipe.
/// ///
/// Samples are added to the end of the sample buffer with the 'putSamples' /// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling /// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the /// the 'receiveSamples' function. The class automatically removes the
/// outputted samples from the buffer, as well as grows the buffer size /// outputted samples from the buffer, as well as grows the buffer size
/// whenever necessary. /// whenever necessary.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -50,12 +50,12 @@ FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
{ {
assert(numChannels > 0); assert(numChannels > 0);
sizeInBytes = 0; // reasonable initial value sizeInBytes = 0; // reasonable initial value
buffer = NULL; buffer = nullptr;
bufferUnaligned = NULL; bufferUnaligned = nullptr;
samplesInBuffer = 0; samplesInBuffer = 0;
bufferPos = 0; bufferPos = 0;
channels = (uint)numChannels; channels = (uint)numChannels;
ensureCapacity(32); // allocate initial capacity ensureCapacity(32); // allocate initial capacity
} }
@ -63,8 +63,8 @@ FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
FIFOSampleBuffer::~FIFOSampleBuffer() FIFOSampleBuffer::~FIFOSampleBuffer()
{ {
delete[] bufferUnaligned; delete[] bufferUnaligned;
bufferUnaligned = NULL; bufferUnaligned = nullptr;
buffer = NULL; buffer = nullptr;
} }
@ -82,11 +82,11 @@ void FIFOSampleBuffer::setChannels(int numChannels)
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and // if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
// zeroes this pointer by copying samples from the 'bufferPos' pointer // zeroes this pointer by copying samples from the 'bufferPos' pointer
// location on to the beginning of the buffer. // location on to the beginning of the buffer.
void FIFOSampleBuffer::rewind() void FIFOSampleBuffer::rewind()
{ {
if (buffer && bufferPos) if (buffer && bufferPos)
{ {
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
bufferPos = 0; bufferPos = 0;
@ -94,7 +94,7 @@ void FIFOSampleBuffer::rewind()
} }
// Adds 'numSamples' pcs of samples from the 'samples' memory position to // Adds 'numSamples' pcs of samples from the 'samples' memory position to
// the sample buffer. // the sample buffer.
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
{ {
@ -107,7 +107,7 @@ void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
// samples. // samples.
// //
// This function is used to update the number of samples in the sample buffer // This function is used to update the number of samples in the sample buffer
// when accessing the buffer directly with 'ptrEnd' function. Please be // when accessing the buffer directly with 'ptrEnd' function. Please be
// careful though! // careful though!
void FIFOSampleBuffer::putSamples(uint nSamples) void FIFOSampleBuffer::putSamples(uint nSamples)
{ {
@ -119,31 +119,31 @@ void FIFOSampleBuffer::putSamples(uint nSamples)
} }
// Returns a pointer to the end of the used part of the sample buffer (i.e. // Returns a pointer to the end of the used part of the sample buffer (i.e.
// where the new samples are to be inserted). This function may be used for // where the new samples are to be inserted). This function may be used for
// inserting new samples into the sample buffer directly. Please be careful! // inserting new samples into the sample buffer directly. Please be careful!
// //
// Parameter 'slackCapacity' tells the function how much free capacity (in // Parameter 'slackCapacity' tells the function how much free capacity (in
// terms of samples) there _at least_ should be, in order to the caller to // terms of samples) there _at least_ should be, in order to the caller to
// successfully insert all the required samples to the buffer. When necessary, // successfully insert all the required samples to the buffer. When necessary,
// the function grows the buffer size to comply with this requirement. // the function grows the buffer size to comply with this requirement.
// //
// When using this function as means for inserting new samples, also remember // When using this function as means for inserting new samples, also remember
// to increase the sample count afterwards, by calling the // to increase the sample count afterwards, by calling the
// 'putSamples(numSamples)' function. // 'putSamples(numSamples)' function.
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
{ {
ensureCapacity(samplesInBuffer + slackCapacity); ensureCapacity(samplesInBuffer + slackCapacity);
return buffer + samplesInBuffer * channels; return buffer + samplesInBuffer * channels;
} }
// Returns a pointer to the beginning of the currently non-outputted samples. // Returns a pointer to the beginning of the currently non-outputted samples.
// This function is provided for accessing the output samples directly. // This function is provided for accessing the output samples directly.
// Please be careful! // Please be careful!
// //
// When using this function to output samples, also remember to 'remove' the // When using this function to output samples, also remember to 'remove' the
// outputted samples from the buffer by calling the // outputted samples from the buffer by calling the
// 'receiveSamples(numSamples)' function // 'receiveSamples(numSamples)' function
SAMPLETYPE *FIFOSampleBuffer::ptrBegin() SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
{ {
@ -160,13 +160,13 @@ void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
{ {
SAMPLETYPE *tempUnaligned, *temp; SAMPLETYPE *tempUnaligned, *temp;
if (capacityRequirement > getCapacity()) if (capacityRequirement > getCapacity())
{ {
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary) // enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
assert(sizeInBytes % 2 == 0); assert(sizeInBytes % 2 == 0);
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
if (tempUnaligned == NULL) if (tempUnaligned == nullptr)
{ {
ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
} }
@ -180,8 +180,8 @@ void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
buffer = temp; buffer = temp;
bufferUnaligned = tempUnaligned; bufferUnaligned = tempUnaligned;
bufferPos = 0; bufferPos = 0;
} }
else else
{ {
// simply rewind the buffer (if necessary) // simply rewind the buffer (if necessary)
rewind(); rewind();

View File

@ -1,13 +1,13 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// General FIR digital filter routines with MMX optimization. /// General FIR digital filter routines with MMX optimization.
/// ///
/// Notes : 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 /// This source file contains OpenMP optimizations that allow speeding up the
/// corss-correlation algorithm by executing it in several threads / CPU cores /// corss-correlation algorithm by executing it in several threads / CPU cores
/// in parallel. See the following article link for more detailed discussion /// in parallel. See the following article link for more detailed discussion
/// about SoundTouch OpenMP optimizations: /// about SoundTouch OpenMP optimizations:
/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices /// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
/// ///
@ -59,8 +59,8 @@ FIRFilter::FIRFilter()
resultDivider = 0; resultDivider = 0;
length = 0; length = 0;
lengthDiv8 = 0; lengthDiv8 = 0;
filterCoeffs = NULL; filterCoeffs = nullptr;
filterCoeffsStereo = NULL; filterCoeffsStereo = nullptr;
} }
@ -75,20 +75,16 @@ FIRFilter::~FIRFilter()
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{ {
int j, end; int j, end;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
// hint compiler autovectorization that loop length is divisible by 8 // hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8; uint ilength = length & -8;
assert((length != 0) && (length == ilength) && (src != NULL) && (dest != NULL) && (filterCoeffs != NULL)); assert((length != 0) && (length == ilength) && (src != nullptr) && (dest != nullptr) && (filterCoeffs != nullptr));
assert(numSamples > ilength);
end = 2 * (numSamples - ilength); end = 2 * (numSamples - ilength);
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < end; j += 2) for (j = 0; j < end; j += 2)
{ {
const SAMPLETYPE *ptr; const SAMPLETYPE *ptr;
LONG_SAMPLETYPE suml, sumr; LONG_SAMPLETYPE suml, sumr;
@ -96,7 +92,7 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
suml = sumr = 0; suml = sumr = 0;
ptr = src + j; ptr = src + j;
for (int i = 0; i < ilength; i ++) for (uint i = 0; i < ilength; i ++)
{ {
suml += ptr[2 * i] * filterCoeffsStereo[2 * i]; suml += ptr[2 * i] * filterCoeffsStereo[2 * i];
sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1]; sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1];
@ -121,11 +117,6 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{ {
int j, end; int j, end;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
// hint compiler autovectorization that loop length is divisible by 8 // hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8; int ilength = length & -8;
@ -160,16 +151,10 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin
{ {
int j, end; int j, end;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0); assert(length != 0);
assert(src != NULL); assert(src != nullptr);
assert(dest != NULL); assert(dest != nullptr);
assert(filterCoeffs != NULL); assert(filterCoeffs != nullptr);
assert(numChannels < 16); assert(numChannels < 16);
// hint compiler autovectorization that loop length is divisible by 8 // hint compiler autovectorization that loop length is divisible by 8
@ -201,7 +186,7 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin
ptr ++; ptr ++;
} }
} }
for (c = 0; c < numChannels; c ++) for (c = 0; c < numChannels; c ++)
{ {
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
@ -257,11 +242,11 @@ uint FIRFilter::getLength() const
} }
// Applies the filter to the given sequence of samples. // Applies the filter to the given sequence of samples.
// //
// Note : The amount of outputted samples is by value of 'filter_length' // Note : The amount of outputted samples is by value of 'filter_length'
// smaller than the amount of input samples. // smaller than the amount of input samples.
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
{ {
assert(length > 0); assert(length > 0);
assert(lengthDiv8 * 8 == length); assert(lengthDiv8 * 8 == length);
@ -272,7 +257,7 @@ uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSample
if (numChannels == 1) if (numChannels == 1)
{ {
return evaluateFilterMono(dest, src, numSamples); return evaluateFilterMono(dest, src, numSamples);
} }
else if (numChannels == 2) else if (numChannels == 2)
{ {
return evaluateFilterStereo(dest, src, numSamples); return evaluateFilterStereo(dest, src, numSamples);
@ -286,9 +271,9 @@ uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSample
} }
// Operator 'new' is overloaded so that it automatically creates a suitable instance // Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX-capable CPU available or not. // depending on if we've a MMX-capable CPU available or not.
void * FIRFilter::operator new(size_t s) void * FIRFilter::operator new(size_t)
{ {
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
@ -301,6 +286,7 @@ FIRFilter * FIRFilter::newInstance()
uint uExtensions; uint uExtensions;
uExtensions = detectCPUextensions(); uExtensions = detectCPUextensions();
(void)uExtensions;
// Check if MMX/SSE instruction set extensions supported by CPU // Check if MMX/SSE instruction set extensions supported by CPU

View File

@ -1,8 +1,8 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// General FIR digital filter routines with MMX optimization. /// General FIR digital filter routines with MMX optimization.
/// ///
/// Note : MMX optimized functions reside in a separate, platform-specific file, /// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' /// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -41,11 +41,11 @@
namespace soundtouch namespace soundtouch
{ {
class FIRFilter class FIRFilter
{ {
protected: protected:
// Number of FIR filter taps // Number of FIR filter taps
uint length; uint length;
// Number of FIR filter taps divided by 8 // Number of FIR filter taps divided by 8
uint lengthDiv8; uint lengthDiv8;
@ -59,11 +59,11 @@ protected:
SAMPLETYPE *filterCoeffs; SAMPLETYPE *filterCoeffs;
SAMPLETYPE *filterCoeffsStereo; SAMPLETYPE *filterCoeffsStereo;
virtual uint evaluateFilterStereo(SAMPLETYPE *dest, virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples) const; uint numSamples) const;
virtual uint evaluateFilterMono(SAMPLETYPE *dest, virtual uint evaluateFilterMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples) const; uint numSamples) const;
virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels); virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels);
@ -71,26 +71,26 @@ public:
FIRFilter(); FIRFilter();
virtual ~FIRFilter(); virtual ~FIRFilter();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance /// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX-capable CPU available or not. /// depending on if we've a MMX-capable CPU available or not.
static void * operator new(size_t s); static void * operator new(size_t s);
static FIRFilter *newInstance(); static FIRFilter *newInstance();
/// Applies the filter to the given sequence of samples. /// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter_length' /// Note : The amount of outputted samples is by value of 'filter_length'
/// smaller than the amount of input samples. /// smaller than the amount of input samples.
/// ///
/// \return Number of samples copied to 'dest'. /// \return Number of samples copied to 'dest'.
uint evaluate(SAMPLETYPE *dest, uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
uint numSamples, uint numSamples,
uint numChannels); uint numChannels);
uint getLength() const; uint getLength() const;
virtual void setCoefficients(const SAMPLETYPE *coeffs, virtual void setCoefficients(const SAMPLETYPE *coeffs,
uint newLength, uint newLength,
uint uResultDivFactor); uint uResultDivFactor);
}; };

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Cubic interpolation routine. /// Cubic interpolation routine.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -37,7 +37,7 @@
using namespace soundtouch; using namespace soundtouch;
// cubic interpolation coefficients // cubic interpolation coefficients
static const float _coeffs[]= static const float _coeffs[]=
{ -0.5f, 1.0f, -0.5f, 0.0f, { -0.5f, 1.0f, -0.5f, 0.0f,
1.5f, -2.5f, 0.0f, 1.0f, 1.5f, -2.5f, 0.0f, 1.0f,
-1.5f, 2.0f, 0.5f, 0.0f, -1.5f, 2.0f, 0.5f, 0.0f,
@ -56,10 +56,10 @@ void InterpolateCubic::resetRegisters()
} }
/// Transpose mono audio. Returns number of produced output samples, and /// Transpose mono audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, int InterpolateCubic::transposeMono(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
@ -101,10 +101,10 @@ int InterpolateCubic::transposeMono(SAMPLETYPE *pdest,
} }
/// Transpose stereo audio. Returns number of produced output samples, and /// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
@ -148,10 +148,10 @@ int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest,
} }
/// Transpose multi-channel audio. Returns number of produced output samples, and /// Transpose multi-channel audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Cubic interpolation routine. /// Cubic interpolation routine.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -38,17 +38,17 @@
namespace soundtouch namespace soundtouch
{ {
class InterpolateCubic final : public TransposerBase class InterpolateCubic : public TransposerBase
{ {
protected: protected:
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
double fract; double fract;
@ -58,7 +58,7 @@ public:
virtual void resetRegisters() override; virtual void resetRegisters() override;
int getLatency() const override virtual int getLatency() const override
{ {
return 1; return 1;
} }

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Linear interpolation algorithm. /// Linear interpolation algorithm.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -38,7 +38,7 @@ using namespace soundtouch;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// InterpolateLinearInteger - integer arithmetic implementation // InterpolateLinearInteger - integer arithmetic implementation
// //
/// fixed-point interpolation routine precision /// fixed-point interpolation routine precision
#define SCALE 65536 #define SCALE 65536
@ -47,7 +47,7 @@ using namespace soundtouch;
// Constructor // Constructor
InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase() InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase()
{ {
// Notice: use local function calling syntax for sake of clarity, // Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions. // to indicate the fact that C++ constructor can't call virtual functions.
resetRegisters(); resetRegisters();
setRate(1.0f); setRate(1.0f);
@ -60,8 +60,8 @@ void InterpolateLinearInteger::resetRegisters()
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in // 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
@ -73,7 +73,7 @@ int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
LONG_SAMPLETYPE temp; LONG_SAMPLETYPE temp;
assert(iFract < SCALE); assert(iFract < SCALE);
temp = (SCALE - iFract) * src[0] + iFract * src[1]; temp = (SCALE - iFract) * src[0] + iFract * src[1];
@ -93,8 +93,8 @@ int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Stereo' version of the routine. Returns the number of samples returned in // 'Stereo' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
@ -107,7 +107,7 @@ int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE
{ {
LONG_SAMPLETYPE temp0; LONG_SAMPLETYPE temp0;
LONG_SAMPLETYPE temp1; LONG_SAMPLETYPE temp1;
assert(iFract < SCALE); assert(iFract < SCALE);
temp0 = (SCALE - iFract) * src[0] + iFract * src[2]; temp0 = (SCALE - iFract) * src[0] + iFract * src[2];
@ -140,7 +140,7 @@ int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
LONG_SAMPLETYPE temp, vol1; LONG_SAMPLETYPE temp, vol1;
assert(iFract < SCALE); assert(iFract < SCALE);
vol1 = (LONG_SAMPLETYPE)(SCALE - iFract); vol1 = (LONG_SAMPLETYPE)(SCALE - iFract);
for (int c = 0; c < numChannels; c ++) for (int c = 0; c < numChannels; c ++)
@ -164,7 +164,7 @@ int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE
} }
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates. // iRate, larger faster iRates.
void InterpolateLinearInteger::setRate(double newRate) void InterpolateLinearInteger::setRate(double newRate)
{ {
@ -176,14 +176,14 @@ void InterpolateLinearInteger::setRate(double newRate)
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// InterpolateLinearFloat - floating point arithmetic implementation // InterpolateLinearFloat - floating point arithmetic implementation
// //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Constructor // Constructor
InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase() InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase()
{ {
// Notice: use local function calling syntax for sake of clarity, // Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions. // to indicate the fact that C++ constructor can't call virtual functions.
resetRegisters(); resetRegisters();
setRate(1.0); setRate(1.0);
@ -196,8 +196,8 @@ void InterpolateLinearFloat::resetRegisters()
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in // 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
@ -228,8 +228,8 @@ int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *sr
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in // 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer // the "dest" buffer
int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{ {
@ -272,7 +272,7 @@ int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *s
while (srcCount < srcSampleEnd) while (srcCount < srcSampleEnd)
{ {
float temp, vol1, fract_float; float temp, vol1, fract_float;
vol1 = (float)(1.0 - fract); vol1 = (float)(1.0 - fract);
fract_float = (float)fract; fract_float = (float)fract;
for (int c = 0; c < numChannels; c ++) for (int c = 0; c < numChannels; c ++)

View File

@ -1,5 +1,5 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Linear interpolation routine. /// Linear interpolation routine.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -39,29 +39,29 @@ namespace soundtouch
{ {
/// Linear transposer class that uses integer arithmetic /// Linear transposer class that uses integer arithmetic
class InterpolateLinearInteger final : public TransposerBase class InterpolateLinearInteger : public TransposerBase
{ {
protected: protected:
int iFract; int iFract;
int iRate; int iRate;
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override; virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override;
public: public:
InterpolateLinearInteger(); InterpolateLinearInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates. /// rate, larger faster rates.
virtual void setRate(double newRate) override; virtual void setRate(double newRate) override;
virtual void resetRegisters() override; virtual void resetRegisters() override;
int getLatency() const override virtual int getLatency() const override
{ {
return 0; return 0;
} }
@ -69,25 +69,25 @@ public:
/// Linear transposer class that uses floating point arithmetic /// Linear transposer class that uses floating point arithmetic
class InterpolateLinearFloat final : public TransposerBase class InterpolateLinearFloat : public TransposerBase
{ {
protected: protected:
double fract; double fract;
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples);
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples);
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override; virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);
public: public:
InterpolateLinearFloat(); InterpolateLinearFloat();
void resetRegisters() override; virtual void resetRegisters();
int getLatency() const override int getLatency() const
{ {
return 0; return 0;
} }

View File

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation /// Sample interpolation routine using 8-tap band-limited Shannon interpolation
/// with kaiser window. /// with kaiser window.
/// ///
/// Notice. This algorithm is remarkably much heavier than linear or cubic /// Notice. This algorithm is remarkably much heavier than linear or cubic
@ -43,7 +43,7 @@ using namespace soundtouch;
/// Kaiser window with beta = 2.0 /// Kaiser window with beta = 2.0
/// Values scaled down by 5% to avoid overflows /// Values scaled down by 5% to avoid overflows
static const double _kaiser8[8] = static const double _kaiser8[8] =
{ {
0.41778693317814, 0.41778693317814,
0.64888025049173, 0.64888025049173,
@ -71,10 +71,10 @@ void InterpolateShannon::resetRegisters()
#define PI 3.1415926536 #define PI 3.1415926536
#define sinc(x) (sin(PI * (x)) / (PI * (x))) #define sinc(x) (sin(PI * (x)) / (PI * (x)))
/// Transpose mono audio. Returns number of produced output samples, and /// Transpose mono audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, int InterpolateShannon::transposeMono(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
@ -119,10 +119,10 @@ int InterpolateShannon::transposeMono(SAMPLETYPE *pdest,
} }
/// Transpose stereo audio. Returns number of produced output samples, and /// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc, const SAMPLETYPE *psrc,
int &srcSamples) int &srcSamples)
{ {
int i; int i;
@ -169,11 +169,11 @@ int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest,
} }
/// Transpose stereo audio. Returns number of produced output samples, and /// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, int InterpolateShannon::transposeMulti(SAMPLETYPE *,
const SAMPLETYPE *psrc, const SAMPLETYPE *,
int &srcSamples) int &)
{ {
// not implemented // not implemented
assert(false); assert(false);

View File

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation /// Sample interpolation routine using 8-tap band-limited Shannon interpolation
/// with kaiser window. /// with kaiser window.
/// ///
/// Notice. This algorithm is remarkably much heavier than linear or cubic /// Notice. This algorithm is remarkably much heavier than linear or cubic
@ -43,17 +43,17 @@
namespace soundtouch namespace soundtouch
{ {
class InterpolateShannon final : public TransposerBase class InterpolateShannon : public TransposerBase
{ {
protected: protected:
int transposeMono(SAMPLETYPE *dest, int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
int transposeStereo(SAMPLETYPE *dest, int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
int transposeMulti(SAMPLETYPE *dest, int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) override; int &srcSamples) override;
double fract; double fract;
@ -63,7 +63,7 @@ public:
void resetRegisters() override; void resetRegisters() override;
int getLatency() const override virtual int getLatency() const override
{ {
return 3; return 3;
} }

View File

@ -1,8 +1,8 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Peak detection routine. /// Peak detection routine.
/// ///
/// The routine detects highest value on an array of values and calculates the /// 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. /// precise peak location as a mass-center of the 'hump' around the peak value.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -80,7 +80,7 @@ int PeakFinder::findTop(const float *data, int peakpos) const
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding // 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 // to direction defined by 'direction' until next 'hump' after minimum value will
// begin // begin
int PeakFinder::findGround(const float *data, int peakpos, int direction) const int PeakFinder::findGround(const float *data, int peakpos, int direction) const
{ {
@ -186,7 +186,7 @@ double PeakFinder::getPeakCenter(const float *data, int peakpos) const
peakLevel = data[peakpos]; peakLevel = data[peakpos];
if (gp1 == gp2) if (gp1 == gp2)
{ {
// avoid rounding errors when all are equal // avoid rounding errors when all are equal
assert(gp1 == peakpos); assert(gp1 == peakpos);
@ -210,7 +210,7 @@ double PeakFinder::getPeakCenter(const float *data, int peakpos) const
} }
double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
{ {
int i; int i;
@ -225,19 +225,19 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
peak = data[minPos]; peak = data[minPos];
for (i = minPos + 1; i < maxPos; i ++) for (i = minPos + 1; i < maxPos; i ++)
{ {
if (data[i] > peak) if (data[i] > peak)
{ {
peak = data[i]; peak = data[i];
peakpos = i; peakpos = i;
} }
} }
// Calculate exact location of the highest peak mass center // Calculate exact location of the highest peak mass center
highPeak = getPeakCenter(data, peakpos); highPeak = getPeakCenter(data, peakpos);
peak = highPeak; peak = highPeak;
// Now check if the highest peak were in fact harmonic of the true base beat peak // 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 // - sometimes the highest peak can be Nth harmonic of the true base peak yet
// just a slightly higher than the true base // just a slightly higher than the true base
for (i = 1; i < 3; i ++) for (i = 1; i < 3; i ++)
@ -254,7 +254,7 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
// calculate mass-center of possible harmonic peak // calculate mass-center of possible harmonic peak
peaktmp = getPeakCenter(data, peakpos); peaktmp = getPeakCenter(data, peakpos);
// accept harmonic peak if // accept harmonic peak if
// (a) it is found // (a) it is found
// (b) is within ±4% of the expected harmonic interval // (b) is within ±4% of the expected harmonic interval
// (c) has at least half x-corr value of the max. peak // (c) has at least half x-corr value of the max. peak

View File

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// The routine detects highest value on an array of values and calculates the /// 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. /// precise peak location as a mass-center of the 'hump' around the peak value.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -60,7 +60,7 @@ protected:
int findTop(const float *data, int peakpos) const; int findTop(const float *data, int peakpos) const;
/// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
/// or left-hand side of the given peak position. /// or left-hand side of the given peak position.
int findGround(const float *data, /// Data vector. int findGround(const float *data, /// Data vector.
int peakpos, /// Peak position index within the data vector. int peakpos, /// Peak position index within the data vector.
@ -71,7 +71,7 @@ protected:
double getPeakCenter(const float *data, int peakpos) const; double getPeakCenter(const float *data, int peakpos) const;
public: public:
/// Constructor. /// Constructor.
PeakFinder(); PeakFinder();
/// Detect exact peak position of the data vector by finding the largest peak 'hump' /// Detect exact peak position of the data vector by finding the largest peak 'hump'

View File

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample rate transposer. Changes sample rate by using linear interpolation /// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti- /// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application) /// alias filtering should be quite adequate for this application)
/// ///
@ -50,7 +50,7 @@ TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
// Constructor // Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{ {
bUseAAFilter = bUseAAFilter =
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
true; true;
#else #else
@ -96,7 +96,7 @@ AAFilter *RateTransposer::getAAFilter()
} }
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower // Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates. // iRate, larger faster iRates.
void RateTransposer::setRate(double newRate) void RateTransposer::setRate(double newRate)
{ {
@ -105,11 +105,11 @@ void RateTransposer::setRate(double newRate)
pTransposer->setRate(newRate); pTransposer->setRate(newRate);
// design a new anti-alias filter // design a new anti-alias filter
if (newRate > 1.0) if (newRate > 1.0)
{ {
fCutoff = 0.5 / newRate; fCutoff = 0.5 / newRate;
} }
else else
{ {
fCutoff = 0.5 * newRate; fCutoff = 0.5 * newRate;
} }
@ -125,14 +125,12 @@ void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
} }
// Transposes sample rate by applying anti-alias filter to prevent folding. // Transposes sample rate by applying anti-alias filter to prevent folding.
// Returns amount of samples returned in the "dest" buffer. // Returns amount of samples returned in the "dest" buffer.
// The maximum amount of samples that can be returned at a time is set by // The maximum amount of samples that can be returned at a time is set by
// the 'set_returnBuffer_size' function. // the 'set_returnBuffer_size' function.
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
{ {
uint count;
if (nSamples == 0) return; if (nSamples == 0) return;
// Store samples to input buffer // Store samples to input buffer
@ -140,16 +138,16 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
// If anti-alias filter is turned off, simply transpose without applying // If anti-alias filter is turned off, simply transpose without applying
// the filter // the filter
if (bUseAAFilter == false) if (bUseAAFilter == false)
{ {
count = pTransposer->transpose(outputBuffer, inputBuffer); (void)pTransposer->transpose(outputBuffer, inputBuffer);
return; return;
} }
assert(pAAFilter); assert(pAAFilter);
// Transpose with anti-alias filter // Transpose with anti-alias filter
if (pTransposer->rate < 1.0f) if (pTransposer->rate < 1.0f)
{ {
// If the parameter 'Rate' value is smaller than 1, first transpose // If the parameter 'Rate' value is smaller than 1, first transpose
// the samples and then apply the anti-alias filter to remove aliasing. // the samples and then apply the anti-alias filter to remove aliasing.
@ -159,8 +157,8 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
// Apply the anti-alias filter for transposed samples in midBuffer // Apply the anti-alias filter for transposed samples in midBuffer
pAAFilter->evaluate(outputBuffer, midBuffer); pAAFilter->evaluate(outputBuffer, midBuffer);
} }
else else
{ {
// If the parameter 'Rate' value is larger than 1, first apply the // If the parameter 'Rate' value is larger than 1, first apply the
// anti-alias filter to remove high frequencies (prevent them from folding // anti-alias filter to remove high frequencies (prevent them from folding
@ -224,7 +222,7 @@ int RateTransposer::getLatency() const
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// TransposerBase - Base class for interpolation // TransposerBase - Base class for interpolation
// //
// static function to set interpolation algorithm // static function to set interpolation algorithm
void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a) void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
@ -233,7 +231,7 @@ void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
} }
// Transposes the sample rate of the given samples using linear interpolation. // Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer // Returns the number of samples returned in the "dest" buffer
int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
{ {
@ -248,11 +246,11 @@ int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
{ {
numOutput = transposeMono(pdest, psrc, numSrcSamples); numOutput = transposeMono(pdest, psrc, numSrcSamples);
} }
else if (numChannels == 2) else if (numChannels == 2)
{ {
numOutput = transposeStereo(pdest, psrc, numSrcSamples); numOutput = transposeStereo(pdest, psrc, numSrcSamples);
} }
else else
#endif // USE_MULTICH_ALWAYS #endif // USE_MULTICH_ALWAYS
{ {
assert(numChannels > 0); assert(numChannels > 0);
@ -309,7 +307,7 @@ TransposerBase *TransposerBase::newInstance()
default: default:
assert(false); assert(false);
return NULL; return nullptr;
} }
#endif #endif
} }

View File

@ -1,10 +1,10 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sample rate transposer. Changes sample rate by using linear interpolation /// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti- /// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application). /// alias filtering should be quite adequate for this application).
/// ///
/// Use either of the derived classes of 'RateTransposerInteger' or /// Use either of the derived classes of 'RateTransposerInteger' or
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing /// 'RateTransposerFloat' for corresponding integer/floating point tranposing
/// algorithm implementation. /// algorithm implementation.
/// ///
@ -59,14 +59,14 @@ public:
}; };
protected: protected:
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) = 0; int &srcSamples) = 0;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) = 0; int &srcSamples) = 0;
virtual int transposeMulti(SAMPLETYPE *dest, virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) = 0; int &srcSamples) = 0;
static ALGORITHM algorithm; static ALGORITHM algorithm;
@ -115,11 +115,11 @@ protected:
bool bUseAAFilter; bool bUseAAFilter;
/// Transposes sample rate by applying anti-alias filter to prevent folding. /// Transposes sample rate by applying anti-alias filter to prevent folding.
/// Returns amount of samples returned in the "dest" buffer. /// Returns amount of samples returned in the "dest" buffer.
/// The maximum amount of samples that can be returned at a time is set by /// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function. /// the 'set_returnBuffer_size' function.
void processSamples(const SAMPLETYPE *src, void processSamples(const SAMPLETYPE *src,
uint numSamples); uint numSamples);
public: public:
@ -138,7 +138,7 @@ public:
/// Returns nonzero if anti-alias filter is enabled. /// Returns nonzero if anti-alias filter is enabled.
bool isAAFilterEnabled() const; bool isAAFilterEnabled() const;
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates. /// rate, larger faster rates.
virtual void setRate(double newRate); virtual void setRate(double newRate);

View File

@ -1,27 +1,27 @@
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// ///
/// SoundTouch - main class for tempo/pitch/rate adjusting routines. /// SoundTouch - main class for tempo/pitch/rate adjusting routines.
/// ///
/// Notes: /// Notes:
/// - Initialize the SoundTouch object instance by setting up the sound stream /// - Initialize the SoundTouch object instance by setting up the sound stream
/// parameters with functions 'setSampleRate' and 'setChannels', then set /// parameters with functions 'setSampleRate' and 'setChannels', then set
/// desired tempo/pitch/rate settings with the corresponding functions. /// desired tempo/pitch/rate settings with the corresponding functions.
/// ///
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The /// - The SoundTouch class behaves like a first-in-first-out pipeline: The
/// samples that are to be processed are fed into one of the pipe by calling /// samples that are to be processed are fed into one of the pipe by calling
/// function 'putSamples', while the ready processed samples can be read /// function 'putSamples', while the ready processed samples can be read
/// from the other end of the pipeline with function 'receiveSamples'. /// from the other end of the pipeline with function 'receiveSamples'.
/// ///
/// - The SoundTouch processing classes require certain sized 'batches' of /// - The SoundTouch processing classes require certain sized 'batches' of
/// samples in order to process the sound. For this reason the classes buffer /// samples in order to process the sound. For this reason the classes buffer
/// incoming samples until there are enough of samples available for /// incoming samples until there are enough of samples available for
/// processing, then they carry out the processing step and consequently /// processing, then they carry out the processing step and consequently
/// make the processed samples available for outputting. /// make the processed samples available for outputting.
/// ///
/// - For the above reason, the processing routines introduce a certain /// - For the above reason, the processing routines introduce a certain
/// 'latency' between the input and output, so that the samples input to /// 'latency' between the input and output, so that the samples input to
/// SoundTouch may not be immediately available in the output, and neither /// SoundTouch may not be immediately available in the output, and neither
/// the amount of outputtable samples may not immediately be in direct /// the amount of outputtable samples may not immediately be in direct
/// relationship with the amount of previously input samples. /// relationship with the amount of previously input samples.
/// ///
/// - The tempo/pitch/rate control parameters can be altered during processing. /// - The tempo/pitch/rate control parameters can be altered during processing.
@ -30,8 +30,8 @@
/// required. /// required.
/// ///
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying /// - This class utilizes classes 'TDStretch' for tempo change (without modifying
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both /// pitch) and 'RateTransposer' for changing the playback rate (that is, both
/// tempo and pitch in the same ratio) of the sound. The third available control /// tempo and pitch in the same ratio) of the sound. The third available control
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of /// 'pitch' (change pitch but maintain tempo) is produced by a combination of
/// combining the two other controls. /// combining the two other controls.
/// ///
@ -74,7 +74,7 @@
#include "cpu_detect.h" #include "cpu_detect.h"
using namespace soundtouch; using namespace soundtouch;
/// test if two floating point numbers are equal /// test if two floating point numbers are equal
#define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10) #define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10)
@ -83,7 +83,7 @@ using namespace soundtouch;
extern "C" void soundtouch_ac_test() extern "C" void soundtouch_ac_test()
{ {
printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);
} }
SoundTouch::SoundTouch() SoundTouch::SoundTouch()
@ -97,8 +97,8 @@ SoundTouch::SoundTouch()
rate = tempo = 0; rate = tempo = 0;
virtualPitch = virtualPitch =
virtualRate = virtualRate =
virtualTempo = 1.0; virtualTempo = 1.0;
calcEffectiveRateAndTempo(); calcEffectiveRateAndTempo();
@ -227,9 +227,9 @@ void SoundTouch::calcEffectiveRateAndTempo()
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)
{ {
if (output != pTDStretch) if (output != pTDStretch)
{ {
FIFOSamplePipe *tempoOut; FIFOSamplePipe *tempoOut;
@ -246,7 +246,7 @@ void SoundTouch::calcEffectiveRateAndTempo()
else else
#endif #endif
{ {
if (output != pRateTransposer) if (output != pRateTransposer)
{ {
FIFOSamplePipe *transOut; FIFOSamplePipe *transOut;
@ -259,7 +259,7 @@ void SoundTouch::calcEffectiveRateAndTempo()
output = pRateTransposer; output = pRateTransposer;
} }
} }
} }
@ -276,31 +276,31 @@ void SoundTouch::setSampleRate(uint srate)
// the input of the object. // the input of the object.
void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
{ {
if (bSrateSet == false) if (bSrateSet == false)
{ {
ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined"); ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined");
} }
else if (channels == 0) else if (channels == 0)
{ {
ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined"); ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined");
} }
// 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)
{ {
// transpose the rate down, output the transposed sound to tempo changer buffer // transpose the rate down, output the transposed sound to tempo changer buffer
assert(output == pTDStretch); assert(output == pTDStretch);
pRateTransposer->putSamples(samples, nSamples); pRateTransposer->putSamples(samples, nSamples);
pTDStretch->moveSamples(*pRateTransposer); pTDStretch->moveSamples(*pRateTransposer);
} }
else else
#endif #endif
{ {
// evaluate the tempo changer, then transpose the rate up, // evaluate the tempo changer, then transpose the rate up,
assert(output == pRateTransposer); assert(output == pRateTransposer);
pTDStretch->putSamples(samples, nSamples); pTDStretch->putSamples(samples, nSamples);
pRateTransposer->moveSamples(*pTDStretch); pRateTransposer->moveSamples(*pTDStretch);
@ -327,8 +327,8 @@ void SoundTouch::flush()
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 ++)
{ {
@ -355,7 +355,7 @@ bool SoundTouch::setSetting(int settingId, int value)
// read current tdstretch routine parameters // read current tdstretch routine parameters
pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);
switch (settingId) switch (settingId)
{ {
case SETTING_USE_AA_FILTER : case SETTING_USE_AA_FILTER :
// enables / disabless anti-alias filter // enables / disabless anti-alias filter
@ -401,7 +401,7 @@ int SoundTouch::getSetting(int settingId) const
{ {
int temp; int temp;
switch (settingId) switch (settingId)
{ {
case SETTING_USE_AA_FILTER : case SETTING_USE_AA_FILTER :
return (uint)pRateTransposer->isAAFilterEnabled(); return (uint)pRateTransposer->isAAFilterEnabled();
@ -413,15 +413,15 @@ int SoundTouch::getSetting(int settingId) const
return (uint)pTDStretch->isQuickSeekEnabled(); return (uint)pTDStretch->isQuickSeekEnabled();
case SETTING_SEQUENCE_MS: case SETTING_SEQUENCE_MS:
pTDStretch->getParameters(NULL, &temp, NULL, NULL); pTDStretch->getParameters(nullptr, &temp, nullptr, nullptr);
return temp; return temp;
case SETTING_SEEKWINDOW_MS: case SETTING_SEEKWINDOW_MS:
pTDStretch->getParameters(NULL, NULL, &temp, NULL); pTDStretch->getParameters(nullptr, nullptr, &temp, nullptr);
return temp; return temp;
case SETTING_OVERLAP_MS: case SETTING_OVERLAP_MS:
pTDStretch->getParameters(NULL, NULL, NULL, &temp); pTDStretch->getParameters(nullptr, nullptr, nullptr, &temp);
return temp; return temp;
case SETTING_NOMINAL_INPUT_SEQUENCE : case SETTING_NOMINAL_INPUT_SEQUENCE :
@ -503,8 +503,8 @@ uint SoundTouch::numUnprocessedSamples() const
} }
/// Output samples from beginning of the sample buffer. Copies requested samples to /// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than /// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available. /// 'numsample' samples in the buffer, returns all that available.
/// ///
/// \return Number of samples returned. /// \return Number of samples returned.
@ -516,8 +516,8 @@ uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples)
} }
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
@ -530,7 +530,7 @@ uint SoundTouch::receiveSamples(uint maxSamples)
/// Get ratio between input and output audio durations, useful for calculating /// Get ratio between input and output audio durations, useful for calculating
/// processed output duration: if you'll process a stream of N samples, then /// processed output duration: if you'll process a stream of N samples, then
/// you can expect to get out N * getInputOutputSampleRatio() samples. /// you can expect to get out N * getInputOutputSampleRatio() samples.
double SoundTouch::getInputOutputSampleRatio() double SoundTouch::getInputOutputSampleRatio()
{ {

View File

@ -1,15 +1,15 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// ///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// 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.
/// ///
/// Notes : 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 /// This source file contains OpenMP optimizations that allow speeding up the
/// corss-correlation algorithm by executing it in several threads / CPU cores /// corss-correlation algorithm by executing it in several threads / CPU cores
/// in parallel. See the following article link for more detailed discussion /// in parallel. See the following article link for more detailed discussion
/// about SoundTouch OpenMP optimizations: /// about SoundTouch OpenMP optimizations:
/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices /// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
/// ///
@ -54,25 +54,6 @@ using namespace soundtouch;
#define max(x, y) (((x) > (y)) ? (x) : (y)) #define max(x, y) (((x) > (y)) ? (x) : (y))
/*****************************************************************************
*
* Constant definitions
*
*****************************************************************************/
// Table for the hierarchical mixing position seeking algorithm
const short _scanOffsets[5][24]={
{ 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806,
868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0},
{-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 121, 114, 97, 114, 98, 105, 108, 32, 104, 99, 117, 111,
116, 100, 110, 117, 111, 115, 0, 0, 0, 0, 0, 0}};
/***************************************************************************** /*****************************************************************************
* *
* Implementation of the class 'TDStretch' * Implementation of the class 'TDStretch'
@ -85,8 +66,8 @@ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
bQuickSeek = false; bQuickSeek = false;
channels = 2; channels = 2;
pMidBuffer = NULL; pMidBuffer = nullptr;
pMidBufferUnaligned = NULL; pMidBufferUnaligned = nullptr;
overlapLength = 0; overlapLength = 0;
bAutoSeqSetting = true; bAutoSeqSetting = true;
@ -113,11 +94,11 @@ TDStretch::~TDStretch()
// //
// 'sampleRate' = sample rate of the sound // 'sampleRate' = sample rate of the sound
// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) // 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms)
// 'seekwindowMS' = seeking window length for scanning the best overlapping // 'seekwindowMS' = seeking window length for scanning the best overlapping
// position (default = 28 ms) // position (default = 28 ms)
// 'overlapMS' = overlapping length (default = 12 ms) // 'overlapMS' = overlapping length (default = 12 ms)
void TDStretch::setParameters(int aSampleRate, int aSequenceMS, void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
int aSeekWindowMS, int aOverlapMS) int aSeekWindowMS, int aOverlapMS)
{ {
// accept only positive parameter values - if zero or negative, use old values instead // accept only positive parameter values - if zero or negative, use old values instead
@ -133,19 +114,19 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
{ {
this->sequenceMs = aSequenceMS; this->sequenceMs = aSequenceMS;
bAutoSeqSetting = false; bAutoSeqSetting = false;
} }
else if (aSequenceMS == 0) else if (aSequenceMS == 0)
{ {
// if zero, use automatic setting // if zero, use automatic setting
bAutoSeqSetting = true; bAutoSeqSetting = true;
} }
if (aSeekWindowMS > 0) if (aSeekWindowMS > 0)
{ {
this->seekWindowMs = aSeekWindowMS; this->seekWindowMs = aSeekWindowMS;
bAutoSeekSetting = false; bAutoSeekSetting = false;
} }
else if (aSeekWindowMS == 0) else if (aSeekWindowMS == 0)
{ {
// if zero, use automatic setting // if zero, use automatic setting
bAutoSeekSetting = true; bAutoSeekSetting = true;
@ -162,7 +143,7 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
/// Get routine control parameters, see setParameters() function. /// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be NULL, in such case corresponding parameter /// Any of the parameters to this function can be nullptr, in such case corresponding parameter
/// value isn't returned. /// value isn't returned.
void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const
{ {
@ -251,11 +232,11 @@ bool TDStretch::isQuickSeekEnabled() const
// Seeks for the optimal overlap-mixing position. // Seeks for the optimal overlap-mixing position.
int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)
{ {
if (bQuickSeek) if (bQuickSeek)
{ {
return seekBestOverlapPositionQuick(refPos); return seekBestOverlapPositionQuick(refPos);
} }
else else
{ {
return seekBestOverlapPositionFull(refPos); return seekBestOverlapPositionFull(refPos);
} }
@ -276,8 +257,8 @@ inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, ui
{ {
// stereo sound // stereo sound
overlapStereo(pOutput, pInput + 2 * ovlPos); overlapStereo(pOutput, pInput + 2 * ovlPos);
} }
else else
#endif // USE_MULTICH_ALWAYS #endif // USE_MULTICH_ALWAYS
{ {
assert(channels > 0); assert(channels > 0);
@ -292,7 +273,7 @@ inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, ui
// The best position is determined as the position where the two overlapped // The best position is determined as the position where the two overlapped
// sample sequences are 'most alike', in terms of the highest cross-correlation // sample sequences are 'most alike', in terms of the highest cross-correlation
// value over the overlapping period // value over the overlapping period
int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
{ {
int bestOffs; int bestOffs;
double bestCorr; double bestCorr;
@ -319,7 +300,7 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm); corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm);
#else #else
// In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same
// as "calcCrossCorr", but saves time by reusing & updating previously stored // as "calcCrossCorr", but saves time by reusing & updating previously stored
// "norm" value // "norm" value
corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm); corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm);
#endif #endif
@ -328,7 +309,7 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp)); corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));
// Checks for the highest correlation value // Checks for the highest correlation value
if (corr > bestCorr) if (corr > bestCorr)
{ {
// For optimal performance, enter critical section only in case that best value found. // For optimal performance, enter critical section only in case that best value found.
// in such case repeat 'if' condition as it's possible that parallel execution may have // in such case repeat 'if' condition as it's possible that parallel execution may have
@ -353,14 +334,14 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
} }
// Quick seek algorithm for improved runtime-performance: First roughly scans through the // Quick seek algorithm for improved runtime-performance: First roughly scans through the
// correlation area, and then scan surroundings of two best preliminary correlation candidates // correlation area, and then scan surroundings of two best preliminary correlation candidates
// with improved precision // with improved precision
// //
// Based on testing: // Based on testing:
// - This algorithm gives on average 99% as good match as the full algorithm // - This algorithm gives on average 99% as good match as the full algorithm
// - this quick seek algorithm finds the best match on ~90% of cases // - this quick seek algorithm finds the best match on ~90% of cases
// - on those 10% of cases when this algorithm doesn't find best match, // - on those 10% of cases when this algorithm doesn't find best match,
// it still finds on average ~90% match vs. the best possible match // it still finds on average ~90% match vs. the best possible match
int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
{ {
@ -379,7 +360,7 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
bestCorr = bestCorr =
bestCorr2 = -FLT_MAX; bestCorr2 = -FLT_MAX;
bestOffs = bestOffs =
bestOffs2 = SCANWIND; bestOffs2 = SCANWIND;
// Scans for the best correlation value by testing each possible position // Scans for the best correlation value by testing each possible position
@ -387,7 +368,7 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
// increase possibility of ideal match. // increase possibility of ideal match.
// //
// Begin from "SCANSTEP" instead of SCANWIND to make the calculation // Begin from "SCANSTEP" instead of SCANWIND to make the calculation
// catch the 'middlepoint' of seekLength vector as that's the a-priori // catch the 'middlepoint' of seekLength vector as that's the a-priori
// expected best match position // expected best match position
// //
// Roughly: // Roughly:
@ -475,7 +456,7 @@ int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)
/// For integer algorithm: adapt normalization factor divider with music so that /// For integer algorithm: adapt normalization factor divider with music so that
/// it'll not be pessimistically restrictive that can degrade quality on quieter sections /// it'll not be pessimistically restrictive that can degrade quality on quieter sections
/// yet won't cause integer overflows either /// yet won't cause integer overflows either
void TDStretch::adaptNormalizer() void TDStretch::adaptNormalizer()
@ -483,7 +464,7 @@ void TDStretch::adaptNormalizer()
// Do not adapt normalizer over too silent sequences to avoid averaging filter depleting to // Do not adapt normalizer over too silent sequences to avoid averaging filter depleting to
// too low values during pauses in music // too low values during pauses in music
if ((maxnorm > 1000) || (maxnormf > 40000000)) if ((maxnorm > 1000) || (maxnormf > 40000000))
{ {
//norm averaging filter //norm averaging filter
maxnormf = 0.9f * maxnormf + 0.1f * (float)maxnorm; maxnormf = 0.9f * maxnormf + 0.1f * (float)maxnorm;
@ -504,7 +485,7 @@ void TDStretch::adaptNormalizer()
} }
/// clear cross correlation routine state if necessary /// clear cross correlation routine state if necessary
void TDStretch::clearCrossCorrState() void TDStretch::clearCrossCorrState()
{ {
// default implementation is empty. // default implementation is empty.
@ -534,7 +515,7 @@ void TDStretch::calcSeqParameters()
#define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x))) #define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x)))
double seq, seek; double seq, seek;
if (bAutoSeqSetting) if (bAutoSeqSetting)
{ {
seq = AUTOSEQ_C + AUTOSEQ_K * tempo; seq = AUTOSEQ_C + AUTOSEQ_K * tempo;
@ -551,7 +532,7 @@ void TDStretch::calcSeqParameters()
// Update seek window lengths // Update seek window lengths
seekWindowLength = (sampleRate * sequenceMs) / 1000; seekWindowLength = (sampleRate * sequenceMs) / 1000;
if (seekWindowLength < 2 * overlapLength) if (seekWindowLength < 2 * overlapLength)
{ {
seekWindowLength = 2 * overlapLength; seekWindowLength = 2 * overlapLength;
} }
@ -560,7 +541,7 @@ void TDStretch::calcSeqParameters()
// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower // Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
// tempo, larger faster tempo. // tempo, larger faster tempo.
void TDStretch::setTempo(double newTempo) void TDStretch::setTempo(double newTempo)
{ {
@ -571,11 +552,11 @@ void TDStretch::setTempo(double newTempo)
// Calculate new sequence duration // Calculate new sequence duration
calcSeqParameters(); calcSeqParameters();
// Calculate ideal skip length (according to tempo value) // Calculate ideal skip length (according to tempo value)
nominalSkip = tempo * (seekWindowLength - overlapLength); nominalSkip = tempo * (seekWindowLength - overlapLength);
intskip = (int)(nominalSkip + 0.5); intskip = (int)(nominalSkip + 0.5);
// Calculate how many samples are needed in the 'inputBuffer' to // Calculate how many samples are needed in the 'inputBuffer' to
// process another batch of samples // process another batch of samples
//sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2; //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2;
sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength; sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength;
@ -606,18 +587,18 @@ void TDStretch::processNominalTempo()
{ {
assert(tempo == 1.0f); assert(tempo == 1.0f);
if (bMidBufferDirty) if (bMidBufferDirty)
{ {
// If there are samples in pMidBuffer waiting for overlapping, // If there are samples in pMidBuffer waiting for overlapping,
// do a single sliding overlapping with them in order to prevent a // do a single sliding overlapping with them in order to prevent a
// clicking distortion in the output sound // clicking distortion in the output sound
if (inputBuffer.numSamples() < overlapLength) if (inputBuffer.numSamples() < overlapLength)
{ {
// wait until we've got overlapLength input samples // wait until we've got overlapLength input samples
return; return;
} }
// Mix the samples in the beginning of 'inputBuffer' with the // Mix the samples in the beginning of 'inputBuffer' with the
// samples in 'midBuffer' using sliding overlapping // samples in 'midBuffer' using sliding overlapping
overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);
outputBuffer.putSamples(overlapLength); outputBuffer.putSamples(overlapLength);
inputBuffer.receiveSamples(overlapLength); inputBuffer.receiveSamples(overlapLength);
@ -642,7 +623,7 @@ void TDStretch::processSamples()
/* 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
crosses the nominal value crosses the nominal value
if (tempo == 1.0f) if (tempo == 1.0f)
{ {
// tempo not changed from the original, so bypass the processing // tempo not changed from the original, so bypass the processing
processNominalTempo(); processNominalTempo();
@ -652,15 +633,15 @@ void TDStretch::processSamples()
// Process samples as long as there are enough samples in 'inputBuffer' // Process samples as long as there are enough samples in 'inputBuffer'
// to form a processing frame. // to form a processing frame.
while ((int)inputBuffer.numSamples() >= sampleReq) while ((int)inputBuffer.numSamples() >= sampleReq)
{ {
if (isBeginning == false) if (isBeginning == false)
{ {
// apart from the very beginning of the track, // apart from the very beginning of the track,
// scan for the best overlapping position & do overlap-add // scan for the best overlapping position & do overlap-add
offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); 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')
@ -705,11 +686,11 @@ void TDStretch::processSamples()
temp = (seekWindowLength - 2 * overlapLength); temp = (seekWindowLength - 2 * overlapLength);
outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * offset, (uint)temp); 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) <= (int)inputBuffer.numSamples()); assert((offset + temp + overlapLength) <= (int)inputBuffer.numSamples());
memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp), 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
@ -757,9 +738,9 @@ void TDStretch::acceptNewOverlapLength(int newOverlapLength)
} }
// Operator 'new' is overloaded so that it automatically creates a suitable instance // Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX/SSE/etc-capable CPU available or not. // depending on if we've a MMX/SSE/etc-capable CPU available or not.
void * TDStretch::operator new(size_t s) void * TDStretch::operator new(size_t)
{ {
// Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"); ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!");
@ -772,6 +753,7 @@ TDStretch * TDStretch::newInstance()
uint uExtensions; uint uExtensions;
uExtensions = detectCPUextensions(); uExtensions = detectCPUextensions();
(void)uExtensions;
// Check if MMX/SSE instruction set extensions supported by CPU // Check if MMX/SSE instruction set extensions supported by CPU
@ -809,7 +791,7 @@ TDStretch * TDStretch::newInstance()
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' // Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo'
// version of the routine. // version of the routine.
void TDStretch::overlapStereo(short *poutput, const short *input) const void TDStretch::overlapStereo(short *poutput, const short *input) const
{ {
@ -862,8 +844,8 @@ void TDStretch::calculateOverlapLength(int aoverlapMs)
assert(aoverlapMs >= 0); assert(aoverlapMs >= 0);
// calculate overlap length so that it's power of 2 - thus it's easy to do // calculate overlap length so that it's power of 2 - thus it's easy to do
// integer division by right-shifting. Term "-1" at end is to account for // integer division by right-shifting. Term "-1" at end is to account for
// the extra most significatnt bit left unused in result by signed multiplication // the extra most significatnt bit left unused in result by signed multiplication
overlapDividerBitsPure = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1; overlapDividerBitsPure = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1;
if (overlapDividerBitsPure > 9) overlapDividerBitsPure = 9; if (overlapDividerBitsPure > 9) overlapDividerBitsPure = 9;
if (overlapDividerBitsPure < 3) overlapDividerBitsPure = 3; if (overlapDividerBitsPure < 3) overlapDividerBitsPure = 3;
@ -873,8 +855,8 @@ void TDStretch::calculateOverlapLength(int aoverlapMs)
overlapDividerBitsNorm = overlapDividerBitsPure; overlapDividerBitsNorm = overlapDividerBitsPure;
// calculate sloping divider so that crosscorrelation operation won't // calculate sloping divider so that crosscorrelation operation won't
// overflow 32-bit register. Max. sum of the crosscorrelation sum without // overflow 32-bit register. Max. sum of the crosscorrelation sum without
// divider would be 2^30*(N^3-N)/3, where N = overlap length // divider would be 2^30*(N^3-N)/3, where N = overlap length
slopingDivider = (newOvl * newOvl - 1) / 3; slopingDivider = (newOvl * newOvl - 1) / 3;
} }
@ -898,9 +880,9 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do
// Same routine for stereo and mono // Same routine for stereo and mono
for (i = 0; i < ilength; i += 2) for (i = 0; i < ilength; i += 2)
{ {
corr += (mixingPos[i] * compare[i] + corr += (mixingPos[i] * compare[i] +
mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;
lnorm += (mixingPos[i] * mixingPos[i] + lnorm += (mixingPos[i] * mixingPos[i] +
mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm; mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm;
// do intermediate scalings to avoid integer overflow // do intermediate scalings to avoid integer overflow
} }
@ -914,7 +896,7 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do
maxnorm = lnorm; 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
norm = (double)lnorm; norm = (double)lnorm;
return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm);
@ -940,9 +922,9 @@ double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *c
corr = 0; corr = 0;
// Same routine for stereo and mono. // Same routine for stereo and mono.
for (i = 0; i < ilength; i += 2) for (i = 0; i < ilength; i += 2)
{ {
corr += (mixingPos[i] * compare[i] + corr += (mixingPos[i] * compare[i] +
mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;
} }
@ -959,7 +941,7 @@ double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *c
maxnorm = (unsigned long)norm; maxnorm = (unsigned long)norm;
} }
// 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
return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm);
} }
@ -986,7 +968,7 @@ void TDStretch::overlapStereo(float *pOutput, const float *pInput) const
f1 = 0; f1 = 0;
f2 = 1.0f; f2 = 1.0f;
for (i = 0; i < 2 * (int)overlapLength ; i += 2) for (i = 0; i < 2 * (int)overlapLength ; i += 2)
{ {
pOutput[i + 0] = pInput[i + 0] * f1 + pMidBuffer[i + 0] * f2; pOutput[i + 0] = pInput[i + 0] * f1 + pMidBuffer[i + 0] * f2;
pOutput[i + 1] = pInput[i + 1] * f1 + pMidBuffer[i + 1] * f2; pOutput[i + 1] = pInput[i + 1] * f1 + pMidBuffer[i + 1] * f2;
@ -997,7 +979,7 @@ void TDStretch::overlapStereo(float *pOutput, const float *pInput) const
} }
// Overlaps samples in 'midBuffer' with the samples in 'input'. // Overlaps samples in 'midBuffer' with the samples in 'input'.
void TDStretch::overlapMulti(float *pOutput, const float *pInput) const void TDStretch::overlapMulti(float *pOutput, const float *pInput) const
{ {
int i; int i;

View File

@ -1,10 +1,10 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method /// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks. /// with several performance-increasing tweaks.
/// ///
/// Note : MMX/SSE optimized functions reside in separate, platform-specific files /// Note : MMX/SSE optimized functions reside in separate, platform-specific files
/// 'mmx_optimized.cpp' and 'sse_optimized.cpp' /// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -46,14 +46,14 @@ namespace soundtouch
{ {
/// Default values for sound processing parameters: /// Default values for sound processing parameters:
/// Notice that the default parameters are tuned for contemporary popular music /// Notice that the default parameters are tuned for contemporary popular music
/// processing. For speech processing applications these parameters suit better: /// processing. For speech processing applications these parameters suit better:
/// #define DEFAULT_SEQUENCE_MS 40 /// #define DEFAULT_SEQUENCE_MS 40
/// #define DEFAULT_SEEKWINDOW_MS 15 /// #define DEFAULT_SEEKWINDOW_MS 15
/// #define DEFAULT_OVERLAP_MS 8 /// #define DEFAULT_OVERLAP_MS 8
/// ///
/// Default length of a single processing sequence, in milliseconds. This determines to how /// Default length of a single processing sequence, in milliseconds. This determines to how
/// long sequences the original sound is chopped in the time-stretch algorithm. /// long sequences the original sound is chopped in the time-stretch algorithm.
/// ///
/// The larger this value is, the lesser sequences are used in processing. In principle /// The larger this value is, the lesser sequences are used in processing. In principle
@ -68,15 +68,15 @@ namespace soundtouch
/// according to tempo setting (recommended) /// according to tempo setting (recommended)
#define USE_AUTO_SEQUENCE_LEN 0 #define USE_AUTO_SEQUENCE_LEN 0
/// Seeking window default length in milliseconds for algorithm that finds the best possible /// Seeking window default length in milliseconds for algorithm that finds the best possible
/// overlapping location. This determines from how wide window the algorithm may look for an /// overlapping location. This determines from how wide window the algorithm may look for an
/// optimal joining location when mixing the sound sequences back together. /// optimal joining location when mixing the sound sequences back together.
/// ///
/// The bigger this window setting is, the higher the possibility to find a better mixing /// The bigger this window setting is, the higher the possibility to find a better mixing
/// position will become, but at the same time large values may cause a "drifting" artifact /// position will become, but at the same time large values may cause a "drifting" artifact
/// because consequent sequences will be taken at more uneven intervals. /// because consequent sequences will be taken at more uneven intervals.
/// ///
/// If there's a disturbing artifact that sounds as if a constant frequency was drifting /// If there's a disturbing artifact that sounds as if a constant frequency was drifting
/// around, try reducing this setting. /// around, try reducing this setting.
/// ///
/// Increasing this value increases computational burden & vice versa. /// Increasing this value increases computational burden & vice versa.
@ -87,11 +87,11 @@ namespace soundtouch
/// according to tempo setting (recommended) /// according to tempo setting (recommended)
#define USE_AUTO_SEEKWINDOW_LEN 0 #define USE_AUTO_SEEKWINDOW_LEN 0
/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, /// Overlap length in milliseconds. When the chopped sound sequences are mixed back together,
/// to form a continuous sound stream, this parameter defines over how long period the two /// to form a continuous sound stream, this parameter defines over how long period the two
/// consecutive sequences are let to overlap each other. /// consecutive sequences are let to overlap each other.
/// ///
/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting /// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting
/// by a large amount, you might wish to try a smaller value on this. /// by a large amount, you might wish to try a smaller value on this.
/// ///
/// Increasing this value increases computational burden & vice versa. /// Increasing this value increases computational burden & vice versa.
@ -162,27 +162,27 @@ protected:
/// The maximum amount of samples that can be returned at a time is set by /// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function. /// the 'set_returnBuffer_size' function.
void processSamples(); void processSamples();
public: public:
TDStretch(); TDStretch();
virtual ~TDStretch() override; virtual ~TDStretch() override;
/// Operator 'new' is overloaded so that it automatically creates a suitable instance /// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX/SSE/etc-capable CPU available or not. /// depending on if we've a MMX/SSE/etc-capable CPU available or not.
static void *operator new(size_t s); static void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class. /// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct feature set depending on if the CPU /// This function automatically chooses a correct feature set depending on if the CPU
/// supports MMX/SSE/etc extensions. /// supports MMX/SSE/etc extensions.
static TDStretch *newInstance(); static TDStretch *newInstance();
/// Returns the output buffer object /// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; }; FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the input buffer object /// Returns the input buffer object
FIFOSamplePipe *getInput() { return &inputBuffer; }; FIFOSamplePipe *getInput() { return &inputBuffer; };
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
/// tempo, larger faster tempo. /// tempo, larger faster tempo.
void setTempo(double newTempo); void setTempo(double newTempo);
@ -195,7 +195,7 @@ public:
/// Sets the number of channels, 1 = mono, 2 = stereo /// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(int numChannels); void setChannels(int numChannels);
/// Enables/disables the quick position seeking algorithm. Zero to disable, /// Enables/disables the quick position seeking algorithm. Zero to disable,
/// nonzero to enable /// nonzero to enable
void enableQuickSeek(bool enable); void enableQuickSeek(bool enable);
@ -207,7 +207,7 @@ public:
// //
/// 'sampleRate' = sample rate of the sound /// 'sampleRate' = sample rate of the sound
/// 'sequenceMS' = one processing sequence length in milliseconds /// 'sequenceMS' = one processing sequence length in milliseconds
/// 'seekwindowMS' = seeking window length for scanning the best overlapping /// 'seekwindowMS' = seeking window length for scanning the best overlapping
/// position /// position
/// 'overlapMS' = overlapping length /// 'overlapMS' = overlapping length
void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz) void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
@ -217,7 +217,7 @@ public:
); );
/// Get routine control parameters, see setParameters() function. /// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be NULL, in such case corresponding parameter /// Any of the parameters to this function can be nullptr, in such case corresponding parameter
/// value isn't returned. /// value isn't returned.
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const; void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;

View File

@ -2,8 +2,8 @@
/// ///
/// A header file for detecting the Intel MMX instructions set extension. /// A header file for detecting the Intel MMX instructions set extension.
/// ///
/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the /// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
/// routine implementations for x86 Windows, x86 gnu version and non-x86 /// routine implementations for x86 Windows, x86 gnu version and non-x86
/// platforms, respectively. /// platforms, respectively.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen

View File

@ -2,7 +2,7 @@
/// ///
/// Generic version of the x86 CPU extension detection routine. /// Generic version of the x86 CPU extension detection routine.
/// ///
/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' /// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
/// for the Microsoft compiler version. /// for the Microsoft compiler version.
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -86,9 +86,9 @@ uint detectCPUextensions(void)
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
if (_dwDisabledISA == 0xffffffff) return 0; if (_dwDisabledISA == 0xffffffff) return 0;
uint res = 0; uint res = 0;
#if defined(__GNUC__) #if defined(__GNUC__)
// GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support. // GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support.
uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable. uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable.
@ -101,7 +101,7 @@ uint detectCPUextensions(void)
if (edx & bit_SSE2) res = res | SUPPORT_SSE2; if (edx & bit_SSE2) res = res | SUPPORT_SSE2;
#else #else
// Window / VS version of cpuid. Notice that Visual Studio 2005 or later required // Window / VS version of cpuid. Notice that Visual Studio 2005 or later required
// for __cpuid intrinsic support. // for __cpuid intrinsic support.
int reg[4] = {-1}; int reg[4] = {-1};

View File

@ -1,15 +1,15 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// MMX optimized routines. All MMX optimized functions have been gathered into /// MMX optimized routines. All MMX optimized functions have been gathered into
/// this single source code file, regardless to their class or original source /// this single source code file, regardless to their class or original source
/// code file, in order to ease porting the library to other compiler and /// code file, in order to ease porting the library to other compiler and
/// processor platforms. /// processor platforms.
/// ///
/// The MMX-optimizations are programmed using MMX compiler intrinsics that /// The MMX-optimizations are programmed using MMX compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file /// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets. /// should compile with both toolsets.
/// ///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ /// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support compiler intrinsic syntax. The update /// 6.0 processor pack" update to support compiler intrinsic syntax. The update
/// is available for download at Microsoft Developers Network, see here: /// is available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx /// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
@ -68,14 +68,14 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &d
__m64 accu, normaccu; __m64 accu, normaccu;
long corr, norm; long corr, norm;
int i; int i;
pVec1 = (__m64*)pV1; pVec1 = (__m64*)pV1;
pVec2 = (__m64*)pV2; pVec2 = (__m64*)pV2;
shifter = _m_from_int(overlapDividerBitsNorm); shifter = _m_from_int(overlapDividerBitsNorm);
normaccu = accu = _mm_setzero_si64(); normaccu = accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
// during each round for improved CPU-level parallellization. // during each round for improved CPU-level parallellization.
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
@ -126,7 +126,7 @@ double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &d
} }
} }
// 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
dnorm = (double)norm; dnorm = (double)norm;
@ -144,7 +144,7 @@ double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2,
__m64 accu; __m64 accu;
long corr, lnorm; long corr, lnorm;
int i; int i;
// cancel first normalizer tap from previous round // cancel first normalizer tap from previous round
lnorm = 0; lnorm = 0;
for (i = 1; i <= channels; i ++) for (i = 1; i <= channels; i ++)
@ -158,7 +158,7 @@ double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2,
shifter = _m_from_int(overlapDividerBitsNorm); shifter = _m_from_int(overlapDividerBitsNorm);
accu = _mm_setzero_si64(); accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
// during each round for improved CPU-level parallellization. // during each round for improved CPU-level parallellization.
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
@ -203,7 +203,7 @@ double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2,
maxnorm = lnorm; 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
return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm); return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm);
} }
@ -232,7 +232,7 @@ void TDStretchMMX::overlapStereo(short *output, const short *input) const
// mix1 = mixer values for 1st stereo sample // mix1 = mixer values for 1st stereo sample
// mix1 = mixer values for 2nd stereo sample // mix1 = mixer values for 2nd stereo sample
// adder = adder for updating mixer values after each round // adder = adder for updating mixer values after each round
mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
adder = _mm_set_pi16(1, -1, 1, -1); adder = _mm_set_pi16(1, -1, 1, -1);
mix2 = _mm_add_pi16(mix1, adder); mix2 = _mm_add_pi16(mix1, adder);
@ -245,7 +245,7 @@ void TDStretchMMX::overlapStereo(short *output, const short *input) const
for (i = 0; i < overlapLength / 4; i ++) for (i = 0; i < overlapLength / 4; i ++)
{ {
__m64 temp1, temp2; __m64 temp1, temp2;
// load & shuffle data so that input & mixbuffer data samples are paired // load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
@ -294,8 +294,8 @@ void TDStretchMMX::overlapStereo(short *output, const short *input) const
FIRFilterMMX::FIRFilterMMX() : FIRFilter() FIRFilterMMX::FIRFilterMMX() : FIRFilter()
{ {
filterCoeffsAlign = NULL; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = NULL; filterCoeffsUnalign = nullptr;
} }
@ -316,8 +316,8 @@ void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uRe
filterCoeffsUnalign = new short[2 * newLength + 8]; filterCoeffsUnalign = new short[2 * newLength + 8];
filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
// rearrange the filter coefficients for mmx routines // rearrange the filter coefficients for mmx routines
for (i = 0;i < length; i += 4) for (i = 0;i < length; i += 4)
{ {
filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];

View File

@ -1,20 +1,20 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// ///
/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE /// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
/// optimized functions have been gathered into this single source /// optimized functions have been gathered into this single source
/// code file, regardless to their class or original source code file, in order /// code file, regardless to their class or original source code file, in order
/// to ease porting the library to other compiler and processor platforms. /// to ease porting the library to other compiler and processor platforms.
/// ///
/// The SSE-optimizations are programmed using SSE compiler intrinsics that /// The SSE-optimizations are programmed using SSE compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file /// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets. /// should compile with both toolsets.
/// ///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ /// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support SSE instruction set. The update is /// 6.0 processor pack" update to support SSE instruction set. The update is
/// available for download at Microsoft Developers Network, see here: /// available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.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 /// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
/// perform a search with keywords "processor pack". /// perform a search with keywords "processor pack".
/// ///
/// Author : Copyright (c) Olli Parviainen /// Author : Copyright (c) Olli Parviainen
@ -51,7 +51,7 @@ using namespace soundtouch;
#ifdef SOUNDTOUCH_ALLOW_SSE #ifdef SOUNDTOUCH_ALLOW_SSE
// SSE routines available only with float sample type // SSE routines available only with float sample type
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -71,8 +71,8 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &a
const __m128 *pVec2; const __m128 *pVec2;
__m128 vSum, vNorm; __m128 vSum, vNorm;
// Note. It means a major slow-down if the routine needs to tolerate // Note. It means a major slow-down if the routine needs to tolerate
// unaligned __m128 memory accesses. It's way faster if we can skip // unaligned __m128 memory accesses. It's way faster if we can skip
// unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
// This can mean up to ~ 10-fold difference (incl. part of which is // This can mean up to ~ 10-fold difference (incl. part of which is
// due to skipping every second round for stereo sound though). // due to skipping every second round for stereo sound though).
@ -81,7 +81,7 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &a
// for choosing if this little cheating is allowed. // for choosing if this little cheating is allowed.
#ifdef ST_SIMD_AVOID_UNALIGNED #ifdef ST_SIMD_AVOID_UNALIGNED
// Little cheating allowed, return valid correlation only for // Little cheating allowed, return valid correlation only for
// aligned locations, meaning every second round for stereo sound. // aligned locations, meaning every second round for stereo sound.
#define _MM_LOAD _mm_load_ps #define _MM_LOAD _mm_load_ps
@ -92,7 +92,7 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &a
// No cheating allowed, use unaligned load & take the resulting // No cheating allowed, use unaligned load & take the resulting
// performance hit. // performance hit.
#define _MM_LOAD _mm_loadu_ps #define _MM_LOAD _mm_loadu_ps
#endif #endif
// ensure overlapLength is divisible by 8 // ensure overlapLength is divisible by 8
assert((overlapLength % 8) == 0); assert((overlapLength % 8) == 0);
@ -105,7 +105,7 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &a
// Unroll the loop by factor of 4 * 4 operations. Use same routine for // Unroll the loop by factor of 4 * 4 operations. Use same routine for
// stereo & mono, for mono it just means twice the amount of unrolling. // stereo & mono, for mono it just means twice the amount of unrolling.
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
__m128 vTemp; __m128 vTemp;
// vSum += pV1[0..3] * pV2[0..3] // vSum += pV1[0..3] * pV2[0..3]
@ -146,7 +146,7 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &a
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
corr = norm = 0.0; corr = norm = 0.0;
for (i = 0; i < channels * overlapLength / 16; i ++) for (i = 0; i < channels * overlapLength / 16; i ++)
{ {
corr += pV1[0] * pV2[0] + corr += pV1[0] * pV2[0] +
pV1[1] * pV2[1] + pV1[1] * pV2[1] +
@ -178,8 +178,8 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &a
double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm) double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm)
{ {
// call usual calcCrossCorr function because SSE does not show big benefit of // call usual calcCrossCorr function because SSE does not show big benefit of
// accumulating "norm" value, and also the "norm" rolling algorithm would get // accumulating "norm" value, and also the "norm" rolling algorithm would get
// complicated due to SSE-specific alignment-vs-nonexact correlation rules. // complicated due to SSE-specific alignment-vs-nonexact correlation rules.
return calcCrossCorr(pV1, pV2, norm); return calcCrossCorr(pV1, pV2, norm);
} }
@ -195,16 +195,16 @@ double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2,
FIRFilterSSE::FIRFilterSSE() : FIRFilter() FIRFilterSSE::FIRFilterSSE() : FIRFilter()
{ {
filterCoeffsAlign = NULL; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = NULL; filterCoeffsUnalign = nullptr;
} }
FIRFilterSSE::~FIRFilterSSE() FIRFilterSSE::~FIRFilterSSE()
{ {
delete[] filterCoeffsUnalign; delete[] filterCoeffsUnalign;
filterCoeffsAlign = NULL; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = NULL; filterCoeffsUnalign = nullptr;
} }
@ -225,7 +225,7 @@ void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uRe
fDivider = (float)resultDivider; fDivider = (float)resultDivider;
// rearrange the filter coefficients for mmx routines // rearrange the filter coefficients for mmx routines
for (i = 0; i < newLength; i ++) for (i = 0; i < newLength; i ++)
{ {
filterCoeffsAlign[2 * i + 0] = filterCoeffsAlign[2 * i + 0] =
@ -245,10 +245,10 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n
if (count < 2) return 0; if (count < 2) return 0;
assert(source != NULL); assert(source != nullptr);
assert(dest != NULL); assert(dest != nullptr);
assert((length % 8) == 0); assert((length % 8) == 0);
assert(filterCoeffsAlign != NULL); assert(filterCoeffsAlign != nullptr);
assert(((ulongptr)filterCoeffsAlign) % 16 == 0); assert(((ulongptr)filterCoeffsAlign) % 16 == 0);
// filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
@ -263,13 +263,13 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n
pSrc = (const float*)source + j * 2; // source audio data pSrc = (const float*)source + j * 2; // source audio data
pDest = dest + j * 2; // destination audio data pDest = dest + j * 2; // destination audio data
pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
// are aligned to 16-byte boundary // are aligned to 16-byte boundary
sum1 = sum2 = _mm_setzero_ps(); sum1 = sum2 = _mm_setzero_ps();
for (i = 0; i < length / 8; i ++) for (i = 0; i < length / 8; i ++)
{ {
// Unroll loop for efficiency & calculate filter for 2*2 stereo samples // Unroll loop for efficiency & calculate filter for 2*2 stereo samples
// at each pass // at each pass
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
@ -302,14 +302,14 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n
} }
// Ideas for further improvement: // Ideas for further improvement:
// 1. If it could be guaranteed that 'source' were always aligned to 16-byte // 1. If it could be guaranteed that 'source' were always aligned to 16-byte
// boundary, a faster aligned '_mm_load_ps' instruction could be used. // boundary, a faster aligned '_mm_load_ps' instruction could be used.
// 2. If it could be guaranteed that 'dest' were always aligned to 16-byte // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
// boundary, a faster '_mm_store_ps' instruction could be used. // boundary, a faster '_mm_store_ps' instruction could be used.
return (uint)count; return (uint)count;
/* original routine in C-language. please notice the C-version has differently /* original routine in C-language. please notice the C-version has differently
organized coefficients though. organized coefficients though.
double suml1, suml2; double suml1, suml2;
double sumr1, sumr2; double sumr1, sumr2;
@ -324,26 +324,26 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n
suml2 = sumr2 = 0.0; suml2 = sumr2 = 0.0;
ptr = src; ptr = src;
pFil = filterCoeffs; pFil = filterCoeffs;
for (i = 0; i < lengthLocal; i ++) for (i = 0; i < lengthLocal; i ++)
{ {
// unroll loop for efficiency. // unroll loop for efficiency.
suml1 += ptr[0] * pFil[0] + suml1 += ptr[0] * pFil[0] +
ptr[2] * pFil[2] + ptr[2] * pFil[2] +
ptr[4] * pFil[4] + ptr[4] * pFil[4] +
ptr[6] * pFil[6]; ptr[6] * pFil[6];
sumr1 += ptr[1] * pFil[1] + sumr1 += ptr[1] * pFil[1] +
ptr[3] * pFil[3] + ptr[3] * pFil[3] +
ptr[5] * pFil[5] + ptr[5] * pFil[5] +
ptr[7] * pFil[7]; ptr[7] * pFil[7];
suml2 += ptr[8] * pFil[0] + suml2 += ptr[8] * pFil[0] +
ptr[10] * pFil[2] + ptr[10] * pFil[2] +
ptr[12] * pFil[4] + ptr[12] * pFil[4] +
ptr[14] * pFil[6]; ptr[14] * pFil[6];
sumr2 += ptr[9] * pFil[1] + sumr2 += ptr[9] * pFil[1] +
ptr[11] * pFil[3] + ptr[11] * pFil[3] +
ptr[13] * pFil[5] + ptr[13] * pFil[5] +
ptr[15] * pFil[7]; ptr[15] * pFil[7];