mirror of https://github.com/PCSX2/pcsx2.git
3rdparty:soundtouch: Upgrade SoundTouch lib to 2.1.2. (#2787)
This commit is contained in:
parent
1ae48db873
commit
f25fe48c9b
|
@ -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
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
DAMAGES.
|
DAMAGES.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
|
@ -8,13 +8,14 @@
|
||||||
<meta name="author" content="Olli Parviainen">
|
<meta name="author" content="Olli Parviainen">
|
||||||
<meta name="description"
|
<meta name="description"
|
||||||
content="Readme file for SoundTouch audio processing library">
|
content="Readme file for SoundTouch audio processing library">
|
||||||
<style> <!-- .normal { font-family: Arial }
|
<style>
|
||||||
--></style>
|
body {font-family: Arial, Helvetica; }
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="normal">
|
<body class="normal">
|
||||||
<hr>
|
<hr>
|
||||||
<h1>SoundTouch audio processing library v1.9.2</h1>
|
<h1>SoundTouch audio processing library v2.1.2</h1>
|
||||||
<p class="normal">SoundTouch library Copyright © Olli Parviainen 2001-2015</p>
|
<p class="normal">SoundTouch library Copyright © Olli Parviainen 2001-2018</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
|
||||||
|
@ -32,6 +33,7 @@ same time</li>
|
||||||
<h3>1.1 Contact information </h3>
|
<h3>1.1 Contact information </h3>
|
||||||
<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 href="https://gitlab.com/soundtouch/soundtouch.git">https://gitlab.com/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
|
||||||
|
@ -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
|
be created manually to the SoundTouch package root for the final
|
||||||
executables. The make-win.bat script creates these directories
|
executables. The make-win.bat script creates these directories
|
||||||
automatically. </p>
|
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
|
<p><strong>OpenMP NOTE</strong>: If activating the OpenMP parallel computing in
|
||||||
the compilation, the target program will require additional vcomp dll library to
|
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
|
properly run. In Visual C++ 9.0 these libraries can be found in the following
|
||||||
|
@ -120,7 +125,7 @@ destination locations.</p>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h4><b>2.2.1 Required GNU tools</b> </h4>
|
<h4><b>2.2.1 Required GNU tools</b></h4>
|
||||||
<p> <span style="font-weight: bold;">Bash shell</span>, <span
|
<p> <span style="font-weight: bold;">Bash shell</span>, <span
|
||||||
style="font-weight: bold;">GNU C++ compiler</span>, <span
|
style="font-weight: bold;">GNU C++ compiler</span>, <span
|
||||||
style="font-weight: bold;">libtool</span>, <span
|
style="font-weight: bold;">libtool</span>, <span
|
||||||
|
@ -156,7 +161,7 @@ directly and remove the following definition:<blockquote>
|
||||||
sstrip SoundTouch.dll</pre>
|
sstrip SoundTouch.dll</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<h3>2.1. Building in Android</h3>
|
<h3>2.3. Building in Android</h3>
|
||||||
<p>Android compilation instructions are within the
|
<p>Android compilation instructions are within the
|
||||||
source code package, see file "<b>source/Android-lib/README-SoundTouch-Android.html</b>"
|
source code package, see file "<b>source/Android-lib/README-SoundTouch-Android.html</b>"
|
||||||
in the source code package. </p>
|
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>
|
and <em>time-stretching</em>.</p>
|
||||||
<p><em>Sample rate transposing</em> affects both the audio stream
|
<p><em>Sample rate transposing</em> affects both the audio stream
|
||||||
duration and pitch. It's implemented simply by converting the original
|
duration and pitch. It's implemented simply by converting the original
|
||||||
audio sample stream to the desired duration by interpolating from
|
audio sample stream to the desired duration by interpolating from
|
||||||
the original audio samples. In SoundTouch, linear interpolation with
|
the original audio samples. In SoundTouch, linear interpolation with
|
||||||
anti-alias filtering is used. Theoretically a higher-order
|
anti-alias filtering is used. Theoretically a higher-order
|
||||||
interpolation provide better result than 1st order linear
|
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.
|
the how the original sound is chopped in the time-stretch algorithm.
|
||||||
Larger values mean fewer sequences are used in processing. In principle
|
Larger values mean fewer sequences are used in processing. In principle
|
||||||
a larger value sounds better when slowing down the tempo, but worse
|
a larger value sounds better when slowing down the tempo, but worse
|
||||||
when increasing the tempo and vice versa. <br>
|
when increasing the tempo and vice versa.<br>
|
||||||
<br>
|
<br>
|
||||||
By default, this setting value is calculated automatically according to
|
By default, this setting value is calculated automatically according to
|
||||||
tempo value.<br>
|
tempo value.<br>
|
||||||
|
@ -277,7 +282,7 @@ tempo value.<br>
|
||||||
default length in milliseconds is for the algorithm that seeks the best
|
default length in milliseconds is for the algorithm that seeks the best
|
||||||
possible overlapping location. This determines from how wide a sample
|
possible overlapping location. This determines from how wide a sample
|
||||||
"window" the algorithm can use to find an optimal mixing location when
|
"window" the algorithm can use to find an optimal mixing location when
|
||||||
the sound sequences are to be linked back together. <br>
|
the sound sequences are to be linked back together.<br>
|
||||||
<br>
|
<br>
|
||||||
The bigger this window setting is, the higher the possibility to find a
|
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
|
better mixing position becomes, but at the same time large values may
|
||||||
|
@ -345,7 +350,7 @@ computation burden</td>
|
||||||
</td>
|
</td>
|
||||||
<td valign="top">Default value is relatively large, chosen to
|
<td valign="top">Default value is relatively large, chosen to
|
||||||
suit with above parameters.</td>
|
suit with above parameters.</td>
|
||||||
<td valign="top"> </td>
|
<td valign="top"></td>
|
||||||
<td valign="top">If you reduce the "sequence ms" setting, you
|
<td valign="top">If you reduce the "sequence ms" setting, you
|
||||||
might wish to try a smaller value.</td>
|
might wish to try a smaller value.</td>
|
||||||
<td valign="top">Increasing the parameter value increases
|
<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
|
<p>The time-stretch routine has a 'quick' mode that substantially
|
||||||
speeds up the algorithm but may slightly compromise the sound quality.
|
speeds up the algorithm but may slightly compromise the sound quality.
|
||||||
This mode is activated by calling SoundTouch::setSetting()
|
This mode is activated by calling SoundTouch::setSetting()
|
||||||
function with parameter id of SETTING_USE_QUICKSEEK and value
|
function with parameter id of SETTING_USE_QUICKSEEK and value
|
||||||
"1", i.e. </p>
|
"1", i.e. </p>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>setSetting(SETTING_USE_QUICKSEEK, 1);</p>
|
<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
|
<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
|
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
|
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
|
<p>The parallel computing support is implemented using OpenMP spec 3.0
|
||||||
instructions. These instructions are supported by Visual C++ 2008 and later, and
|
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
|
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>
|
||||||
<td valign="top">Name of the output sound file where the
|
<td valign="top">Name of the output sound file where the
|
||||||
resulting sound is saved (in .WAV audio file format). This parameter
|
resulting sound is saved (in .WAV audio file format). This parameter
|
||||||
may be omitted if you don't want to save the output (e.g. when
|
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
|
only calculating BPM rate with '-bpm' switch). Give "stdout" as
|
||||||
filename to use standard output pipe.</td>
|
filename to use standard output pipe.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td valign="top">
|
<td valign="top">
|
||||||
<pre> [switches]</pre>
|
<pre>[switches]</pre>
|
||||||
</td>
|
</td>
|
||||||
<td valign="top">Are one or more control switches.</td>
|
<td valign="top">Are one or more control switches.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -567,6 +575,41 @@ this corresponds to lowering the pitch by -0.318 semitones:</p>
|
||||||
<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.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>
|
<p><b>1.9.2:</b></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Fix in GNU package configuration</li>
|
<li>Fix in GNU package configuration</li>
|
||||||
|
@ -575,8 +618,8 @@ this corresponds to lowering the pitch by -0.318 semitones:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Improved SoundTouch::flush() function so that it returns precisely the desired amount of samples for exact output duration control</li>
|
<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
|
<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
|
default full-scan mode, while the quickseek algorithm is remarkable less
|
||||||
CPU intensive.</li>
|
CPU intensive.</li>
|
||||||
<li>Added adaptive integer divider scaling for improved sound quality when using integer processing algorithm
|
<li>Added adaptive integer divider scaling for improved sound quality when using integer processing algorithm
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -647,13 +690,13 @@ sample batch sizes</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li> Added normalization to correlation calculation and improvement
|
<li> Added normalization to correlation calculation and improvement
|
||||||
automatic seek/sequence parameter calculation to improve sound quality</li>
|
automatic seek/sequence parameter calculation to improve sound quality</li>
|
||||||
<li> Bugfixes:
|
<li> Bugfixes:
|
||||||
<ul>
|
<ul>
|
||||||
<li> Fixed negative array indexing in quick seek algorithm</li>
|
<li> Fixed negative array indexing in quick seek algorithm</li>
|
||||||
<li> FIR autoalias filter running too far in processing buffer</li>
|
<li> FIR autoalias filter running too far in processing buffer</li>
|
||||||
<li> Check against zero sample count in rate transposing</li>
|
<li> Check against zero sample count in rate transposing</li>
|
||||||
<li> Fix for x86-64 support: Removed pop/push instructions from
|
<li> Fix for x86-64 support: Removed pop/push instructions from
|
||||||
the cpu detection algorithm. </li>
|
the cpu detection algorithm.</li>
|
||||||
<li> Check against empty buffers in FIFOSampleBuffer</li>
|
<li> Check against empty buffers in FIFOSampleBuffer</li>
|
||||||
<li> Other minor fixes & code cleanup</li>
|
<li> Other minor fixes & code cleanup</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -669,7 +712,7 @@ negative side or vice versa</li>
|
||||||
<p><strong>1.4.1:</strong></p>
|
<p><strong>1.4.1:</strong></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li> Fixed a buffer overflow bug in BPM detect algorithm routines if
|
<li> Fixed a buffer overflow bug in BPM detect algorithm routines if
|
||||||
processing more than 2048 samples at one call </li>
|
processing more than 2048 samples at one call</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p><strong>1.4.0:</strong></p>
|
<p><strong>1.4.0:</strong></p>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -752,7 +795,6 @@ accessing the FIFOSampleBuffer class from external files.</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li> Initial release</li>
|
<li> Initial release</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p> </p>
|
|
||||||
<h3>5.2. SoundStretch application Change History </h3>
|
<h3>5.2. SoundStretch application Change History </h3>
|
||||||
<p><b>1.9:</b></p>
|
<p><b>1.9:</b></p>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -819,10 +861,12 @@ switch "-bpm"</li>
|
||||||
<p>Kudos for these people who have contributed to development or
|
<p>Kudos for these people who have contributed to development or
|
||||||
submitted bugfixes:</p>
|
submitted bugfixes:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li> Arthur A</li>
|
<li> Arthur A</li>
|
||||||
|
<li> Paul Adenot</li>
|
||||||
<li> Richard Ash</li>
|
<li> Richard Ash</li>
|
||||||
<li> Stanislav Brabec</li>
|
<li> Stanislav Brabec</li>
|
||||||
<li> Christian Budde</li>
|
<li> Christian Budde</li>
|
||||||
|
<li> Jamie Bullock</li>
|
||||||
<li> Chris Bryan</li>
|
<li> Chris Bryan</li>
|
||||||
<li> Jacek Caban</li>
|
<li> Jacek Caban</li>
|
||||||
<li> Brian Cameron</li>
|
<li> Brian Cameron</li>
|
||||||
|
@ -830,25 +874,35 @@ submitted bugfixes:</p>
|
||||||
<li> David Clark</li>
|
<li> David Clark</li>
|
||||||
<li> Patrick Colis</li>
|
<li> Patrick Colis</li>
|
||||||
<li> Miquel Colon</li>
|
<li> Miquel Colon</li>
|
||||||
<li> Jim Credland</li>
|
<li> Jim Credland</li>
|
||||||
<li> Sandro Cumerlato</li>
|
<li> Sandro Cumerlato</li>
|
||||||
|
<li> Gerry Fan</li>
|
||||||
<li> Justin Frankel</li>
|
<li> Justin Frankel</li>
|
||||||
<li> Masa H.</li>
|
<li> Masa H.</li>
|
||||||
<li> Jason Garland</li>
|
<li> Jason Garland</li>
|
||||||
<li> Takashi Iwai</li>
|
<li> Takashi Iwai</li>
|
||||||
<li> Thomas Klausner</li>
|
<li> Thomas Klausner</li>
|
||||||
<li> Mathias Möhl</li>
|
<li> Lu Zhihe</li>
|
||||||
|
<li> Luzpaz</li>
|
||||||
|
<li> Tony Mechelynck </li>
|
||||||
|
<li> Mathias Möhl</li>
|
||||||
<li> Yuval Naveh</li>
|
<li> Yuval Naveh</li>
|
||||||
|
<li> Mats Palmgren </li>
|
||||||
|
<li> Chandni Patel</li>
|
||||||
<li> Paulo Pizarro</li>
|
<li> Paulo Pizarro</li>
|
||||||
|
<li> Andrey Ponomarenko</li>
|
||||||
<li> Blaise Potard</li>
|
<li> Blaise Potard</li>
|
||||||
<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> John Sheehy</li>
|
<li> John Sheehy</li>
|
||||||
<li> Tim Shuttleworth</li>
|
<li> Tim Shuttleworth</li>
|
||||||
<li> Albert Sirvent</li>
|
<li> Albert Sirvent</li>
|
||||||
|
<li> Tyson Smith</li>
|
||||||
<li> John Stumpo</li>
|
<li> John Stumpo</li>
|
||||||
|
<li> Mario di Vece</li>
|
||||||
<li> Katja Vetter</li>
|
<li> Katja Vetter</li>
|
||||||
|
<li> Wu Q.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Moral greetings to all other contributors and users also!</p>
|
<p>Moral greetings to all other contributors and users also!</p>
|
||||||
<hr>
|
<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
|
<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
|
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>
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>
|
||||||
<hr><!--
|
<p>---</p>
|
||||||
$Id: README.html 230 2015-09-20 07:38:32Z oparviai $
|
<p>commercial license alternative also available, contact author for details.</p>
|
||||||
-->
|
<hr>
|
||||||
<p>
|
<p><i>README.html file updated in November-2018</i></p>
|
||||||
<i>README.html file updated in Sep-2015</i></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -57,102 +50,156 @@
|
||||||
#ifndef _BPMDetect_H_
|
#ifndef _BPMDetect_H_
|
||||||
#define _BPMDetect_H_
|
#define _BPMDetect_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include "STTypes.h"
|
#include "STTypes.h"
|
||||||
#include "FIFOSampleBuffer.h"
|
#include "FIFOSampleBuffer.h"
|
||||||
|
|
||||||
namespace soundtouch
|
namespace soundtouch
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
|
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
|
||||||
#define MIN_BPM 29
|
#define MIN_BPM 45
|
||||||
|
|
||||||
/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
|
/// Maximum allowed BPM rate range. Used for calculating algorithm parametrs
|
||||||
#define MAX_BPM 200
|
#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 IIR2_filter
|
||||||
class BPMDetect
|
{
|
||||||
{
|
double coeffs[5];
|
||||||
protected:
|
double prev[5];
|
||||||
/// Auto-correlation accumulator bins.
|
|
||||||
float *xcorr;
|
|
||||||
|
|
||||||
/// Sample average counter.
|
|
||||||
int decimateCount;
|
|
||||||
|
|
||||||
/// Sample average accumulator for FIFO-like decimation.
|
public:
|
||||||
soundtouch::LONG_SAMPLETYPE decimateSum;
|
IIR2_filter(const double *lpf_coeffs);
|
||||||
|
float update(float x);
|
||||||
/// 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
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/// Analyzes the results and returns the BPM rate. Use this function to read result
|
/// Class for calculating BPM rate for audio data.
|
||||||
/// after whole song data has been input to the class by consecutive calls of
|
class BPMDetect
|
||||||
/// 'inputSamples' function.
|
{
|
||||||
///
|
protected:
|
||||||
/// \return Beats-per-minute rate, or zero if detection failed.
|
/// Auto-correlation accumulator bins.
|
||||||
float getBpm();
|
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_
|
#endif // _BPMDetect_H_
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -119,7 +112,7 @@ public:
|
||||||
/// '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 succesfully 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.
|
||||||
);
|
);
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -58,6 +51,18 @@ namespace soundtouch
|
||||||
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
|
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
|
||||||
class FIFOSamplePipe
|
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:
|
public:
|
||||||
// virtual default destructor
|
// virtual default destructor
|
||||||
virtual ~FIFOSamplePipe() {}
|
virtual ~FIFOSamplePipe() {}
|
||||||
|
@ -122,7 +127,6 @@ 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
|
||||||
|
@ -145,7 +149,6 @@ protected:
|
||||||
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()
|
||||||
|
@ -153,7 +156,6 @@ protected:
|
||||||
output = NULL;
|
output = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Constructor. Configures output pipe.
|
/// Constructor. Configures output pipe.
|
||||||
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
|
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
|
||||||
)
|
)
|
||||||
|
@ -161,13 +163,11 @@ protected:
|
||||||
output = pOutput;
|
output = pOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
virtual ~FIFOProcessor()
|
virtual ~FIFOProcessor()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// 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!
|
||||||
|
@ -194,7 +194,6 @@ 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.
|
||||||
///
|
///
|
||||||
|
@ -206,14 +205,12 @@ public:
|
||||||
return output->receiveSamples(maxSamples);
|
return output->receiveSamples(maxSamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns number of samples currently available.
|
/// Returns number of samples currently available.
|
||||||
virtual uint numSamples() const
|
virtual uint numSamples() const
|
||||||
{
|
{
|
||||||
return output->numSamples();
|
return output->numSamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Returns nonzero if there aren't any samples available for outputting.
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
virtual int isEmpty() const
|
virtual int isEmpty() const
|
||||||
{
|
{
|
||||||
|
@ -226,7 +223,6 @@ public:
|
||||||
{
|
{
|
||||||
return output->adjustAmountOfSamples(numSamples);
|
return output->adjustAmountOfSamples(numSamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -63,6 +56,9 @@ typedef unsigned long ulong;
|
||||||
|
|
||||||
namespace soundtouch
|
namespace soundtouch
|
||||||
{
|
{
|
||||||
|
/// Max allowed number of channels
|
||||||
|
#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
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -79,10 +72,10 @@ namespace soundtouch
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Soundtouch library version string
|
/// Soundtouch library version string
|
||||||
#define SOUNDTOUCH_VERSION "2.0.0"
|
#define SOUNDTOUCH_VERSION "2.1.2"
|
||||||
|
|
||||||
/// SoundTouch library version id
|
/// SoundTouch library version id
|
||||||
#define SOUNDTOUCH_VERSION_ID (20000)
|
#define SOUNDTOUCH_VERSION_ID (20102)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
||||||
|
@ -320,7 +313,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 succesfully 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.
|
||||||
);
|
);
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -63,7 +56,6 @@ 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
|
||||||
|
@ -222,23 +214,23 @@ void WavInFile::init()
|
||||||
if (hdrsOk != 0)
|
if (hdrsOk != 0)
|
||||||
{
|
{
|
||||||
// Something didn't match in the wav file headers
|
// Something didn't match in the wav file headers
|
||||||
string msg = "Input file is corrupt or not a WAV file";
|
ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file");
|
||||||
ST_THROW_RT_ERROR(msg.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore 'fixed' field value as 32bit signed linear data can have other value than 1.
|
// sanity check for format parameters
|
||||||
if (header.format.fixed != 1)
|
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.";
|
// Something didn't match in the wav file headers
|
||||||
ST_THROW_RT_ERROR(msg.c_str());
|
ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters.");
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
dataRead = 0;
|
dataRead = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WavInFile::~WavInFile()
|
WavInFile::~WavInFile()
|
||||||
{
|
{
|
||||||
if (fptr) fclose(fptr);
|
if (fptr) fclose(fptr);
|
||||||
|
@ -246,7 +238,6 @@ WavInFile::~WavInFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void WavInFile::rewind()
|
void WavInFile::rewind()
|
||||||
{
|
{
|
||||||
int hdrsOk;
|
int hdrsOk;
|
||||||
|
@ -463,7 +454,6 @@ int WavInFile::eof() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// test if character code is between a white space ' ' and little 'z'
|
// test if character code is between a white space ' ' and little 'z'
|
||||||
static int isAlpha(char c)
|
static int isAlpha(char c)
|
||||||
{
|
{
|
||||||
|
@ -504,8 +494,6 @@ int WavInFile::readRIFFBlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int WavInFile::readHeaderBlock()
|
int WavInFile::readHeaderBlock()
|
||||||
{
|
{
|
||||||
char label[5];
|
char label[5];
|
||||||
|
@ -528,12 +516,16 @@ int WavInFile::readHeaderBlock()
|
||||||
// read length of the format field
|
// read length of the format field
|
||||||
if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
|
if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
|
||||||
// swap byte order if necessary
|
// swap byte order if necessary
|
||||||
_swap32(nLen); // int format_len;
|
_swap32(nLen);
|
||||||
header.format.format_len = 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
|
||||||
|
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 format_len is larger than expected, read only as much data as we've space for
|
||||||
if (nDump > 0)
|
if (nDump > 0)
|
||||||
{
|
{
|
||||||
|
@ -544,12 +536,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(header.format.fixed); // short int fixed;
|
_swap16((short &)header.format.fixed); // short int fixed;
|
||||||
_swap16(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(header.format.byte_per_sample); // short int byte_per_sample;
|
_swap16((short &)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.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)
|
||||||
|
@ -569,12 +561,16 @@ int WavInFile::readHeaderBlock()
|
||||||
// read length of the fact field
|
// read length of the fact field
|
||||||
if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
|
if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;
|
||||||
// swap byte order if necessary
|
// swap byte order if necessary
|
||||||
_swap32(nLen); // int fact_len;
|
_swap32(nLen);
|
||||||
header.fact.fact_len = nLen;
|
|
||||||
|
|
||||||
// calculate how much length differs from expected
|
// calculate how much length differs from expected
|
||||||
nDump = nLen - ((int)sizeof(header.fact) - 8);
|
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 format_len is larger than expected, read only as much data as we've space for
|
||||||
if (nDump > 0)
|
if (nDump > 0)
|
||||||
{
|
{
|
||||||
|
@ -669,7 +665,6 @@ uint WavInFile::getSampleRate() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint WavInFile::getDataSizeInBytes() const
|
uint WavInFile::getDataSizeInBytes() const
|
||||||
{
|
{
|
||||||
return header.data.data_len;
|
return header.data.data_len;
|
||||||
|
@ -703,7 +698,6 @@ uint WavInFile::getElapsedMS() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Class WavOutFile
|
// Class WavOutFile
|
||||||
|
@ -742,7 +736,6 @@ WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WavOutFile::~WavOutFile()
|
WavOutFile::~WavOutFile()
|
||||||
{
|
{
|
||||||
finishHeader();
|
finishHeader();
|
||||||
|
@ -751,7 +744,6 @@ WavOutFile::~WavOutFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
|
void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
|
||||||
{
|
{
|
||||||
// fill in the 'riff' part..
|
// fill in the 'riff' part..
|
||||||
|
@ -779,8 +771,8 @@ void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
|
||||||
|
|
||||||
// fill in the 'fact' part...
|
// fill in the 'fact' part...
|
||||||
memcpy(&(header.fact.fact_field), factStr, 4);
|
memcpy(&(header.fact.fact_field), factStr, 4);
|
||||||
header.fact.fact_len = 4;
|
header.fact.fact_len = 4;
|
||||||
header.fact.fact_sample_len = 0;
|
header.fact.fact_sample_len = 0;
|
||||||
|
|
||||||
// fill in the 'data' part..
|
// fill in the 'data' part..
|
||||||
|
|
||||||
|
@ -796,13 +788,12 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void WavOutFile::writeHeader()
|
void WavOutFile::writeHeader()
|
||||||
{
|
{
|
||||||
WavHeader hdrTemp;
|
WavHeader hdrTemp;
|
||||||
|
@ -835,7 +826,6 @@ 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;
|
||||||
|
@ -856,7 +846,6 @@ 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;
|
||||||
|
@ -935,7 +924,7 @@ 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;
|
||||||
short *temp = (short*)getConvBuffer(numBytes);
|
void *temp = getConvBuffer(numBytes + 7); // round bit up to avoid buffer overrun with 24bit-value assignment
|
||||||
|
|
||||||
switch (bytesPerSample)
|
switch (bytesPerSample)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -58,7 +51,7 @@ typedef unsigned int uint;
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char riff_char[4];
|
char riff_char[4];
|
||||||
int package_len;
|
uint package_len;
|
||||||
char wave[4];
|
char wave[4];
|
||||||
} WavRiff;
|
} WavRiff;
|
||||||
|
|
||||||
|
@ -66,21 +59,21 @@ typedef struct
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char fmt[4];
|
char fmt[4];
|
||||||
int format_len;
|
unsigned int format_len;
|
||||||
short fixed;
|
unsigned short fixed;
|
||||||
short channel_number;
|
unsigned short channel_number;
|
||||||
int sample_rate;
|
unsigned int sample_rate;
|
||||||
int byte_rate;
|
unsigned int byte_rate;
|
||||||
short byte_per_sample;
|
unsigned short byte_per_sample;
|
||||||
short bits_per_sample;
|
unsigned short bits_per_sample;
|
||||||
} 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];
|
||||||
int fact_len;
|
uint fact_len;
|
||||||
uint fact_sample_len;
|
uint fact_sample_len;
|
||||||
} WavFact;
|
} WavFact;
|
||||||
|
|
||||||
/// WAV audio file 'data' section header
|
/// WAV audio file 'data' section header
|
||||||
|
@ -225,7 +218,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Class for writing WAV audio files.
|
/// Class for writing WAV audio files.
|
||||||
class WavOutFile : protected WavFileBase
|
class WavOutFile : protected WavFileBase
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -75,7 +68,6 @@ using namespace soundtouch;
|
||||||
#define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
|
#define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* Implementation of the class 'AAFilter'
|
* Implementation of the class 'AAFilter'
|
||||||
|
@ -90,14 +82,12 @@ AAFilter::AAFilter(uint len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AAFilter::~AAFilter()
|
AAFilter::~AAFilter()
|
||||||
{
|
{
|
||||||
delete pFIR;
|
delete pFIR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Sets new anti-alias filter cut-off edge frequency, scaled to
|
// Sets new anti-alias filter cut-off edge frequency, scaled to
|
||||||
// sampling frequency (nyquist frequency = 0.5).
|
// sampling frequency (nyquist frequency = 0.5).
|
||||||
// The filter will cut frequencies higher than the given frequency.
|
// 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
|
// Sets number of FIR filter taps
|
||||||
void AAFilter::setLength(uint newLength)
|
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
|
// Calculates coefficients for a low-pass FIR filter using Hamming window
|
||||||
void AAFilter::calculateCoeffs()
|
void AAFilter::calculateCoeffs()
|
||||||
{
|
{
|
||||||
|
@ -177,12 +165,10 @@ void AAFilter::calculateCoeffs()
|
||||||
for (i = 0; i < length; i ++)
|
for (i = 0; i < length; i ++)
|
||||||
{
|
{
|
||||||
temp = work[i] * scaleCoeff;
|
temp = work[i] * scaleCoeff;
|
||||||
//#if SOUNDTOUCH_INTEGER_SAMPLES
|
|
||||||
// scale & round to nearest integer
|
// scale & round to nearest integer
|
||||||
temp += (temp >= 0) ? 0.5 : -0.5;
|
temp += (temp >= 0) ? 0.5 : -0.5;
|
||||||
// ensure no overfloods
|
// ensure no overfloods
|
||||||
assert(temp >= -32768 && temp <= 32767);
|
assert(temp >= -32768 && temp <= 32767);
|
||||||
//#endif
|
|
||||||
coeffs[i] = (SAMPLETYPE)temp;
|
coeffs[i] = (SAMPLETYPE)temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -54,50 +47,62 @@
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define _USE_MATH_DEFINES
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <cfloat>
|
||||||
#include "FIFOSampleBuffer.h"
|
#include "FIFOSampleBuffer.h"
|
||||||
#include "PeakFinder.h"
|
#include "PeakFinder.h"
|
||||||
#include "BPMDetect.h"
|
#include "BPMDetect.h"
|
||||||
|
|
||||||
using namespace soundtouch;
|
using namespace soundtouch;
|
||||||
|
|
||||||
#define INPUT_BLOCK_SAMPLES 2048
|
// algorithm input sample block size
|
||||||
#define DECIMATED_BLOCK_SAMPLES 256
|
static const int INPUT_BLOCK_SIZE = 2048;
|
||||||
|
|
||||||
|
// decimated sample block size
|
||||||
|
static const int DECIMATED_BLOCK_SIZE = 256;
|
||||||
|
|
||||||
/// Target sample rate after decimation
|
/// 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
|
/// 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
|
/// 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.
|
||||||
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:
|
// Enable following define to create bpm analysis file:
|
||||||
|
|
||||||
// #define _CREATE_BPM_DEBUG_FILE
|
//#define _CREATE_BPM_DEBUG_FILE
|
||||||
|
|
||||||
#ifdef _CREATE_BPM_DEBUG_FILE
|
#ifdef _CREATE_BPM_DEBUG_FILE
|
||||||
|
|
||||||
#define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt"
|
static void _SaveDebugData(const char *name, const float *data, int minpos, int maxpos, double coeff)
|
||||||
|
|
||||||
static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff)
|
|
||||||
{
|
{
|
||||||
FILE *fptr = fopen(DEBUGFILE_NAME, "wt");
|
FILE *fptr = fopen(name, "wt");
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (fptr)
|
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 ++)
|
for (i = minpos; i < maxpos; i ++)
|
||||||
{
|
{
|
||||||
fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[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);
|
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
|
#else
|
||||||
#define _SaveDebugData(a,b,c,d)
|
#define _SaveDebugData(name, a,b,c,d)
|
||||||
|
#define _SaveDebugBeatPos(name, b)
|
||||||
#endif
|
#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->sampleRate = aSampleRate;
|
||||||
this->channels = numChannels;
|
this->channels = numChannels;
|
||||||
|
|
||||||
|
@ -121,13 +185,15 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate)
|
||||||
decimateCount = 0;
|
decimateCount = 0;
|
||||||
|
|
||||||
// choose decimation factor so that result is approx. 1000 Hz
|
// choose decimation factor so that result is approx. 1000 Hz
|
||||||
decimateBy = sampleRate / target_srate;
|
decimateBy = sampleRate / TARGET_SRATE;
|
||||||
assert(decimateBy > 0);
|
if ((decimateBy <= 0) || (decimateBy * DECIMATED_BLOCK_SIZE < INPUT_BLOCK_SIZE))
|
||||||
assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES);
|
{
|
||||||
|
ST_THROW_RT_ERROR("Too small samplerate");
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate window length & starting item according to desired min & max bpms
|
// Calculate window length & starting item according to desired min & max bpms
|
||||||
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
|
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
|
||||||
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM);
|
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM_RANGE);
|
||||||
|
|
||||||
assert(windowLen > windowStart);
|
assert(windowLen > windowStart);
|
||||||
|
|
||||||
|
@ -135,23 +201,38 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate)
|
||||||
xcorr = new float[windowLen];
|
xcorr = new float[windowLen];
|
||||||
memset(xcorr, 0, windowLen * sizeof(float));
|
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
|
// allocate processing buffer
|
||||||
buffer = new FIFOSampleBuffer();
|
buffer = new FIFOSampleBuffer();
|
||||||
// we do processing in mono mode
|
// we do processing in mono mode
|
||||||
buffer->setChannels(1);
|
buffer->setChannels(1);
|
||||||
buffer->clear();
|
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()
|
BPMDetect::~BPMDetect()
|
||||||
{
|
{
|
||||||
delete[] xcorr;
|
delete[] xcorr;
|
||||||
|
delete[] beatcorr_ringbuff;
|
||||||
|
delete[] hamw;
|
||||||
|
delete[] hamw2;
|
||||||
delete buffer;
|
delete buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// 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.
|
||||||
///
|
///
|
||||||
|
@ -208,7 +289,6 @@ int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Calculates autocorrelation function of the sample history buffer
|
// Calculates autocorrelation function of the sample history buffer
|
||||||
void BPMDetect::updateXCorr(int process_samples)
|
void BPMDetect::updateXCorr(int process_samples)
|
||||||
{
|
{
|
||||||
|
@ -216,22 +296,30 @@ void BPMDetect::updateXCorr(int process_samples)
|
||||||
SAMPLETYPE *pBuffer;
|
SAMPLETYPE *pBuffer;
|
||||||
|
|
||||||
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
|
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
|
||||||
|
assert(process_samples == XCORR_UPDATE_SEQUENCE);
|
||||||
|
|
||||||
pBuffer = buffer->ptrBegin();
|
pBuffer = buffer->ptrBegin();
|
||||||
|
|
||||||
// calculate decay factor for xcorr filtering
|
// 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
|
#pragma omp parallel for
|
||||||
for (offs = windowStart; offs < windowLen; offs ++)
|
for (offs = windowStart; offs < windowLen; offs ++)
|
||||||
{
|
{
|
||||||
LONG_SAMPLETYPE sum;
|
double sum;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
sum = 0;
|
sum = 0;
|
||||||
for (i = 0; i < process_samples; i ++)
|
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.
|
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)
|
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
|
// iterate so that max INPUT_BLOCK_SAMPLES processed per iteration
|
||||||
while (numSamples > 0)
|
while (numSamples > 0)
|
||||||
|
@ -251,7 +422,7 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
|
||||||
int block;
|
int block;
|
||||||
int decSamples;
|
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
|
// decimate. note that converts to mono at the same time
|
||||||
decSamples = decimate(decimated, samples, block);
|
decSamples = decimate(decimated, samples, block);
|
||||||
|
@ -261,31 +432,60 @@ void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
|
||||||
buffer->putSamples(decimated, decSamples);
|
buffer->putSamples(decimated, decSamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when the buffer has enought samples for processing...
|
// when the buffer has enough samples for processing...
|
||||||
while ((int)buffer->numSamples() >= windowLen + xcorr_update_sequence)
|
int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE);
|
||||||
|
while ((int)buffer->numSamples() >= req)
|
||||||
{
|
{
|
||||||
// ... calculate autocorrelations for oldest samples...
|
// ... update autocorrelations...
|
||||||
updateXCorr(xcorr_update_sequence);
|
updateXCorr(XCORR_UPDATE_SEQUENCE);
|
||||||
// ... and remove these from the buffer
|
// ...update beat position calculation...
|
||||||
buffer->receiveSamples(xcorr_update_sequence);
|
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()
|
void BPMDetect::removeBias()
|
||||||
{
|
{
|
||||||
int i;
|
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 ++)
|
for (i = windowStart; i < windowLen; i ++)
|
||||||
{
|
{
|
||||||
|
xcorr[i] -= (float)(b * i);
|
||||||
if (xcorr[i] < minval)
|
if (xcorr[i] < minval)
|
||||||
{
|
{
|
||||||
minval = xcorr[i];
|
minval = xcorr[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// subtract min.value
|
||||||
for (i = windowStart; i < windowLen; i ++)
|
for (i = windowStart; i < windowLen; i ++)
|
||||||
{
|
{
|
||||||
xcorr[i] -= minval;
|
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()
|
float BPMDetect::getBpm()
|
||||||
{
|
{
|
||||||
double peakPos;
|
double peakPos;
|
||||||
double coeff;
|
double coeff;
|
||||||
PeakFinder peakFinder;
|
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
|
// remove bias from xcorr data
|
||||||
removeBias();
|
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
|
// 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);
|
assert(decimateBy != 0);
|
||||||
if (peakPos < 1e-9) return 0.0; // detection failed.
|
if (peakPos < 1e-9) return 0.0; // detection failed.
|
||||||
|
|
||||||
|
_SaveDebugBeatPos("soundtouch-detected-beats.txt", beats);
|
||||||
|
|
||||||
// calculate BPM
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -80,7 +73,8 @@ void FIFOSampleBuffer::setChannels(int numChannels)
|
||||||
{
|
{
|
||||||
uint usedBytes;
|
uint usedBytes;
|
||||||
|
|
||||||
assert(numChannels > 0);
|
if (!verifyNumberOfChannels(numChannels)) return;
|
||||||
|
|
||||||
usedBytes = channels * samplesInBuffer;
|
usedBytes = channels * samplesInBuffer;
|
||||||
channels = (uint)numChannels;
|
channels = (uint)numChannels;
|
||||||
samplesInBuffer = usedBytes / channels;
|
samplesInBuffer = usedBytes / channels;
|
||||||
|
@ -131,7 +125,7 @@ void FIFOSampleBuffer::putSamples(uint nSamples)
|
||||||
//
|
//
|
||||||
// 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
|
||||||
// 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.
|
// 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
|
||||||
|
@ -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
|
// 'capacityRequirement' number of samples. The buffer is grown in steps of
|
||||||
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
|
// 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.
|
// 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;
|
return samplesInBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -75,6 +68,7 @@ FIRFilter::~FIRFilter()
|
||||||
delete[] filterCoeffs;
|
delete[] filterCoeffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Usual C-version of the filter routine for stereo sound
|
// Usual C-version of the filter routine for stereo sound
|
||||||
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
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
|
// Usual C-version of the filter routine for mono sound
|
||||||
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
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.
|
// 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'
|
||||||
|
@ -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
|
// 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 s)
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -8,10 +8,6 @@
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// $Id: InterpolateCubic.cpp 179 2014-01-06 18:41:42Z oparviai $
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// License :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -8,10 +8,6 @@
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// $Id: InterpolateCubic.h 225 2015-07-26 14:45:48Z oparviai $
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// License :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -8,10 +8,6 @@
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// $Id: InterpolateLinear.cpp 225 2015-07-26 14:45:48Z oparviai $
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// License :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -8,10 +8,6 @@
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// $Id: InterpolateLinear.h 225 2015-07-26 14:45:48Z oparviai $
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// License :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -42,7 +38,7 @@
|
||||||
namespace soundtouch
|
namespace soundtouch
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Linear transposer class that uses integer arithmetics
|
/// Linear transposer class that uses integer arithmetic
|
||||||
class InterpolateLinearInteger : public TransposerBase
|
class InterpolateLinearInteger : public TransposerBase
|
||||||
{
|
{
|
||||||
protected:
|
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
|
class InterpolateLinearFloat : public TransposerBase
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -13,10 +13,6 @@
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// $Id: InterpolateShannon.cpp 195 2014-04-06 15:57:21Z oparviai $
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// License :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -13,10 +13,6 @@
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// $Id: InterpolateShannon.h 225 2015-07-26 14:45:48Z oparviai $
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// License :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -64,7 +57,7 @@ int PeakFinder::findTop(const float *data, int peakpos) const
|
||||||
|
|
||||||
refvalue = data[peakpos];
|
refvalue = data[peakpos];
|
||||||
|
|
||||||
// seek within ±10 points
|
// seek within <EFBFBD>10 points
|
||||||
start = peakpos - 10;
|
start = peakpos - 10;
|
||||||
if (start < minPos) start = minPos;
|
if (start < minPos) start = minPos;
|
||||||
end = peakpos + 10;
|
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
|
/// get exact center of peak near given position by calculating local mass of center
|
||||||
double PeakFinder::getPeakCenter(const float *data, int peakpos) const
|
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)
|
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
|
// - 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 = 3; i < 10; i ++)
|
for (i = 1; i < 3; i ++)
|
||||||
{
|
{
|
||||||
double peaktmp, harmonic;
|
double peaktmp, harmonic;
|
||||||
int i1,i2;
|
int i1,i2;
|
||||||
|
|
||||||
harmonic = (double)i * 0.5;
|
harmonic = (double)pow(2.0, i);
|
||||||
peakpos = (int)(highPeak / harmonic + 0.5f);
|
peakpos = (int)(highPeak / harmonic + 0.5f);
|
||||||
if (peakpos < minPos) break;
|
if (peakpos < minPos) break;
|
||||||
peakpos = findTop(data, peakpos); // seek true local maximum index
|
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
|
// accept harmonic peak if
|
||||||
// (a) it is found
|
// (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
|
// (c) has at least half x-corr value of the max. peak
|
||||||
|
|
||||||
double diff = harmonic * peaktmp / highPeak;
|
double diff = harmonic * peaktmp / highPeak;
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -51,8 +44,8 @@ protected:
|
||||||
|
|
||||||
/// Calculates the mass center between given vector items.
|
/// Calculates the mass center between given vector items.
|
||||||
double calcMassCenter(const float *data, ///< Data vector.
|
double calcMassCenter(const float *data, ///< Data vector.
|
||||||
int firstPos, ///< Index of first vector item beloging to the peak.
|
int firstPos, ///< Index of first vector item belonging to the peak.
|
||||||
int lastPos ///< Index of last vector item beloging to the peak.
|
int lastPos ///< Index of last vector item belonging to the peak.
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/// Finds the data vector index where the monotoniously decreasing signal crosses the
|
/// Finds the data vector index where the monotoniously decreasing signal crosses the
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -57,7 +50,13 @@ TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
|
||||||
// Constructor
|
// Constructor
|
||||||
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
|
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
|
// Instantiates the anti-alias filter
|
||||||
pAAFilter = new AAFilter(64);
|
pAAFilter = new AAFilter(64);
|
||||||
|
@ -65,7 +64,6 @@ RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RateTransposer::~RateTransposer()
|
RateTransposer::~RateTransposer()
|
||||||
{
|
{
|
||||||
delete pAAFilter;
|
delete pAAFilter;
|
||||||
|
@ -73,11 +71,13 @@ RateTransposer::~RateTransposer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
||||||
void RateTransposer::enableAAFilter(bool newMode)
|
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;
|
bUseAAFilter = newMode;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,7 +94,6 @@ 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)
|
||||||
|
@ -177,11 +176,10 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
|
||||||
// Sets the number of channels, 1 = mono, 2 = stereo
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
void RateTransposer::setChannels(int nChannels)
|
void RateTransposer::setChannels(int nChannels)
|
||||||
{
|
{
|
||||||
assert(nChannels > 0);
|
if (!verifyNumberOfChannels(nChannels) ||
|
||||||
|
(pTransposer->numChannels == nChannels)) return;
|
||||||
|
|
||||||
if (pTransposer->numChannels == nChannels) return;
|
|
||||||
pTransposer->setChannels(nChannels);
|
pTransposer->setChannels(nChannels);
|
||||||
|
|
||||||
inputBuffer.setChannels(nChannels);
|
inputBuffer.setChannels(nChannels);
|
||||||
midBuffer.setChannels(nChannels);
|
midBuffer.setChannels(nChannels);
|
||||||
outputBuffer.setChannels(nChannels);
|
outputBuffer.setChannels(nChannels);
|
||||||
|
@ -287,7 +285,7 @@ void TransposerBase::setRate(double newRate)
|
||||||
TransposerBase *TransposerBase::newInstance()
|
TransposerBase *TransposerBase::newInstance()
|
||||||
{
|
{
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
#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;
|
return ::new InterpolateLinearInteger;
|
||||||
#else
|
#else
|
||||||
switch (algorithm)
|
switch (algorithm)
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -132,21 +125,9 @@ public:
|
||||||
RateTransposer();
|
RateTransposer();
|
||||||
virtual ~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
|
/// Returns the output buffer object
|
||||||
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
||||||
|
|
||||||
/// Returns the store buffer object
|
|
||||||
// FIFOSamplePipe *getStore() { return &storeBuffer; };
|
|
||||||
|
|
||||||
/// Return anti-alias filter object
|
/// Return anti-alias filter object
|
||||||
AAFilter *getAAFilter();
|
AAFilter *getAAFilter();
|
||||||
|
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -118,7 +111,6 @@ SoundTouch::SoundTouch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SoundTouch::~SoundTouch()
|
SoundTouch::~SoundTouch()
|
||||||
{
|
{
|
||||||
delete pRateTransposer;
|
delete pRateTransposer;
|
||||||
|
@ -126,7 +118,6 @@ SoundTouch::~SoundTouch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Get SoundTouch library version string
|
/// Get SoundTouch library version string
|
||||||
const char *SoundTouch::getVersionString()
|
const char *SoundTouch::getVersionString()
|
||||||
{
|
{
|
||||||
|
@ -146,18 +137,14 @@ uint SoundTouch::getVersionId()
|
||||||
// Sets the number of channels, 1 = mono, 2 = stereo
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
void SoundTouch::setChannels(uint numChannels)
|
void SoundTouch::setChannels(uint numChannels)
|
||||||
{
|
{
|
||||||
/*if (numChannels != 1 && numChannels != 2)
|
if (!verifyNumberOfChannels(numChannels)) return;
|
||||||
{
|
|
||||||
//ST_THROW_RT_ERROR("Illegal number of channels");
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
channels = numChannels;
|
channels = numChannels;
|
||||||
pRateTransposer->setChannels((int)numChannels);
|
pRateTransposer->setChannels((int)numChannels);
|
||||||
pTDStretch->setChannels((int)numChannels);
|
pTDStretch->setChannels((int)numChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Sets new rate control value. Normal rate = 1.0, smaller values
|
// Sets new rate control value. Normal rate = 1.0, smaller values
|
||||||
// represent slower rate, larger faster rates.
|
// represent slower rate, larger faster rates.
|
||||||
void SoundTouch::setRate(double newRate)
|
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
|
// Sets new rate control value as a difference in percents compared
|
||||||
// to the original rate (-50 .. +100 %)
|
// to the original rate (-50 .. +100 %)
|
||||||
void SoundTouch::setRateChange(double newRate)
|
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
|
// Sets new tempo control value. Normal tempo = 1.0, smaller values
|
||||||
// represent slower tempo, larger faster tempo.
|
// represent slower tempo, larger faster tempo.
|
||||||
void SoundTouch::setTempo(double newTempo)
|
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
|
// Sets new tempo control value as a difference in percents compared
|
||||||
// to the original tempo (-50 .. +100 %)
|
// to the original tempo (-50 .. +100 %)
|
||||||
void SoundTouch::setTempoChange(double newTempo)
|
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
|
// Sets new pitch control value. Original pitch = 1.0, smaller values
|
||||||
// represent lower pitches, larger values higher pitch.
|
// represent lower pitches, larger values higher pitch.
|
||||||
void SoundTouch::setPitch(double newPitch)
|
void SoundTouch::setPitch(double newPitch)
|
||||||
|
@ -207,7 +190,6 @@ void SoundTouch::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 SoundTouch::setPitchOctaves(double newPitch)
|
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
|
// Sets pitch change in semi-tones compared to the original pitch
|
||||||
// (-12 .. +12)
|
// (-12 .. +12)
|
||||||
void SoundTouch::setPitchSemiTones(int newPitch)
|
void SoundTouch::setPitchSemiTones(int newPitch)
|
||||||
|
@ -226,7 +207,6 @@ void SoundTouch::setPitchSemiTones(int newPitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SoundTouch::setPitchSemiTones(double newPitch)
|
void SoundTouch::setPitchSemiTones(double newPitch)
|
||||||
{
|
{
|
||||||
setPitchOctaves(newPitch / 12.0);
|
setPitchOctaves(newPitch / 12.0);
|
||||||
|
@ -286,9 +266,9 @@ void SoundTouch::calcEffectiveRateAndTempo()
|
||||||
// Sets sample rate.
|
// Sets sample rate.
|
||||||
void SoundTouch::setSampleRate(uint srate)
|
void SoundTouch::setSampleRate(uint srate)
|
||||||
{
|
{
|
||||||
bSrateSet = true;
|
|
||||||
// set sample rate, leave other tempo changer parameters as they are.
|
// set sample rate, leave other tempo changer parameters as they are.
|
||||||
pTDStretch->setParameters((int)srate);
|
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");
|
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
|
// 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);
|
||||||
|
@ -376,7 +340,6 @@ void SoundTouch::flush()
|
||||||
delete[] buff;
|
delete[] buff;
|
||||||
|
|
||||||
// Clear input buffers
|
// Clear input buffers
|
||||||
// pRateTransposer->clearInput();
|
|
||||||
pTDStretch->clearInput();
|
pTDStretch->clearInput();
|
||||||
// yet leave the output intouched as that's where the
|
// yet leave the output intouched as that's where the
|
||||||
// flushed samples are!
|
// 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
|
// Clears all the samples in the object's output and internal processing
|
||||||
// buffers.
|
// buffers.
|
||||||
void SoundTouch::clear()
|
void SoundTouch::clear()
|
||||||
|
@ -525,7 +487,6 @@ void SoundTouch::clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns number of samples currently unprocessed.
|
/// Returns number of samples currently unprocessed.
|
||||||
uint SoundTouch::numUnprocessedSamples() const
|
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 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.
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -134,8 +127,13 @@ 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
|
||||||
if (aSampleRate > 0) this->sampleRate = aSampleRate;
|
if (aSampleRate > 0)
|
||||||
if (aOverlapMS > 0) this->overlapMs = aOverlapMS;
|
{
|
||||||
|
if (aSampleRate > 192000) ST_THROW_RT_ERROR("Error: Excessive samplerate");
|
||||||
|
this->sampleRate = aSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aOverlapMS > 0) this->overlapMs = aOverlapMS;
|
||||||
|
|
||||||
if (aSequenceMS > 0)
|
if (aSequenceMS > 0)
|
||||||
{
|
{
|
||||||
|
@ -362,7 +360,7 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
|
||||||
// with improved precision
|
// with improved precision
|
||||||
//
|
//
|
||||||
// Based on testing:
|
// 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
|
// - 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
|
||||||
|
@ -519,7 +517,7 @@ void TDStretch::clearCrossCorrState()
|
||||||
void TDStretch::calcSeqParameters()
|
void TDStretch::calcSeqParameters()
|
||||||
{
|
{
|
||||||
// Adjust tempo param according to tempo, so that variating processing sequence length is used
|
// 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_LOW 0.5 // auto setting low tempo range (-50%)
|
||||||
#define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%)
|
#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
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
void TDStretch::setChannels(int numChannels)
|
void TDStretch::setChannels(int numChannels)
|
||||||
{
|
{
|
||||||
assert(numChannels > 0);
|
if (!verifyNumberOfChannels(numChannels) ||
|
||||||
if (channels == numChannels) return;
|
(channels == numChannels)) return;
|
||||||
// assert(numChannels == 1 || numChannels == 2);
|
|
||||||
|
|
||||||
channels = numChannels;
|
channels = numChannels;
|
||||||
inputBuffer.setChannels(channels);
|
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
|
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -164,7 +157,6 @@ protected:
|
||||||
void calcSeqParameters();
|
void calcSeqParameters();
|
||||||
void adaptNormalizer();
|
void adaptNormalizer();
|
||||||
|
|
||||||
|
|
||||||
/// Changes the tempo of the given sound samples.
|
/// Changes the tempo of the given sound samples.
|
||||||
/// Returns amount of samples returned in the "output" buffer.
|
/// Returns amount of samples returned in the "output" 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
|
||||||
|
@ -249,7 +241,6 @@ public:
|
||||||
return seekWindowLength - overlapLength;
|
return seekWindowLength - overlapLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// return approximate initial input-output latency
|
/// return approximate initial input-output latency
|
||||||
int getLatency() const
|
int getLatency() const
|
||||||
{
|
{
|
||||||
|
@ -258,7 +249,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Implementation-specific class declarations:
|
// Implementation-specific class declarations:
|
||||||
|
|
||||||
#ifdef SOUNDTOUCH_ALLOW_MMX
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -75,7 +68,6 @@ void disableExtensions(uint dwDisableMask)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Checks which instruction set extensions are supported by the CPU.
|
/// Checks which instruction set extensions are supported by the CPU.
|
||||||
uint detectCPUextensions(void)
|
uint detectCPUextensions(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
@ -224,7 +217,6 @@ void TDStretchMMX::clearCrossCorrState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// MMX-optimized version of the function overlapStereo
|
// MMX-optimized version of the function overlapStereo
|
||||||
void TDStretchMMX::overlapStereo(short *output, const short *input) const
|
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
|
// mmx-optimized version of the filter routine for stereo sound
|
||||||
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
|
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;
|
return (numSamples & 0xfffffffe) - length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// workaround to not complain about empty module
|
||||||
|
bool _dontcomplain_mmx_empty;
|
||||||
|
|
||||||
#endif // SOUNDTOUCH_ALLOW_MMX
|
#endif // SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|
|
@ -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 :
|
// License :
|
||||||
//
|
//
|
||||||
// SoundTouch audio processing library
|
// SoundTouch audio processing library
|
||||||
|
|
Loading…
Reference in New Issue