3rdparty:soundtouch: Upgrade SoundTouch lib to 2.1.2. (#2787)

This commit is contained in:
Christian Kenny 2019-02-02 11:50:38 -05:00 committed by lightningterror
parent 1ae48db873
commit f25fe48c9b
32 changed files with 638 additions and 508 deletions

View File

@ -455,4 +455,4 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS

View File

@ -8,13 +8,14 @@
<meta name="author" content="Olli Parviainen">
<meta name="description"
content="Readme file for SoundTouch audio processing library">
<style> <!-- .normal { font-family: Arial }
--></style>
<style>
body {font-family: Arial, Helvetica; }
</style>
</head>
<body class="normal">
<hr>
<h1>SoundTouch audio processing library v1.9.2</h1>
<p class="normal">SoundTouch library Copyright © Olli Parviainen 2001-2015</p>
<h1>SoundTouch audio processing library v2.1.2</h1>
<p class="normal">SoundTouch library Copyright &copy; Olli Parviainen 2001-2018</p>
<hr>
<h2>1. Introduction </h2>
<p>SoundTouch is an open-source audio processing library that allows
@ -32,6 +33,7 @@ same time</li>
<h3>1.1 Contact information </h3>
<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 git repository: <a href="https://gitlab.com/soundtouch/soundtouch.git">https://gitlab.com/soundtouch/soundtouch.git</a></p>
<hr>
<h2>2. Compiling SoundTouch</h2>
<p>Before compiling, notice that you can choose the sample data format if it's
@ -55,6 +57,9 @@ instead of the make-win.bat script, directories bin and lib may need to
be created manually to the SoundTouch package root for the final
executables. The make-win.bat script creates these directories
automatically. </p>
<p><strong>C# example</strong>: The source code package includes also a C# example
application for Windows that shows how to invoke SoundTouch.dll
dynamic-load library for processing mp3 audio.
<p><strong>OpenMP NOTE</strong>: If activating the OpenMP parallel computing in
the compilation, the target program will require additional vcomp dll library to
properly run. In Visual C++ 9.0 these libraries can be found in the following
@ -120,7 +125,7 @@ destination locations.</p>
</tr>
</tbody>
</table>
<h4><b>2.2.1 Required GNU tools</b>&nbsp;</h4>
<h4><b>2.2.1 Required GNU tools</b></h4>
<p> <span style="font-weight: bold;">Bash shell</span>, <span
style="font-weight: bold;">GNU C++ compiler</span>, <span
style="font-weight: bold;">libtool</span>, <span
@ -156,7 +161,7 @@ directly and remove the following definition:<blockquote>
sstrip SoundTouch.dll</pre>
</blockquote>
<h3>2.1. Building in Android</h3>
<h3>2.3. Building in Android</h3>
<p>Android compilation instructions are within the
source code package, see file &quot;<b>source/Android-lib/README-SoundTouch-Android.html</b>&quot;
in the source code package. </p>
@ -219,7 +224,7 @@ as combination of two primary effects, <em>sample rate transposing</em>
and <em>time-stretching</em>.</p>
<p><em>Sample rate transposing</em> affects both the audio stream
duration and pitch. It's implemented simply by converting the original
audio sample stream to the&nbsp; desired duration by interpolating from
audio sample stream to the desired duration by interpolating from
the original audio samples. In SoundTouch, linear interpolation with
anti-alias filtering is used. Theoretically a higher-order
interpolation provide better result than 1st order linear
@ -268,7 +273,7 @@ length of a single processing sequence in milliseconds which determines
the how the original sound is chopped in the time-stretch algorithm.
Larger values mean fewer sequences are used in processing. In principle
a larger value sounds better when slowing down the tempo, but worse
when increasing the tempo and vice versa.&nbsp;<br>
when increasing the tempo and vice versa.<br>
<br>
By default, this setting value is calculated automatically according to
tempo value.<br>
@ -277,7 +282,7 @@ tempo value.<br>
default length in milliseconds is for the algorithm that seeks the best
possible overlapping location. This determines from how wide a sample
"window" the algorithm can use to find an optimal mixing location when
the sound sequences are to be linked back together.&nbsp;<br>
the sound sequences are to be linked back together.<br>
<br>
The bigger this window setting is, the higher the possibility to find a
better mixing position becomes, but at the same time large values may
@ -345,7 +350,7 @@ computation burden</td>
</td>
<td valign="top">Default value is relatively large, chosen to
suit with above parameters.</td>
<td valign="top">&nbsp;</td>
<td valign="top"></td>
<td valign="top">If you reduce the "sequence ms" setting, you
might wish to try a smaller value.</td>
<td valign="top">Increasing the parameter value increases
@ -358,7 +363,7 @@ computation burden</td>
<p>The time-stretch routine has a 'quick' mode that substantially
speeds up the algorithm but may slightly compromise the sound quality.
This mode is activated by calling SoundTouch::setSetting()
function with parameter&nbsp; id of SETTING_USE_QUICKSEEK and value
function with parameter id of SETTING_USE_QUICKSEEK and value
"1", i.e. </p>
<blockquote>
<p>setSetting(SETTING_USE_QUICKSEEK, 1);</p>
@ -377,7 +382,10 @@ processors vs. non-SIMD implementation:</p>
<p>SoundTouch 1.9 onwards support running the algorithms parallel in several CPU
cores. Based on benchmark the experienced multi-core processing speed-up gain
ranges between +30% (on a high-spec dual-core x86 Windows PC) to 215% (on a moderately low-spec
quad-core ARM of Raspberry Pi2).</p>
quad-core ARM of Raspberry Pi2). </p>
<p>See an external blog article with more detailed discussion about the
<a href="http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices/">
SoundTouch OpenMP optimization</a>.</p>
<p>The parallel computing support is implemented using OpenMP spec 3.0
instructions. These instructions are supported by Visual C++ 2008 and later, and
GCC v4.2 and later. Compilers that do not supporting OpenMP will ignore these
@ -439,13 +447,13 @@ file format). Give "stdin" as filename to use standard input pipe. </td>
</td>
<td valign="top">Name of the output sound file where the
resulting sound is saved (in .WAV audio file format). This parameter
may be omitted if you&nbsp; don't want to save the output (e.g. when
may be omitted if you don't want to save the output (e.g. when
only calculating BPM rate with '-bpm' switch). Give "stdout" as
filename to use standard output pipe.</td>
</tr>
<tr>
<td valign="top">
<pre>&nbsp;[switches]</pre>
<pre>[switches]</pre>
</td>
<td valign="top">Are one or more control switches.</td>
</tr>
@ -567,6 +575,41 @@ this corresponds to lowering the pitch by -0.318 semitones:</p>
<hr>
<h2>5. Change History</h2>
<h3>5.1. SoundTouch library Change History </h3>
<p><b>2.1.2:</b></p>
<ul>
<li>Bump version to 2.1.2 also in configure.ac. The earlier release had old version info for GNU autotools.</li>
</ul>
<p><b>2.1.1:</b></p>
<ul>
<li>Bugfixes: Fixed potential buffer overwrite bugs in WavFile routines. Replaced asserts with runtime exceptions.</li>
<li>Android: Migrated the SoundTouch Android example to new Android Studio</li>
<li>Automake: unset ACLOCAL in bootstrap script in case earlier build script has set it</li>
</ul>
<p><b>2.1:</b></p>
<ul>
<li>Refactored C# interface example</li>
<li>Disable anti-alias filter when switch
SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER defined because anti-alias
filter cause slight click if the rate change crosses zero during
processing</li>
<li>Added script for building SoundTouchDll dynamic-link-library for GNU platforms</li>
<li>Rewrote Beats-per-Minute analysis algorithm for more reliable BPM detection</li>
<li>Added BPM functions to SoundTouchDll API</li>
<li>Migrated Visual Studio project files to MSVC 201x format</li>
<li>Replaced function parameter value asserts with runtime exceptions</li>
<li>Code maintenance & style cleanup</li>
</ul>
<p><b>2.0:</b></p>
<ul>
<li>Added functions to get initial processing latency, duration ratio between the original input and processed output tracks, and clarified reporting of input/output batch sizes</li>
<li>Fixed issue that added brief sequence of silence to beginning of output audio</li>
<li>Adjusted algorithm parameters to reduce reverberating effect at tempo slowdown</li>
<li>Bugfix: Fixed a glitch that could cause negative array indexing in quick seek algorithm</li>
<li>Bugfix: flush() didn't properly flush final samples from the pipeline on 2nd time in case that soundtouch object instance was recycled and used for processing a second audio stream.</li>
<li>Bugfix: Pi value had incorrect 9th/10th decimals</li>
<li>Added C# example application that uses SoundTouch dll library for processing MP3 files</li>
</ul>
<p><b>1.9.2:</b></p>
<ul>
<li>Fix in GNU package configuration</li>
@ -575,8 +618,8 @@ this corresponds to lowering the pitch by -0.318 semitones:</p>
<ul>
<li>Improved SoundTouch::flush() function so that it returns precisely the desired amount of samples for exact output duration control</li>
<li>Redesigned quickseek algorithm for improved sound quality when using the quickseek mode. The new quickseek algorithm can find 99% as good results as the
default full-scan mode, while the quickseek algorithm is remarkable less
CPU intensive.</li>
default full-scan mode, while the quickseek algorithm is remarkable less
CPU intensive.</li>
<li>Added adaptive integer divider scaling for improved sound quality when using integer processing algorithm
</li>
</ul>
@ -647,13 +690,13 @@ sample batch sizes</li>
<ul>
<li> Added normalization to correlation calculation and improvement
automatic seek/sequence parameter calculation to improve sound quality</li>
<li> Bugfixes:&nbsp;
<li> Bugfixes:
<ul>
<li> Fixed negative array indexing in quick seek algorithm</li>
<li> FIR autoalias filter running too far in processing buffer</li>
<li> Check against zero sample count in rate transposing</li>
<li> Fix for x86-64 support: Removed pop/push instructions from
the cpu detection algorithm.&nbsp;</li>
the cpu detection algorithm.</li>
<li> Check against empty buffers in FIFOSampleBuffer</li>
<li> Other minor fixes &amp; code cleanup</li>
</ul>
@ -669,7 +712,7 @@ negative side or vice versa</li>
<p><strong>1.4.1:</strong></p>
<ul>
<li> Fixed a buffer overflow bug in BPM detect algorithm routines if
processing more than 2048 samples at one call&nbsp;</li>
processing more than 2048 samples at one call</li>
</ul>
<p><strong>1.4.0:</strong></p>
<ul>
@ -752,7 +795,6 @@ accessing the FIFOSampleBuffer class from external files.</li>
<ul>
<li> Initial release</li>
</ul>
<p>&nbsp;</p>
<h3>5.2. SoundStretch application Change History </h3>
<p><b>1.9:</b></p>
<ul>
@ -819,10 +861,12 @@ switch "-bpm"</li>
<p>Kudos for these people who have contributed to development or
submitted bugfixes:</p>
<ul>
<li> Arthur A</li>
<li> Arthur A</li>
<li> Paul Adenot</li>
<li> Richard Ash</li>
<li> Stanislav Brabec</li>
<li> Christian Budde</li>
<li> Jamie Bullock</li>
<li> Chris Bryan</li>
<li> Jacek Caban</li>
<li> Brian Cameron</li>
@ -830,25 +874,35 @@ submitted bugfixes:</p>
<li> David Clark</li>
<li> Patrick Colis</li>
<li> Miquel Colon</li>
<li> Jim Credland</li>
<li> Jim Credland</li>
<li> Sandro Cumerlato</li>
<li> Gerry Fan</li>
<li> Justin Frankel</li>
<li> Masa H.</li>
<li> Masa H.</li>
<li> Jason Garland</li>
<li> Takashi Iwai</li>
<li> Thomas Klausner</li>
<li> Mathias Möhl</li>
<li> Thomas Klausner</li>
<li> Lu Zhihe</li>
<li> Luzpaz</li>
<li> Tony Mechelynck </li>
<li> Mathias M&ouml;hl</li>
<li> Yuval Naveh</li>
<li> Mats Palmgren </li>
<li> Chandni Patel</li>
<li> Paulo Pizarro</li>
<li> Andrey Ponomarenko</li>
<li> Blaise Potard</li>
<li> Michael Pruett</li>
<li> Michael Pruett</li>
<li> Rajeev Puran</li>
<li> RJ Ryan</li>
<li> John Sheehy</li>
<li> RJ Ryan</li>
<li> John Sheehy</li>
<li> Tim Shuttleworth</li>
<li> Albert Sirvent</li>
<li> Tyson Smith</li>
<li> John Stumpo</li>
<li> Mario di Vece</li>
<li> Katja Vetter</li>
<li> Wu Q.</li>
</ul>
<p>Moral greetings to all other contributors and users also!</p>
<hr>
@ -865,10 +919,9 @@ General Public License for more details.</p>
<p>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</p>
<hr><!--
$Id: README.html 230 2015-09-20 07:38:32Z oparviai $
-->
<p>
<i>README.html file updated in Sep-2015</i></p>
<p>---</p>
<p>commercial license alternative also available, contact author for details.</p>
<hr>
<p><i>README.html file updated in November-2018</i></p>
</body>
</html>

View File

@ -26,13 +26,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2016-01-12 19:24:46 +0200 (ti, 12 tammi 2016) $
// File revision : $Revision: 4 $
//
// $Id: BPMDetect.h 239 2016-01-12 17:24:46Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -57,102 +50,156 @@
#ifndef _BPMDetect_H_
#define _BPMDetect_H_
#include <vector>
#include "STTypes.h"
#include "FIFOSampleBuffer.h"
namespace soundtouch
{
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
#define MIN_BPM 29
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
#define MIN_BPM 45
/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
#define MAX_BPM 200
/// Maximum allowed BPM rate range. Used for calculating algorithm parametrs
#define MAX_BPM_RANGE 200
/// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit.
#define MAX_BPM_VALID 190
////////////////////////////////////////////////////////////////////////////////
typedef struct
{
float pos;
float strength;
} BEAT;
/// Class for calculating BPM rate for audio data.
class BPMDetect
{
protected:
/// Auto-correlation accumulator bins.
float *xcorr;
/// Sample average counter.
int decimateCount;
class IIR2_filter
{
double coeffs[5];
double prev[5];
/// Sample average accumulator for FIFO-like decimation.
soundtouch::LONG_SAMPLETYPE decimateSum;
/// Decimate sound by this coefficient to reach approx. 500 Hz.
int decimateBy;
/// Auto-correlation window length
int windowLen;
/// Number of channels (1 = mono, 2 = stereo)
int channels;
/// sample rate
int sampleRate;
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for
/// the first these many correlation bins.
int windowStart;
/// FIFO-buffer for decimated processing samples.
soundtouch::FIFOSampleBuffer *buffer;
/// Updates auto-correlation function for given number of decimated samples that
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
/// though).
void updateXCorr(int process_samples /// How many samples are processed.
);
/// Decimates samples to approx. 500 Hz.
///
/// \return Number of output samples.
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
int numsamples ///< Number of source samples.
);
/// Calculates amplitude envelope for the buffer of samples.
/// Result is output to 'samples'.
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
int numsamples ///< Number of samples in buffer
);
/// remove constant bias from xcorr data
void removeBias();
public:
/// Constructor.
BPMDetect(int numChannels, ///< Number of channels in sample data.
int sampleRate ///< Sample rate in Hz.
);
/// Destructor.
virtual ~BPMDetect();
/// Inputs a block of samples for analyzing: Envelopes the samples and then
/// updates the autocorrelation estimation. When whole song data has been input
/// in smaller blocks using this function, read the resulting bpm with 'getBpm'
/// function.
///
/// Notice that data in 'samples' array can be disrupted in processing.
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
int numSamples ///< Number of samples in buffer
);
public:
IIR2_filter(const double *lpf_coeffs);
float update(float x);
};
/// Analyzes the results and returns the BPM rate. Use this function to read result
/// after whole song data has been input to the class by consecutive calls of
/// 'inputSamples' function.
///
/// \return Beats-per-minute rate, or zero if detection failed.
float getBpm();
};
/// Class for calculating BPM rate for audio data.
class BPMDetect
{
protected:
/// Auto-correlation accumulator bins.
float *xcorr;
/// Sample average counter.
int decimateCount;
/// Sample average accumulator for FIFO-like decimation.
soundtouch::LONG_SAMPLETYPE decimateSum;
/// Decimate sound by this coefficient to reach approx. 500 Hz.
int decimateBy;
/// Auto-correlation window length
int windowLen;
/// Number of channels (1 = mono, 2 = stereo)
int channels;
/// sample rate
int sampleRate;
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for
/// the first these many correlation bins.
int windowStart;
/// window functions for data preconditioning
float *hamw;
float *hamw2;
// beat detection variables
int pos;
int peakPos;
int beatcorr_ringbuffpos;
int init_scaler;
float peakVal;
float *beatcorr_ringbuff;
/// FIFO-buffer for decimated processing samples.
soundtouch::FIFOSampleBuffer *buffer;
/// Collection of detected beat positions
//BeatCollection beats;
std::vector<BEAT> beats;
// 2nd order low-pass-filter
IIR2_filter beat_lpf;
/// Updates auto-correlation function for given number of decimated samples that
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
/// though).
void updateXCorr(int process_samples /// How many samples are processed.
);
/// Decimates samples to approx. 500 Hz.
///
/// \return Number of output samples.
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
int numsamples ///< Number of source samples.
);
/// Calculates amplitude envelope for the buffer of samples.
/// Result is output to 'samples'.
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
int numsamples ///< Number of samples in buffer
);
/// remove constant bias from xcorr data
void removeBias();
// Detect individual beat positions
void updateBeatPos(int process_samples);
public:
/// Constructor.
BPMDetect(int numChannels, ///< Number of channels in sample data.
int sampleRate ///< Sample rate in Hz.
);
/// Destructor.
virtual ~BPMDetect();
/// Inputs a block of samples for analyzing: Envelopes the samples and then
/// updates the autocorrelation estimation. When whole song data has been input
/// in smaller blocks using this function, read the resulting bpm with 'getBpm'
/// function.
///
/// Notice that data in 'samples' array can be disrupted in processing.
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
int numSamples ///< Number of samples in buffer
);
/// Analyzes the results and returns the BPM rate. Use this function to read result
/// after whole song data has been input to the class by consecutive calls of
/// 'inputSamples' function.
///
/// \return Beats-per-minute rate, or zero if detection failed.
float getBpm();
/// 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.
/// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths
/// - 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".
///
/// \return number of beats in the arrays.
int getBeats(float *pos, float *strength, int max_num);
};
}
#endif // _BPMDetect_H_

View File

@ -15,13 +15,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2014-01-05 23:40:22 +0200 (su, 05 tammi 2014) $
// File revision : $Revision: 4 $
//
// $Id: FIFOSampleBuffer.h 177 2014-01-05 21:40:22Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -119,7 +112,7 @@ public:
/// 'putSamples(numSamples)' function.
SAMPLETYPE *ptrEnd(
uint slackCapacity ///< How much free capacity (in samples) there _at least_
///< should be so that the caller can succesfully insert the
///< should be so that the caller can successfully insert the
///< desired samples to the buffer. If necessary, the function
///< grows the buffer size to comply with this requirement.
);

View File

@ -17,13 +17,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2012-06-13 22:29:53 +0300 (ke, 13 kesä 2012) $
// File revision : $Revision: 4 $
//
// $Id: FIFOSamplePipe.h 143 2012-06-13 19:29:53Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -58,6 +51,18 @@ namespace soundtouch
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
class FIFOSamplePipe
{
protected:
bool verifyNumberOfChannels(int nChannels) const
{
if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS))
{
return true;
}
ST_THROW_RT_ERROR("Error: Illegal number of channels");
return false;
}
public:
// virtual default destructor
virtual ~FIFOSamplePipe() {}
@ -122,7 +127,6 @@ public:
};
/// Base-class for sound processing routines working in FIFO principle. With this base
/// class it's easy to implement sound processing stages that can be chained together,
/// so that samples that are fed into beginning of the pipe automatically go through
@ -145,7 +149,6 @@ protected:
output = pOutput;
}
/// Constructor. Doesn't define output pipe; it has to be set be
/// 'setOutPipe' function.
FIFOProcessor()
@ -153,7 +156,6 @@ protected:
output = NULL;
}
/// Constructor. Configures output pipe.
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
)
@ -161,13 +163,11 @@ protected:
output = pOutput;
}
/// Destructor.
virtual ~FIFOProcessor()
{
}
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
@ -194,7 +194,6 @@ public:
return output->receiveSamples(outBuffer, maxSamples);
}
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
@ -206,14 +205,12 @@ public:
return output->receiveSamples(maxSamples);
}
/// Returns number of samples currently available.
virtual uint numSamples() const
{
return output->numSamples();
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const
{
@ -226,7 +223,6 @@ public:
{
return output->adjustAmountOfSamples(numSamples);
}
};
}

View File

@ -8,13 +8,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2017-07-30 12:28:06 +0300 (su, 30 heinä 2017) $
// File revision : $Revision: 3 $
//
// $Id: STTypes.h 252 2017-07-30 09:28:06Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -63,6 +56,9 @@ typedef unsigned long ulong;
namespace soundtouch
{
/// Max allowed number of channels
#define SOUNDTOUCH_MAX_CHANNELS 16
/// Activate these undef's to overrule the possible sampletype
/// setting inherited from some other header file:
//#undef SOUNDTOUCH_INTEGER_SAMPLES

View File

@ -41,13 +41,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2017-07-30 12:35:00 +0300 (su, 30 heinä 2017) $
// File revision : $Revision: 4 $
//
// $Id: SoundTouch.h 253 2017-07-30 09:35:00Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -79,10 +72,10 @@ namespace soundtouch
{
/// Soundtouch library version string
#define SOUNDTOUCH_VERSION "2.0.0"
#define SOUNDTOUCH_VERSION "2.1.2"
/// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (20000)
#define SOUNDTOUCH_VERSION_ID (20102)
//
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
@ -320,7 +313,7 @@ public:
/// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
///
/// \return 'true' if the setting was succesfully changed
/// \return 'true' if the setting was successfully changed
bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
int value ///< New setting value.
);

View File

@ -17,13 +17,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2014-10-05 19:20:24 +0300 (su, 05 loka 2014) $
// File revision : $Revision: 4 $
//
// $Id: WavFile.cpp 200 2014-10-05 16:20:24Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -63,7 +56,6 @@ static const char fmtStr[] = "fmt ";
static const char factStr[] = "fact";
static const char dataStr[] = "data";
//////////////////////////////////////////////////////////////////////////////
//
// Helper functions for swapping byte order to correctly read/write WAV files
@ -222,23 +214,23 @@ void WavInFile::init()
if (hdrsOk != 0)
{
// Something didn't match in the wav file headers
string msg = "Input file is corrupt or not a WAV file";
ST_THROW_RT_ERROR(msg.c_str());
ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file");
}
/* Ignore 'fixed' field value as 32bit signed linear data can have other value than 1.
if (header.format.fixed != 1)
// sanity check for format parameters
if ((header.format.channel_number < 1) || (header.format.channel_number > 9) ||
(header.format.sample_rate < 4000) || (header.format.sample_rate > 192000) ||
(header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) ||
(header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32))
{
string msg = "Input file uses unsupported encoding.";
ST_THROW_RT_ERROR(msg.c_str());
// Something didn't match in the wav file headers
ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters.");
}
*/
dataRead = 0;
}
WavInFile::~WavInFile()
{
if (fptr) fclose(fptr);
@ -246,7 +238,6 @@ WavInFile::~WavInFile()
}
void WavInFile::rewind()
{
int hdrsOk;
@ -463,7 +454,6 @@ int WavInFile::eof() const
}
// test if character code is between a white space ' ' and little 'z'
static int isAlpha(char c)
{
@ -504,8 +494,6 @@ int WavInFile::readRIFFBlock()
}
int WavInFile::readHeaderBlock()
{
char label[5];
@ -528,12 +516,16 @@ int WavInFile::readHeaderBlock()
// read length of the format field
if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap32(nLen); // int format_len;
header.format.format_len = nLen;
_swap32(nLen);
// calculate how much length differs from expected
// calculate how much length differs from expected
nDump = nLen - ((int)sizeof(header.format) - 8);
// verify that header length isn't smaller than expected structure
if ((nLen < 0) || (nDump < 0)) return -1;
header.format.format_len = nLen;
// if format_len is larger than expected, read only as much data as we've space for
if (nDump > 0)
{
@ -544,12 +536,12 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap16(header.format.fixed); // short int fixed;
_swap16(header.format.channel_number); // short int channel_number;
_swap32((int &)header.format.sample_rate); // int sample_rate;
_swap32((int &)header.format.byte_rate); // int byte_rate;
_swap16(header.format.byte_per_sample); // short int byte_per_sample;
_swap16(header.format.bits_per_sample); // short int bits_per_sample;
_swap16((short &)header.format.fixed); // short int fixed;
_swap16((short &)header.format.channel_number); // short int channel_number;
_swap32((int &)header.format.sample_rate); // int sample_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.bits_per_sample); // short int bits_per_sample;
// if format_len is larger than expected, skip the extra data
if (nDump > 0)
@ -569,12 +561,16 @@ int WavInFile::readHeaderBlock()
// read length of the fact field
if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
// swap byte order if necessary
_swap32(nLen); // int fact_len;
header.fact.fact_len = nLen;
_swap32(nLen);
// calculate how much length differs from expected
nDump = nLen - ((int)sizeof(header.fact) - 8);
// verify that fact length isn't smaller than expected structure
if ((nLen < 0) || (nDump < 0)) return -1;
header.fact.fact_len = nLen;
// if format_len is larger than expected, read only as much data as we've space for
if (nDump > 0)
{
@ -669,7 +665,6 @@ uint WavInFile::getSampleRate() const
}
uint WavInFile::getDataSizeInBytes() const
{
return header.data.data_len;
@ -703,7 +698,6 @@ uint WavInFile::getElapsedMS() const
}
//////////////////////////////////////////////////////////////////////////////
//
// Class WavOutFile
@ -742,7 +736,6 @@ WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels)
}
WavOutFile::~WavOutFile()
{
finishHeader();
@ -751,7 +744,6 @@ WavOutFile::~WavOutFile()
}
void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
{
// fill in the 'riff' part..
@ -779,8 +771,8 @@ void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
// fill in the 'fact' part...
memcpy(&(header.fact.fact_field), factStr, 4);
header.fact.fact_len = 4;
header.fact.fact_sample_len = 0;
header.fact.fact_len = 4;
header.fact.fact_sample_len = 0;
// fill in the 'data' part..
@ -796,13 +788,12 @@ void WavOutFile::finishHeader()
// supplement the file length into the header structure
header.riff.package_len = bytesWritten + sizeof(WavHeader) - sizeof(WavRiff) + 4;
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();
}
void WavOutFile::writeHeader()
{
WavHeader hdrTemp;
@ -835,7 +826,6 @@ void WavOutFile::writeHeader()
}
void WavOutFile::write(const unsigned char *buffer, int numElems)
{
int res;
@ -856,7 +846,6 @@ void WavOutFile::write(const unsigned char *buffer, int numElems)
}
void WavOutFile::write(const short *buffer, int numElems)
{
int res;
@ -935,7 +924,7 @@ void WavOutFile::write(const float *buffer, int numElems)
bytesPerSample = header.format.bits_per_sample / 8;
numBytes = numElems * bytesPerSample;
short *temp = (short*)getConvBuffer(numBytes);
void *temp = getConvBuffer(numBytes + 7); // round bit up to avoid buffer overrun with 24bit-value assignment
switch (bytesPerSample)
{

View File

@ -16,13 +16,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2014-10-05 19:20:24 +0300 (su, 05 loka 2014) $
// File revision : $Revision: 4 $
//
// $Id: WavFile.h 200 2014-10-05 16:20:24Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -58,7 +51,7 @@ typedef unsigned int uint;
typedef struct
{
char riff_char[4];
int package_len;
uint package_len;
char wave[4];
} WavRiff;
@ -66,21 +59,21 @@ typedef struct
typedef struct
{
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
unsigned int format_len;
unsigned short fixed;
unsigned short channel_number;
unsigned int sample_rate;
unsigned int byte_rate;
unsigned short byte_per_sample;
unsigned short bits_per_sample;
} WavFormat;
/// WAV audio file 'fact' section header
typedef struct
{
char fact_field[4];
int fact_len;
uint fact_sample_len;
char fact_field[4];
uint fact_len;
uint fact_sample_len;
} WavFact;
/// WAV audio file 'data' section header
@ -225,7 +218,6 @@ public:
};
/// Class for writing WAV audio files.
class WavOutFile : protected WavFileBase
{

View File

@ -12,13 +12,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2016-01-12 19:26:21 +0200 (ti, 12 tammi 2016) $
// File revision : $Revision: 4 $
//
// $Id: AAFilter.cpp 240 2016-01-12 17:26:21Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -75,7 +68,6 @@ using namespace soundtouch;
#define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
#endif
/*****************************************************************************
*
* Implementation of the class 'AAFilter'
@ -90,14 +82,12 @@ AAFilter::AAFilter(uint len)
}
AAFilter::~AAFilter()
{
delete pFIR;
}
// Sets new anti-alias filter cut-off edge frequency, scaled to
// sampling frequency (nyquist frequency = 0.5).
// The filter will cut frequencies higher than the given frequency.
@ -108,7 +98,6 @@ void AAFilter::setCutoffFreq(double newCutoffFreq)
}
// Sets number of FIR filter taps
void AAFilter::setLength(uint newLength)
{
@ -117,7 +106,6 @@ void AAFilter::setLength(uint newLength)
}
// Calculates coefficients for a low-pass FIR filter using Hamming window
void AAFilter::calculateCoeffs()
{
@ -177,12 +165,10 @@ void AAFilter::calculateCoeffs()
for (i = 0; i < length; i ++)
{
temp = work[i] * scaleCoeff;
//#if SOUNDTOUCH_INTEGER_SAMPLES
// scale & round to nearest integer
temp += (temp >= 0) ? 0.5 : -0.5;
// ensure no overfloods
assert(temp >= -32768 && temp <= 32767);
//#endif
coeffs[i] = (SAMPLETYPE)temp;
}

View File

@ -13,13 +13,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2014-01-07 21:41:23 +0200 (ti, 07 tammi 2014) $
// File revision : $Revision: 4 $
//
// $Id: AAFilter.h 187 2014-01-07 19:41:23Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -26,13 +26,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2016-01-05 22:59:57 +0200 (ti, 05 tammi 2016) $
// File revision : $Revision: 4 $
//
// $Id: BPMDetect.cpp 237 2016-01-05 20:59:57Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -54,50 +47,62 @@
//
////////////////////////////////////////////////////////////////////////////////
#define _USE_MATH_DEFINES
#include <math.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <cfloat>
#include "FIFOSampleBuffer.h"
#include "PeakFinder.h"
#include "BPMDetect.h"
using namespace soundtouch;
#define INPUT_BLOCK_SAMPLES 2048
#define DECIMATED_BLOCK_SAMPLES 256
// algorithm input sample block size
static const int INPUT_BLOCK_SIZE = 2048;
// decimated sample block size
static const int DECIMATED_BLOCK_SIZE = 256;
/// Target sample rate after decimation
const int target_srate = 1000;
static const int TARGET_SRATE = 1000;
/// XCorr update sequence size, update in about 200msec chunks
const int xcorr_update_sequence = 200;
static const int XCORR_UPDATE_SEQUENCE = (int)(TARGET_SRATE / 5);
/// Moving average N size
static const int MOVING_AVERAGE_N = 15;
/// XCorr decay time constant, decay to half in 30 seconds
/// If it's desired to have the system adapt quicker to beat rate
/// changes within a continuing music stream, then the
/// 'xcorr_decay_time_constant' value can be reduced, yet that
/// can increase possibility of glitches in bpm detection.
const double xcorr_decay_time_constant = 30.0;
static const double XCORR_DECAY_TIME_CONSTANT = 30.0;
/// Data overlap factor for beat detection algorithm
static const int OVERLAP_FACTOR = 4;
static const double TWOPI = (2 * M_PI);
////////////////////////////////////////////////////////////////////////////////
// Enable following define to create bpm analysis file:
// #define _CREATE_BPM_DEBUG_FILE
//#define _CREATE_BPM_DEBUG_FILE
#ifdef _CREATE_BPM_DEBUG_FILE
#define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt"
static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff)
static void _SaveDebugData(const char *name, const float *data, int minpos, int maxpos, double coeff)
{
FILE *fptr = fopen(DEBUGFILE_NAME, "wt");
FILE *fptr = fopen(name, "wt");
int i;
if (fptr)
{
printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n");
printf("\nWriting BPM debug data into file %s\n", name);
for (i = minpos; i < maxpos; i ++)
{
fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]);
@ -105,15 +110,74 @@ const double xcorr_decay_time_constant = 30.0;
fclose(fptr);
}
}
void _SaveDebugBeatPos(const char *name, const std::vector<BEAT> &beats)
{
printf("\nWriting beat detections data into file %s\n", name);
FILE *fptr = fopen(name, "wt");
if (fptr)
{
for (uint i = 0; i < beats.size(); i++)
{
BEAT b = beats[i];
fprintf(fptr, "%lf\t%lf\n", b.pos, b.strength);
}
fclose(fptr);
}
}
#else
#define _SaveDebugData(a,b,c,d)
#define _SaveDebugData(name, a,b,c,d)
#define _SaveDebugBeatPos(name, b)
#endif
// Hamming window
void hamming(float *w, int N)
{
for (int i = 0; i < N; i++)
{
w[i] = (float)(0.54 - 0.46 * cos(TWOPI * i / (N - 1)));
}
}
////////////////////////////////////////////////////////////////////////////////
//
// IIR2_filter - 2nd order IIR filter
IIR2_filter::IIR2_filter(const double *lpf_coeffs)
{
memcpy(coeffs, lpf_coeffs, 5 * sizeof(double));
memset(prev, 0, sizeof(prev));
}
float IIR2_filter::update(float x)
{
prev[0] = x;
double y = x * coeffs[0];
for (int i = 4; i >= 1; i--)
{
y += coeffs[i] * prev[i];
prev[i] = prev[i - 1];
}
prev[3] = y;
return (float)y;
}
// IIR low-pass filter coefficients, calculated with matlab/octave cheby2(2,40,0.05)
const double _LPF_coeffs[5] = { 0.00996655391939, -0.01944529148401, 0.00996655391939, 1.96867605796247, -0.96916387431724 };
////////////////////////////////////////////////////////////////////////////////
BPMDetect::BPMDetect(int numChannels, int aSampleRate)
BPMDetect::BPMDetect(int numChannels, int aSampleRate) :
beat_lpf(_LPF_coeffs)
{
beats.reserve(250); // initial reservation to prevent frequent reallocation
this->sampleRate = aSampleRate;
this->channels = numChannels;
@ -121,13 +185,15 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate)
decimateCount = 0;
// choose decimation factor so that result is approx. 1000 Hz
decimateBy = sampleRate / target_srate;
assert(decimateBy > 0);
assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES);
decimateBy = sampleRate / TARGET_SRATE;
if ((decimateBy <= 0) || (decimateBy * DECIMATED_BLOCK_SIZE < INPUT_BLOCK_SIZE))
{
ST_THROW_RT_ERROR("Too small samplerate");
}
// Calculate window length & starting item according to desired min & max bpms
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM);
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM_RANGE);
assert(windowLen > windowStart);
@ -135,23 +201,38 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate)
xcorr = new float[windowLen];
memset(xcorr, 0, windowLen * sizeof(float));
pos = 0;
peakPos = 0;
peakVal = 0;
init_scaler = 1;
beatcorr_ringbuffpos = 0;
beatcorr_ringbuff = new float[windowLen];
memset(beatcorr_ringbuff, 0, windowLen * sizeof(float));
// allocate processing buffer
buffer = new FIFOSampleBuffer();
// we do processing in mono mode
buffer->setChannels(1);
buffer->clear();
}
// calculate hamming windows
hamw = new float[XCORR_UPDATE_SEQUENCE];
hamming(hamw, XCORR_UPDATE_SEQUENCE);
hamw2 = new float[XCORR_UPDATE_SEQUENCE / 2];
hamming(hamw2, XCORR_UPDATE_SEQUENCE / 2);
}
BPMDetect::~BPMDetect()
{
delete[] xcorr;
delete[] beatcorr_ringbuff;
delete[] hamw;
delete[] hamw2;
delete buffer;
}
/// convert to mono, low-pass filter & decimate to about 500 Hz.
/// return number of outputted samples.
///
@ -208,7 +289,6 @@ int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
}
// Calculates autocorrelation function of the sample history buffer
void BPMDetect::updateXCorr(int process_samples)
{
@ -216,22 +296,30 @@ void BPMDetect::updateXCorr(int process_samples)
SAMPLETYPE *pBuffer;
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
assert(process_samples == XCORR_UPDATE_SEQUENCE);
pBuffer = buffer->ptrBegin();
// calculate decay factor for xcorr filtering
float xcorr_decay = (float)pow(0.5, 1.0 / (xcorr_decay_time_constant * target_srate / process_samples));
float xcorr_decay = (float)pow(0.5, 1.0 / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE / process_samples));
// prescale pbuffer
float tmp[XCORR_UPDATE_SEQUENCE];
for (int i = 0; i < process_samples; i++)
{
tmp[i] = hamw[i] * hamw[i] * pBuffer[i];
}
#pragma omp parallel for
for (offs = windowStart; offs < windowLen; offs ++)
{
LONG_SAMPLETYPE sum;
double sum;
int i;
sum = 0;
for (i = 0; i < process_samples; i ++)
{
sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
sum += tmp[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
}
xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable time constant.
@ -240,10 +328,93 @@ void BPMDetect::updateXCorr(int process_samples)
}
// Detect individual beat positions
void BPMDetect::updateBeatPos(int process_samples)
{
SAMPLETYPE *pBuffer;
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
pBuffer = buffer->ptrBegin();
assert(process_samples == XCORR_UPDATE_SEQUENCE / 2);
// static double thr = 0.0003;
double posScale = (double)this->decimateBy / (double)this->sampleRate;
int resetDur = (int)(0.12 / posScale + 0.5);
double corrScale = 1.0 / (double)(windowLen - windowStart);
// prescale pbuffer
float tmp[XCORR_UPDATE_SEQUENCE / 2];
for (int i = 0; i < process_samples; i++)
{
tmp[i] = hamw2[i] * hamw2[i] * pBuffer[i];
}
#pragma omp parallel for
for (int offs = windowStart; offs < windowLen; offs++)
{
double sum = 0;
for (int i = 0; i < process_samples; i++)
{
sum += tmp[i] * pBuffer[offs + i];
}
beatcorr_ringbuff[(beatcorr_ringbuffpos + offs) % windowLen] += (float)((sum > 0) ? sum : 0); // accumulate only positive correlations
}
int skipstep = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;
// compensate empty buffer at beginning by scaling coefficient
float scale = (float)windowLen / (float)(skipstep * init_scaler);
if (scale > 1.0f)
{
init_scaler++;
}
else
{
scale = 1.0f;
}
// detect beats
for (int i = 0; i < skipstep; i++)
{
LONG_SAMPLETYPE max = 0;
float sum = beatcorr_ringbuff[beatcorr_ringbuffpos];
sum -= beat_lpf.update(sum);
if (sum > peakVal)
{
// found new local largest value
peakVal = sum;
peakPos = pos;
}
if (pos > peakPos + resetDur)
{
// largest value not updated for 200msec => accept as beat
peakPos += skipstep;
if (peakVal > 0)
{
// add detected beat to end of "beats" vector
BEAT temp = { (float)(peakPos * posScale), (float)(peakVal * scale) };
beats.push_back(temp);
}
peakVal = 0;
peakPos = pos;
}
beatcorr_ringbuff[beatcorr_ringbuffpos] = 0;
pos++;
beatcorr_ringbuffpos = (beatcorr_ringbuffpos + 1) % windowLen;
}
}
#define max(x,y) ((x) > (y) ? (x) : (y))
void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
{
SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES];
SAMPLETYPE decimated[DECIMATED_BLOCK_SIZE];
// iterate so that max INPUT_BLOCK_SAMPLES processed per iteration
while (numSamples > 0)
@ -251,7 +422,7 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
int block;
int decSamples;
block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples;
block = (numSamples > INPUT_BLOCK_SIZE) ? INPUT_BLOCK_SIZE : numSamples;
// decimate. note that converts to mono at the same time
decSamples = decimate(decimated, samples, block);
@ -261,31 +432,60 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
buffer->putSamples(decimated, decSamples);
}
// when the buffer has enought samples for processing...
while ((int)buffer->numSamples() >= windowLen + xcorr_update_sequence)
// when the buffer has enough samples for processing...
int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE);
while ((int)buffer->numSamples() >= req)
{
// ... calculate autocorrelations for oldest samples...
updateXCorr(xcorr_update_sequence);
// ... and remove these from the buffer
buffer->receiveSamples(xcorr_update_sequence);
// ... update autocorrelations...
updateXCorr(XCORR_UPDATE_SEQUENCE);
// ...update beat position calculation...
updateBeatPos(XCORR_UPDATE_SEQUENCE / 2);
// ... and remove proceessed samples from the buffer
int n = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;
buffer->receiveSamples(n);
}
}
void BPMDetect::removeBias()
{
int i;
float minval = 1e12f; // arbitrary large number
// Remove linear bias: calculate linear regression coefficient
// 1. calc mean of 'xcorr' and 'i'
double mean_i = 0;
double mean_x = 0;
for (i = windowStart; i < windowLen; i++)
{
mean_x += xcorr[i];
}
mean_x /= (windowLen - windowStart);
mean_i = 0.5 * (windowLen - 1 + windowStart);
// 2. calculate linear regression coefficient
double b = 0;
double div = 0;
for (i = windowStart; i < windowLen; i++)
{
double xt = xcorr[i] - mean_x;
double xi = i - mean_i;
b += xt * xi;
div += xi * xi;
}
b /= div;
// subtract linear regression and resolve min. value bias
float minval = FLT_MAX; // arbitrary large number
for (i = windowStart; i < windowLen; i ++)
{
xcorr[i] -= (float)(b * i);
if (xcorr[i] < minval)
{
minval = xcorr[i];
}
}
// subtract min.value
for (i = windowStart; i < windowLen; i ++)
{
xcorr[i] -= minval;
@ -293,26 +493,82 @@ void BPMDetect::removeBias()
}
// Calculate N-point moving average for "source" values
void MAFilter(float *dest, const float *source, int start, int end, int N)
{
for (int i = start; i < end; i++)
{
int i1 = i - N / 2;
int i2 = i + N / 2 + 1;
if (i1 < start) i1 = start;
if (i2 > end) i2 = end;
double sum = 0;
for (int j = i1; j < i2; j ++)
{
sum += source[j];
}
dest[i] = (float)(sum / (i2 - i1));
}
}
float BPMDetect::getBpm()
{
double peakPos;
double coeff;
PeakFinder peakFinder;
coeff = 60.0 * ((double)sampleRate / (double)decimateBy);
// save bpm debug analysis data if debug data enabled
_SaveDebugData(xcorr, windowStart, windowLen, coeff);
// remove bias from xcorr data
removeBias();
coeff = 60.0 * ((double)sampleRate / (double)decimateBy);
// save bpm debug data if debug data writing enabled
_SaveDebugData("soundtouch-bpm-xcorr.txt", xcorr, windowStart, windowLen, coeff);
// Smoothen by N-point moving-average
float *data = new float[windowLen];
memset(data, 0, sizeof(float) * windowLen);
MAFilter(data, xcorr, windowStart, windowLen, MOVING_AVERAGE_N);
// find peak position
peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen);
peakPos = peakFinder.detectPeak(data, windowStart, windowLen);
// save bpm debug data if debug data writing enabled
_SaveDebugData("soundtouch-bpm-smoothed.txt", data, windowStart, windowLen, coeff);
delete[] data;
assert(decimateBy != 0);
if (peakPos < 1e-9) return 0.0; // detection failed.
_SaveDebugBeatPos("soundtouch-detected-beats.txt", beats);
// calculate BPM
return (float) (coeff / peakPos);
float bpm = (float)(coeff / peakPos);
return (bpm >= MIN_BPM && bpm <= MAX_BPM_VALID) ? bpm : 0;
}
/// 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.
/// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths
/// - 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".
///
/// \return number of beats in the arrays.
int BPMDetect::getBeats(float *pos, float *values, int max_num)
{
int num = beats.size();
if ((!pos) || (!values)) return num; // pos or values NULL, return just size
for (int i = 0; (i < num) && (i < max_num); i++)
{
pos[i] = beats[i].pos;
values[i] = beats[i].strength;
}
return num;
}

View File

@ -15,13 +15,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2012-11-08 20:53:01 +0200 (to, 08 marras 2012) $
// File revision : $Revision: 4 $
//
// $Id: FIFOSampleBuffer.cpp 160 2012-11-08 18:53:01Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -80,7 +73,8 @@ void FIFOSampleBuffer::setChannels(int numChannels)
{
uint usedBytes;
assert(numChannels > 0);
if (!verifyNumberOfChannels(numChannels)) return;
usedBytes = channels * samplesInBuffer;
channels = (uint)numChannels;
samplesInBuffer = usedBytes / channels;
@ -131,7 +125,7 @@ void FIFOSampleBuffer::putSamples(uint nSamples)
//
// Parameter 'slackCapacity' tells the function how much free capacity (in
// terms of samples) there _at least_ should be, in order to the caller to
// succesfully insert all the required samples to the buffer. When necessary,
// successfully insert all the required samples to the buffer. When necessary,
// the function grows the buffer size to comply with this requirement.
//
// When using this function as means for inserting new samples, also remember
@ -158,7 +152,7 @@ SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
}
// Ensures that the buffer has enought capacity, i.e. space for _at least_
// Ensures that the buffer has enough capacity, i.e. space for _at least_
// 'capacityRequirement' number of samples. The buffer is grown in steps of
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
// as well as to round the buffer size up to the virtual memory page size.
@ -271,4 +265,3 @@ uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
}
return samplesInBuffer;
}

View File

@ -17,13 +17,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2015-11-05 19:46:08 +0200 (to, 05 marras 2015) $
// File revision : $Revision: 4 $
//
// $Id: FIRFilter.cpp 234 2015-11-05 17:46:08Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -75,6 +68,7 @@ FIRFilter::~FIRFilter()
delete[] filterCoeffs;
}
// Usual C-version of the filter routine for stereo sound
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
@ -133,8 +127,6 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
}
// Usual C-version of the filter routine for mono sound
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
@ -260,7 +252,6 @@ uint FIRFilter::getLength() const
}
// Applies the filter to the given sequence of samples.
//
// Note : The amount of outputted samples is by value of 'filter_length'
@ -290,7 +281,6 @@ uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSample
}
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX-capable CPU available or not.
void * FIRFilter::operator new(size_t s)

View File

@ -11,13 +11,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2015-02-21 23:24:29 +0200 (la, 21 helmi 2015) $
// File revision : $Revision: 4 $
//
// $Id: FIRFilter.h 202 2015-02-21 21:24:29Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -8,10 +8,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// $Id: InterpolateCubic.cpp 179 2014-01-06 18:41:42Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -8,10 +8,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// $Id: InterpolateCubic.h 225 2015-07-26 14:45:48Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -8,10 +8,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// $Id: InterpolateLinear.cpp 225 2015-07-26 14:45:48Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -8,10 +8,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// $Id: InterpolateLinear.h 225 2015-07-26 14:45:48Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -42,7 +38,7 @@
namespace soundtouch
{
/// Linear transposer class that uses integer arithmetics
/// Linear transposer class that uses integer arithmetic
class InterpolateLinearInteger : public TransposerBase
{
protected:
@ -67,7 +63,7 @@ public:
};
/// Linear transposer class that uses floating point arithmetics
/// Linear transposer class that uses floating point arithmetic
class InterpolateLinearFloat : public TransposerBase
{
protected:

View File

@ -13,10 +13,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// $Id: InterpolateShannon.cpp 195 2014-04-06 15:57:21Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -13,10 +13,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// $Id: InterpolateShannon.h 225 2015-07-26 14:45:48Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -11,13 +11,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2015-05-18 18:22:02 +0300 (ma, 18 touko 2015) $
// File revision : $Revision: 4 $
//
// $Id: PeakFinder.cpp 213 2015-05-18 15:22:02Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -64,7 +57,7 @@ int PeakFinder::findTop(const float *data, int peakpos) const
refvalue = data[peakpos];
// seek within ±10 points
// seek within <EFBFBD>10 points
start = peakpos - 10;
if (start < minPos) start = minPos;
end = peakpos + 10;
@ -178,7 +171,6 @@ double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos)
}
/// get exact center of peak near given position by calculating local mass of center
double PeakFinder::getPeakCenter(const float *data, int peakpos) const
{
@ -218,7 +210,6 @@ double PeakFinder::getPeakCenter(const float *data, int peakpos) const
}
double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
{
@ -249,12 +240,12 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
// - sometimes the highest peak can be Nth harmonic of the true base peak yet
// just a slightly higher than the true base
for (i = 3; i < 10; i ++)
for (i = 1; i < 3; i ++)
{
double peaktmp, harmonic;
int i1,i2;
harmonic = (double)i * 0.5;
harmonic = (double)pow(2.0, i);
peakpos = (int)(highPeak / harmonic + 0.5f);
if (peakpos < minPos) break;
peakpos = findTop(data, peakpos); // seek true local maximum index
@ -265,7 +256,7 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
// accept harmonic peak if
// (a) it is found
// (b) is within ±4% of the expected harmonic interval
// (b) is within <EFBFBD>4% of the expected harmonic interval
// (c) has at least half x-corr value of the max. peak
double diff = harmonic * peaktmp / highPeak;

View File

@ -9,13 +9,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2011-12-30 22:33:46 +0200 (pe, 30 joulu 2011) $
// File revision : $Revision: 4 $
//
// $Id: PeakFinder.h 132 2011-12-30 20:33:46Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -51,8 +44,8 @@ protected:
/// Calculates the mass center between given vector items.
double calcMassCenter(const float *data, ///< Data vector.
int firstPos, ///< Index of first vector item beloging to the peak.
int lastPos ///< Index of last vector item beloging to the peak.
int firstPos, ///< Index of first vector item belonging to the peak.
int lastPos ///< Index of last vector item belonging to the peak.
) const;
/// Finds the data vector index where the monotoniously decreasing signal crosses the

View File

@ -10,13 +10,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2016-10-15 22:34:59 +0300 (la, 15 loka 2016) $
// File revision : $Revision: 4 $
//
// $Id: RateTransposer.cpp 243 2016-10-15 19:34:59Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -57,7 +50,13 @@ TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
// Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{
bUseAAFilter = true;
bUseAAFilter =
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
true;
#else
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
false;
#endif
// Instantiates the anti-alias filter
pAAFilter = new AAFilter(64);
@ -65,7 +64,6 @@ RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
}
RateTransposer::~RateTransposer()
{
delete pAAFilter;
@ -73,11 +71,13 @@ RateTransposer::~RateTransposer()
}
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void RateTransposer::enableAAFilter(bool newMode)
{
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
bUseAAFilter = newMode;
#endif
}
@ -94,7 +94,6 @@ AAFilter *RateTransposer::getAAFilter()
}
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates.
void RateTransposer::setRate(double newRate)
@ -177,11 +176,10 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
// Sets the number of channels, 1 = mono, 2 = stereo
void RateTransposer::setChannels(int nChannels)
{
assert(nChannels > 0);
if (!verifyNumberOfChannels(nChannels) ||
(pTransposer->numChannels == nChannels)) return;
if (pTransposer->numChannels == nChannels) return;
pTransposer->setChannels(nChannels);
inputBuffer.setChannels(nChannels);
midBuffer.setChannels(nChannels);
outputBuffer.setChannels(nChannels);
@ -287,7 +285,7 @@ void TransposerBase::setRate(double newRate)
TransposerBase *TransposerBase::newInstance()
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// Notice: For integer arithmetics support only linear algorithm (due to simplest calculus)
// Notice: For integer arithmetic support only linear algorithm (due to simplest calculus)
return ::new InterpolateLinearInteger;
#else
switch (algorithm)

View File

@ -14,13 +14,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2016-10-15 22:34:59 +0300 (la, 15 loka 2016) $
// File revision : $Revision: 4 $
//
// $Id: RateTransposer.h 243 2016-10-15 19:34:59Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -132,21 +125,9 @@ public:
RateTransposer();
virtual ~RateTransposer();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we're to use integer or floating point arithmetics.
// static void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct implementation, depending on if
/// integer ot floating point arithmetics are to be used.
// static RateTransposer *newInstance();
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the store buffer object
// FIFOSamplePipe *getStore() { return &storeBuffer; };
/// Return anti-alias filter object
AAFilter *getAAFilter();

View File

@ -41,13 +41,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2016-10-15 22:34:59 +0300 (la, 15 loka 2016) $
// File revision : $Revision: 4 $
//
// $Id: SoundTouch.cpp 243 2016-10-15 19:34:59Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -118,7 +111,6 @@ SoundTouch::SoundTouch()
}
SoundTouch::~SoundTouch()
{
delete pRateTransposer;
@ -126,7 +118,6 @@ SoundTouch::~SoundTouch()
}
/// Get SoundTouch library version string
const char *SoundTouch::getVersionString()
{
@ -146,18 +137,14 @@ uint SoundTouch::getVersionId()
// Sets the number of channels, 1 = mono, 2 = stereo
void SoundTouch::setChannels(uint numChannels)
{
/*if (numChannels != 1 && numChannels != 2)
{
//ST_THROW_RT_ERROR("Illegal number of channels");
return;
}*/
if (!verifyNumberOfChannels(numChannels)) return;
channels = numChannels;
pRateTransposer->setChannels((int)numChannels);
pTDStretch->setChannels((int)numChannels);
}
// Sets new rate control value. Normal rate = 1.0, smaller values
// represent slower rate, larger faster rates.
void SoundTouch::setRate(double newRate)
@ -167,7 +154,6 @@ void SoundTouch::setRate(double newRate)
}
// Sets new rate control value as a difference in percents compared
// to the original rate (-50 .. +100 %)
void SoundTouch::setRateChange(double newRate)
@ -177,7 +163,6 @@ void SoundTouch::setRateChange(double newRate)
}
// Sets new tempo control value. Normal tempo = 1.0, smaller values
// represent slower tempo, larger faster tempo.
void SoundTouch::setTempo(double newTempo)
@ -187,7 +172,6 @@ void SoundTouch::setTempo(double newTempo)
}
// Sets new tempo control value as a difference in percents compared
// to the original tempo (-50 .. +100 %)
void SoundTouch::setTempoChange(double newTempo)
@ -197,7 +181,6 @@ void SoundTouch::setTempoChange(double newTempo)
}
// Sets new pitch control value. Original pitch = 1.0, smaller values
// represent lower pitches, larger values higher pitch.
void SoundTouch::setPitch(double newPitch)
@ -207,7 +190,6 @@ void SoundTouch::setPitch(double newPitch)
}
// Sets pitch change in octaves compared to the original pitch
// (-1.00 .. +1.00)
void SoundTouch::setPitchOctaves(double newPitch)
@ -217,7 +199,6 @@ void SoundTouch::setPitchOctaves(double newPitch)
}
// Sets pitch change in semi-tones compared to the original pitch
// (-12 .. +12)
void SoundTouch::setPitchSemiTones(int newPitch)
@ -226,7 +207,6 @@ void SoundTouch::setPitchSemiTones(int newPitch)
}
void SoundTouch::setPitchSemiTones(double newPitch)
{
setPitchOctaves(newPitch / 12.0);
@ -286,9 +266,9 @@ void SoundTouch::calcEffectiveRateAndTempo()
// Sets sample rate.
void SoundTouch::setSampleRate(uint srate)
{
bSrateSet = true;
// set sample rate, leave other tempo changer parameters as they are.
pTDStretch->setParameters((int)srate);
bSrateSet = true;
}
@ -305,22 +285,6 @@ void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)
ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined");
}
// Transpose the rate of the new samples if necessary
/* Bypass the nominal setting - can introduce a click in sound when tempo/pitch control crosses the nominal value...
if (rate == 1.0f)
{
// The rate value is same as the original, simply evaluate the tempo changer.
assert(output == pTDStretch);
if (pRateTransposer->isEmpty() == 0)
{
// yet flush the last samples in the pitch transposer buffer
// (may happen if 'rate' changes from a non-zero value to zero)
pTDStretch->moveSamples(*pRateTransposer);
}
pTDStretch->putSamples(samples, nSamples);
}
*/
// accumulate how many samples are expected out from processing, given the current
// processing setting
samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo);
@ -376,7 +340,6 @@ void SoundTouch::flush()
delete[] buff;
// Clear input buffers
// pRateTransposer->clearInput();
pTDStretch->clearInput();
// yet leave the output intouched as that's where the
// flushed samples are!
@ -513,7 +476,6 @@ int SoundTouch::getSetting(int settingId) const
}
// Clears all the samples in the object's output and internal processing
// buffers.
void SoundTouch::clear()
@ -525,7 +487,6 @@ void SoundTouch::clear()
}
/// Returns number of samples currently unprocessed.
uint SoundTouch::numUnprocessedSamples() const
{
@ -542,7 +503,6 @@ uint SoundTouch::numUnprocessedSamples() const
}
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.

View File

@ -19,13 +19,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2017-04-07 22:01:22 +0300 (pe, 07 huhti 2017) $
// File revision : $Revision: 1.12 $
//
// $Id: TDStretch.cpp 249 2017-04-07 19:01:22Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -134,8 +127,13 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
int aSeekWindowMS, int aOverlapMS)
{
// accept only positive parameter values - if zero or negative, use old values instead
if (aSampleRate > 0) this->sampleRate = aSampleRate;
if (aOverlapMS > 0) this->overlapMs = aOverlapMS;
if (aSampleRate > 0)
{
if (aSampleRate > 192000) ST_THROW_RT_ERROR("Error: Excessive samplerate");
this->sampleRate = aSampleRate;
}
if (aOverlapMS > 0) this->overlapMs = aOverlapMS;
if (aSequenceMS > 0)
{
@ -362,7 +360,7 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
// with improved precision
//
// Based on testing:
// - This algorithm gives on average 99% as good match as the full algorith
// - 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
// - 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
@ -519,7 +517,7 @@ void TDStretch::clearCrossCorrState()
void TDStretch::calcSeqParameters()
{
// Adjust tempo param according to tempo, so that variating processing sequence length is used
// at varius tempo settings, between the given low...top limits
// at various tempo settings, between the given low...top limits
#define AUTOSEQ_TEMPO_LOW 0.5 // auto setting low tempo range (-50%)
#define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%)
@ -590,9 +588,8 @@ void TDStretch::setTempo(double newTempo)
// Sets the number of channels, 1 = mono, 2 = stereo
void TDStretch::setChannels(int numChannels)
{
assert(numChannels > 0);
if (channels == numChannels) return;
// assert(numChannels == 1 || numChannels == 2);
if (!verifyNumberOfChannels(numChannels) ||
(channels == numChannels)) return;
channels = numChannels;
inputBuffer.setChannels(channels);
@ -807,7 +804,7 @@ TDStretch * TDStretch::newInstance()
//////////////////////////////////////////////////////////////////////////////
//
// Integer arithmetics specific algorithm implementations.
// Integer arithmetic specific algorithm implementations.
//
//////////////////////////////////////////////////////////////////////////////
@ -972,7 +969,7 @@ double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *c
//////////////////////////////////////////////////////////////////////////////
//
// Floating point arithmetics specific algorithm implementations.
// Floating point arithmetic specific algorithm implementations.
//
#ifdef SOUNDTOUCH_FLOAT_SAMPLES

View File

@ -13,13 +13,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2016-10-20 19:30:11 +0300 (to, 20 loka 2016) $
// File revision : $Revision: 4 $
//
// $Id: TDStretch.h 244 2016-10-20 16:30:11Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -164,7 +157,6 @@ protected:
void calcSeqParameters();
void adaptNormalizer();
/// Changes the tempo of the given sound samples.
/// Returns amount of samples returned in the "output" buffer.
/// The maximum amount of samples that can be returned at a time is set by
@ -249,7 +241,6 @@ public:
return seekWindowLength - overlapLength;
}
/// return approximate initial input-output latency
int getLatency() const
{
@ -258,7 +249,6 @@ public:
};
// Implementation-specific class declarations:
#ifdef SOUNDTOUCH_ALLOW_MMX

View File

@ -12,13 +12,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2008-02-10 18:26:55 +0200 (su, 10 helmi 2008) $
// File revision : $Revision: 4 $
//
// $Id: cpu_detect.h 11 2008-02-10 16:26:55Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library

View File

@ -11,13 +11,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2014-01-07 20:24:28 +0200 (ti, 07 tammi 2014) $
// File revision : $Revision: 4 $
//
// $Id: cpu_detect_x86.cpp 183 2014-01-07 18:24:28Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -75,7 +68,6 @@ void disableExtensions(uint dwDisableMask)
}
/// Checks which instruction set extensions are supported by the CPU.
uint detectCPUextensions(void)
{

View File

@ -20,13 +20,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2017-03-05 15:56:03 +0200 (su, 05 maalis 2017) $
// File revision : $Revision: 4 $
//
// $Id: mmx_optimized.cpp 247 2017-03-05 13:56:03Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
@ -224,7 +217,6 @@ void TDStretchMMX::clearCrossCorrState()
}
// MMX-optimized version of the function overlapStereo
void TDStretchMMX::overlapStereo(short *output, const short *input) const
{
@ -340,7 +332,6 @@ void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uRe
}
// mmx-optimized version of the filter routine for stereo sound
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
{
@ -397,4 +388,9 @@ uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numS
return (numSamples & 0xfffffffe) - length;
}
#else
// workaround to not complain about empty module
bool _dontcomplain_mmx_empty;
#endif // SOUNDTOUCH_ALLOW_MMX

View File

@ -23,13 +23,6 @@
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date: 2015-08-09 00:00:15 +0300 (su, 09 elo 2015) $
// File revision : $Revision: 4 $
//
// $Id: sse_optimized.cpp 226 2015-08-08 21:00:15Z oparviai $
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library