diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/include/soundtouch')
38 files changed, 9869 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/COPYING.TXT b/Src/external_dependencies/openmpt-trunk/include/soundtouch/COPYING.TXT new file mode 100644 index 00000000..b6e870bf --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/COPYING.TXT @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/OpenMPT.txt b/Src/external_dependencies/openmpt-trunk/include/soundtouch/OpenMPT.txt new file mode 100644 index 00000000..db61542e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/OpenMPT.txt @@ -0,0 +1,7 @@ +SoundTouch Audio Processing Library
+https://www.surina.net/soundtouch/
+version 2.3.1
+Some unused files (SoundStretch, Android library, VS solutions...) have been removed.
+
+For building, premake is used to generate Visual Studio project files.
+See ../build/premake/ for details.
diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/README.html b/Src/external_dependencies/openmpt-trunk/include/soundtouch/README.html new file mode 100644 index 00000000..1efe7a6e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/README.html @@ -0,0 +1,999 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + +<head> + <title>SoundTouch library README</title> + <meta http-equiv="Content-Language" content="en-us"> + <meta name="author" content="Olli Parviainen"> + <meta name="description" content="Readme file for SoundTouch audio processing library"> + <style> + body { + font-family: Arial, Helvetica; + } + </style> +</head> + +<body class="normal"> + <hr> + <h1>SoundTouch audio processing library v2.3.1</h1> + <p class="normal">SoundTouch library Copyright © Olli Parviainen 2001-2021</p> + <hr> + <h2>1. Introduction </h2> + <p>SoundTouch is an open-source audio processing library that allows + changing the sound tempo, pitch and playback rate parameters + independently from each other, i.e.:</p> + <ul> + <li> Sound tempo can be increased or decreased while maintaining the + original pitch</li> + <li> Sound pitch can be increased or decreased while maintaining the + original tempo</li> + <li> Change playback rate that affects both tempo and pitch at the + same time</li> + <li> Choose any combination of tempo/pitch/rate</li> + </ul> + <h3>1.1 Contact information </h3> + <p>Author email: oparviai 'at' iki.fi </p> + <p>SoundTouch WWW page: <a href="http://soundtouch.surina.net">http://soundtouch.surina.net</a></p> + <p>SoundTouch git repository: <a + href="https://gitlab.com/soundtouch/soundtouch.git">https://gitlab.com/soundtouch/soundtouch.git</a></p> + <hr> + <h2>2. Compiling SoundTouch</h2> + <p>Before compiling, notice that you can choose the sample data format if it's + desirable to use 16bit integer sample data instead of floating point samples. See + section "sample data format" for more information.</p> + <p>Also notice that SoundTouch can use OpenMP instructions for parallel + computation to accelerate the runtime processing speed in multi-core systems, + however, these improvements need to be separately enabled before compiling. See + OpenMP notes in Chapter 3 below.</p> + <h3>2.1. Building in Microsoft Windows</h3> + <p>Project files for Microsoft Visual C++ are supplied with the source + code package. Go to Microsoft WWW page to download + <a href="http://www.visualstudio.com/en-US/products/visual-studio-express-vs"> + Microsoft Visual Studio Express version for free</a>. + </p> + <p>To build the binaries with Visual C++ compiler, either run + "make-win.bat" script, or open the appropriate project files in source + code directories with Visual Studio. The final executable will appear + under the "SoundTouch\bin" directory. If using the Visual Studio IDE + instead of the make-win.bat script, directories bin and lib may need to + be created manually to the SoundTouch package root for the final + executables. The make-win.bat script creates these directories + automatically. </p> + <p><strong>C# example</strong>: The source code package includes also a C# example + application for Windows that shows how to invoke SoundTouch.dll + dynamic-load library for processing mp3 audio. + <p><strong>OpenMP NOTE</strong>: If activating the OpenMP parallel computing in + the compilation, the target program will require additional vcomp dll library to + properly run. In Visual C++ 9.0 these libraries can be found in the following + folders.</p> + <ul> + <li>x86 32bit: C:\Program Files (x86)\Microsoft Visual Studio + 9.0\VC\redist\x86\Microsoft.VC90.OPENMP\vcomp90.dll</li> + <li>x64 64bit: C:\Program Files (x86)\Microsoft Visual Studio + 9.0\VC\redist\amd64\Microsoft.VC90.OPENMP\vcomp90.dll</li> + </ul> + <p>In other VC++ versions the required library will be expectedly found in similar + "redist" location.</p> + <p>Notice that as minor demonstration of a "dll hell" phenomenon both the 32-bit + and 64-bit version of vcomp90.dll have the same filename but different contents, + thus choose the proper version to allow the program to start.</p> + <h3>2.2. Building in Gnu platforms</h3> + <p>The SoundTouch library compiles in practically any platform + supporting GNU compiler (GCC) tools. + <h4>2.2.1 Compiling with autotools</h4> + <p>To install build prerequisites for 'autotools' tool chain:</p> + <pre> sudo apt-get install automake autoconf libtool build-essential</pre> + <p>To build and install the binaries, run the following commands in + /soundtouch directory:</p> + <table border="0" cellpadding="0" cellspacing="4"> + <tbody> + <tr> + <td style="vertical-align: top;"> + <pre>./bootstrap -</pre> + </td> + <td style="vertical-align: top;">Creates "configure" file with + local autoconf/automake toolset.<br> + </td> + </tr> + <tr valign="top"> + <td> + <pre>./configure -</pre> + </td> + <td> + <p>Configures the SoundTouch package for the local environment. + Notice that "configure" file is not available before running the + "./bootstrap" command as above.<br> + </p> + </td> + </tr> + <tr valign="top"> + <td> + <pre>make -</pre> + </td> + <td> + <p>Builds the SoundTouch library & SoundStretch utility. You can + optionally add "-j" switch after "make" to speed up the compilation in + multi-core systems.</p> + </td> + </tr> + <tr valign="top"> + <td> + <pre>make install -</pre> + </td> + <td> + <p>Installs the SoundTouch & BPM libraries to <b>/usr/local/lib</b> + and SoundStretch utility to <b>/usr/local/bin</b>. Please notice that + 'root' privileges may be required to install the binaries to the + destination locations.</p> + </td> + </tr> + </tbody> + </table> + + <b>Compiling portable Shared Library / DLL version</b> + <p> The GNU autotools compilation does not automatically create a shared-library version of + SoundTouch (.so or .dll) that features position-independent code and C-language + api that are more suitable for cross-language development than C++ libraries.</p> + <p> Use script "make-gnu-dll-sh" to build a portable dynamic library version if such is desired.</p> + + <h4><b>2.2.2 Compiling with cmake</b></h4> + <p>'cmake' build scripts are provided as an alternative to the autotools toolchain.</p> + <p>To install cmake build prerequisites:</p> + <pre> sudo apt-get install libtool build-essential cmake</pre> + <p>To build:</p> + <pre> + cmake . + make -j + make install</pre> + <p>To compile the additional portable Shared Library / DLL version with the native C-language API:</p> + <pre> + cmake . -DSOUNDTOUCH_DLL=ON + make -j + make install</pre> + + <h3>2.3. Building in Android</h3> + <p>Android compilation instructions are within the + source code package, see file "<b>source/Android-lib/README-SoundTouch-Android.html</b>" + in the source code package. </p> + <p>The Android compilation automatically builds separate .so library binaries + for ARM, X86 and MIPS processor architectures. For optimal device support, + include all these .so library binaries into the Android .apk application + package, so the target Android device can automatically choose the proper + library binary version to use.</p> + <p>The <strong>source/Android-lib</strong> folder includes also an Android + example application that processes WAV audio files using SoundTouch library in + Android devices.</p> + + <h3>2.4. Building in Mac</h3> + <p>Install autoconf tool as instructed in <a + href="http://macappstore.org/autoconf/">http://macappstore.org/autoconf/</a>, or alternatively the 'cmake' toolchain.</p> + <p>Then, build as described above in section "Building in Gnu platforms".</p> + + <hr> + <h2>3. About implementation & Usage tips <h3>3.1. Supported sample data formats</h3> + <p>The sample data format can be chosen between 16bit signed integer + and 32bit floating point values.</p> + </p> The default sample type is 32bit floating point format, + which also provides better sound quality than integer format because + integer algorithms need to scale already intermediate calculation results to + avoid integer overflows. These early integer scalings can slightly degrade + output quality.</p> + <p> In Windows environment, the sample data format is chosen in file + "STTypes.h" by choosing one of the following defines:</p> + <ul> + <li> <span style="font-weight: bold;">#define + SOUNDTOUCH_INTEGER_SAMPLES</span> for 16bit signed integer</li> + <li> <span style="font-weight: bold;">#define </span><span style="font-weight: bold;">SOUNDTOUCH_</span><span + style="font-weight: bold;">FLOAT_SAMPLES</span> for 32bit floating + point</li> + </ul> + <p> In GNU environment, the floating sample format is used by default, + but integer sample format can be chosen by giving the following switch + to the configure script: </p> + <blockquote> + <pre>./configure --enable-integer-samples</pre> + </blockquote> + <p>The sample data can have either single (mono) or double (stereo) + audio channel. Stereo data is interleaved so that every other data + value is for left channel and every second for right channel. Notice + that while it'd be possible in theory to process stereo sound as two + separate mono channels, this isn't recommended because processing the + channels separately would result in losing the phase coherency between + the channels, which consequently would ruin the stereo effect.</p> + <p>Sample rates between 8000-48000H are supported.</p> + <h3>3.2. Processing latency</h3> + <p>The processing and latency constraints of the SoundTouch library are:</p> + <ul> + <li> Input/output processing latency for the SoundTouch processor is + around 100 ms. This is when time-stretching is used. If the rate + transposing effect alone is used, the latency requirement is much + shorter, see section 'About algorithms'.</li> + <li> Processing CD-quality sound (16bit stereo sound with 44100H + sample rate) in real-time or faster is possible starting from + processors equivalent to Intel Pentium 133Mh or better, if using the + "quick" processing algorithm. If not using the "quick" mode or if + floating point sample data are being used, several times more CPU power + is typically required.</li> + </ul> + <h3>3.3. About algorithms</h3> + <p>SoundTouch provides three seemingly independent effects: tempo, + pitch and playback rate control. These three controls are implemented + as combination of two primary effects, <em>sample rate transposing</em> + and <em>time-stretching</em>.</p> + <p><em>Sample rate transposing</em> affects both the audio stream + duration and pitch. It's implemented simply by converting the original + audio sample stream to the desired duration by interpolating from + the original audio samples. In SoundTouch, linear interpolation with + anti-alias filtering is used. Theoretically a higher-order + interpolation provide better result than 1st order linear + interpolation, but in audio application linear interpolation together + with anti-alias filtering performs subjectively about as well as + higher-order filtering would.</p> + <p><em>Time-stretching </em>means changing the audio stream duration + without affecting it's pitch. SoundTouch uses WSOLA-like + time-stretching routines that operate in the time domain. Compared to + sample rate transposing, time-stretching is a much heavier operation + and also requires a longer processing "window" of sound samples used by + the processing algorithm, thus increasing the algorithm input/output + latency. Typical i/o latency for the SoundTouch time-stretch algorithm + is around 100 ms.</p> + <p>Sample rate transposing and time-stretching are then used together + to produce the tempo, pitch and rate controls:</p> + <ul> + <li> <strong>'Tempo'</strong> control is implemented purely by + time-stretching.</li> + <li> <strong>'Rate</strong>' control is implemented purely by sample + rate transposing.</li> + <li> <strong>'Pitch</strong>' control is implemented as a + combination of time-stretching and sample rate transposing. For + example, to increase pitch the audio stream is first time-stretched to + longer duration (without affecting pitch) and then transposed back to + original duration by sample rate transposing, which simultaneously + reduces duration and increases pitch. The result is original duration + but increased pitch.</li> + </ul> + <h3>3.4 Tuning the algorithm parameters</h3> + <p>The time-stretch algorithm has few parameters that can be tuned to + optimize sound quality for certain application. The current default + parameters have been chosen by iterative if-then analysis (read: "trial + and error") to obtain best subjective sound quality in pop/rock music + processing, but in applications processing different kind of sound the + default parameter set may result into a sub-optimal result.</p> + <p>The time-stretch algorithm default parameter values are set by the + following #defines in file "TDStretch.h":</p> + <blockquote> + <pre>#define DEFAULT_SEQUENCE_MS AUTOMATIC<br>#define DEFAULT_SEEKWINDOW_MS AUTOMATIC<br>#define DEFAULT_OVERLAP_MS 8</pre> + </blockquote> + <p>These parameters affect to the time-stretch algorithm as follows:</p> + <ul> + <li> <strong>DEFAULT_SEQUENCE_MS</strong>: This is the default + length of a single processing sequence in milliseconds which determines + the how the original sound is chopped in the time-stretch algorithm. + Larger values mean fewer sequences are used in processing. In principle + a larger value sounds better when slowing down the tempo, but worse + when increasing the tempo and vice versa.<br> + <br> + By default, this setting value is calculated automatically according to + tempo value.<br> + </li> + <li> <strong>DEFAULT_SEEKWINDOW_MS</strong>: The seeking window + default length in milliseconds is for the algorithm that seeks the best + possible overlapping location. This determines from how wide a sample + "window" the algorithm can use to find an optimal mixing location when + the sound sequences are to be linked back together.<br> + <br> + The bigger this window setting is, the higher the possibility to find a + better mixing position becomes, but at the same time large values may + cause a "drifting" sound artifact because neighboring sequences can be + chosen at more uneven intervals. If there's a disturbing artifact that + sounds as if a constant frequency was drifting around, try reducing + this setting.<br> + <br> + By default, this setting value is calculated automatically according to + tempo value.<br> + </li> + <li> <strong>DEFAULT_OVERLAP_MS</strong>: Overlap length in + milliseconds. When the sound sequences are mixed back together to form + again a continuous sound stream, this parameter defines how much the + ends of the consecutive sequences will overlap with each other.<br> + <br> + This shouldn't be that critical parameter. If you reduce the + DEFAULT_SEQUENCE_MS setting by a large amount, you might wish to try a + smaller value on this. + </li> + </ul> + <p>Notice that these parameters can also be set during execution time + with functions "<strong>TDStretch::setParameters()</strong>" and "<strong>SoundTouch::setSetting()</strong>".</p> + <p>The table below summaries how the parameters can be adjusted for + different applications:</p> + <table border="1"> + <tbody> + <tr> + <td valign="top"><strong>Parameter name</strong></td> + <td valign="top"><strong>Default value magnitude</strong></td> + <td valign="top"><strong>Larger value affects...</strong></td> + <td valign="top"><strong>Smaller value affects...</strong></td> + <td valign="top"><strong>Effect to CPU burden</strong></td> + </tr> + <tr> + <td valign="top"> + <pre>SEQUENCE_MS</pre> + </td> + <td valign="top">Default value is relatively large, chosen for + slowing down music tempo</td> + <td valign="top">Larger value is usually better for slowing down + tempo. Growing the value decelerates the "echoing" artifact when + slowing down the tempo.</td> + <td valign="top">Smaller value might be better for speeding up + tempo. Reducing the value accelerates the "echoing" artifact when + slowing down the tempo </td> + <td valign="top">Increasing the parameter value reduces + computation burden</td> + </tr> + <tr> + <td valign="top"> + <pre>SEEKWINDOW_MS</pre> + </td> + <td valign="top">Default value is relatively large, chosen for + slowing down music tempo</td> + <td valign="top">Larger value eases finding a good mixing + position, but may cause a "drifting" artifact</td> + <td valign="top">Smaller reduce possibility to find a good mixing + position, but reduce the "drifting" artifact.</td> + <td valign="top">Increasing the parameter value increases + computation burden</td> + </tr> + <tr> + <td valign="top"> + <pre>OVERLAP_MS</pre> + </td> + <td valign="top">Default value is relatively large, chosen to + suit with above parameters.</td> + <td valign="top"></td> + <td valign="top">If you reduce the "sequence ms" setting, you + might wish to try a smaller value.</td> + <td valign="top">Increasing the parameter value increases + computation burden</td> + </tr> + </tbody> + </table> + <h3>3.5 Performance Optimizations </h3> + <p><strong>Integer vs floating point:</strong></p> + <p>Floating point sample type is generally recommended because it provides + better sound quality.</p> + + <p>However, execution speed difference between integer and floating point processing + depends on the CPU architecture. As rule of thumb, + <ul> + <li>in 32-bit x86 floating point and integer are roughly equally fast</li> + <li>in 64-bit x86/x64 floating point can be significantly faster than integer + version, because MMX integer optimizations are not available in the x64 architecture. + That depends on the compiler however, so that gcc can autovectorize integer routines + to work equally fast as floating point, where as Visual C++ (2017) does not + perform equally well and produces integer code that runs some 3x slower than + SSE-optimized floating poing code. + </li> + <li>in ARMv7 integer routines are twice as fast as floating point. Their + relative difference is roughly the same both with and without NEON; NEON + vfpu can however bring 2.4x speed improvement. + </li> + <li>in other platforms: try out if the execution time performance makes a + big difference</li> + </ul> + </p> + <p><strong>General optimizations:</strong></p> + <p>The time-stretch routine has a 'quick' mode that substantially + speeds up the algorithm but may slightly compromise the sound quality. + This mode is activated by calling SoundTouch::setSetting() + function with parameter id of SETTING_USE_QUICKSEEK and value + "1", i.e. </p> + <blockquote> + <p>setSetting(SETTING_USE_QUICKSEEK, 1);</p> + </blockquote> + <p><strong>CPU-specific optimizations:</strong></p> + <p>Intel x86 specific SIMD optimizations are implemented using compiler + intrinsics, providing about a 3x processing speedup for x86 compatible + processors vs. non-SIMD implementation:</p> + <ul> + <li> MMX optimized routines are used in 32-bit x86 build when 16bit integer + sample type is used</li> + <li> SSE optimized routines are used in 32- and 64-bit x86 CPUs when 32bit + floating point sample type is used</li> + </ul> + <p>The algorithms are tuned to utilize autovectorization efficiently + also in other CPU architectures, for example ARM cpus see approx 2.4x processing + speedup when NEON SIMD support is present. + </p> + <h3>3.5 OpenMP parallel computation</h3> + <p>SoundTouch 1.9 onwards support running the algorithms parallel in several CPU + cores. Based on benchmark the experienced multi-core processing speed-up gain + ranges between +30% (on a high-spec dual-core x86 Windows PC) to 215% (on a moderately low-spec + quad-core ARM of Raspberry Pi2). </p> + <p>See an external blog article with more detailed discussion about the + <a href="http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices/"> + SoundTouch OpenMP optimization</a>. + </p> + <p>The parallel computing support is implemented using OpenMP spec 3.0 + instructions. These instructions are supported by Visual C++ 2008 and later, and + GCC v4.2 and later. Compilers that do not supporting OpenMP will ignore these + optimizations and routines will still work properly. Possible warnings about + unknown #pragmas are related to OpenMP support and can be safely ignored.</p> + <p>The OpenMP improvements are disabled by default, and need to be enabled by + developer during compile-time. Reason for this is that parallel processing adds + moderate runtime overhead in managing the multi-threading, so it may not be + necessary nor desirable in all applications. For example real-time processing + that is not constrained by CPU power will not benefit of speed-up provided by + the parallel processing, in the contrary it may increase power consumption due + to the increased overhead.</p> + <p>However, applications that run on low-spec multi-core CPUs and may otherwise + have possibly constrained performance will benefit of the OpenMP improvements. + This include for example multi-core embedded devices.</p> + <p>OpenMP parallel computation can be enabled before compiling SoundTouch + library as follows:</p> + <ul> + <li><strong>Visual Studio</strong>: Open properties for the <strong>SoundTouch + </strong>sub-project, browse to <strong>C/C++</strong> and <strong>Language + </strong>settings. Set + there "<strong>OpenMP support</strong>" to "<strong>Yes</strong>". Alternatively add + <strong>/openmp</strong> switch to command-line + parameters + </li> + <li><strong>GNU</strong>: Run the configure script with "<strong>./configure + --enable-openmp</strong>" switch, then run make as usually</li> + <li><strong>Android</strong>: Add "<strong>-fopenmp</strong>" switches to compiler & linker + options, see README-SoundTouch-Android.html in the source code package for + more detailed instructions.</li> + </ul> + <hr> + <h2><a name="SoundStretch"></a>4. SoundStretch audio processing utility + </h2> + <p>SoundStretch audio processing utility<br> + Copyright (c) Olli Parviainen 2002-2015</p> + <p>SoundStretch is a simple command-line application that can change + tempo, pitch and playback rates of WAV sound files. This program is + intended primarily to demonstrate how the "SoundTouch" library can be + used to process sound in your own program, but it can as well be used + for processing sound files.</p> + <h3>4.1. SoundStretch Usage Instructions</h3> + <p>SoundStretch Usage syntax:</p> + <blockquote> + <pre>soundstretch infilename outfilename [switches]</pre> + </blockquote> + <p>Where: </p> + <table width="100%" border="0" cellpadding="2"> + <tbody> + <tr> + <td valign="top"> + <pre>"infilename"</pre> + </td> + <td valign="top">Name of the input sound data file (in .WAV audio + file format). Give "stdin" as filename to use standard input pipe. </td> + </tr> + <tr> + <td valign="top"> + <pre>"outfilename"</pre> + </td> + <td valign="top">Name of the output sound file where the + resulting sound is saved (in .WAV audio file format). This parameter + may be omitted if you don't want to save the output (e.g. when + only calculating BPM rate with '-bpm' switch). Give "stdout" as + filename to use standard output pipe.</td> + </tr> + <tr> + <td valign="top"> + <pre>[switches]</pre> + </td> + <td valign="top">Are one or more control switches.</td> + </tr> + </tbody> + </table> + <p>Available control switches are:</p> + <table width="100%" border="0" cellpadding="2"> + <tbody> + <tr> + <td valign="top"> + <pre>-tempo=n </pre> + </td> + <td valign="top">Change the sound tempo by n percents (n = -95.0 + .. +5000.0 %) </td> + </tr> + <tr> + <td valign="top"> + <pre>-pitch=n</pre> + </td> + <td valign="top">Change the sound pitch by n semitones (n = -60.0 + .. + 60.0 semitones) </td> + </tr> + <tr> + <td valign="top"> + <pre>-rate=n</pre> + </td> + <td valign="top">Change the sound playback rate by n percents (n + = -95.0 .. +5000.0 %) </td> + </tr> + <tr> + <td valign="top"> + <pre>-bpm=n</pre> + </td> + <td valign="top">Detect the Beats-Per-Minute (BPM) rate of the + sound and adjust the tempo to meet 'n' BPMs. When this switch is + applied, the "-tempo" switch is ignored. If "=n" is omitted, i.e. + switch "-bpm" is used alone, then the BPM rate is estimated and + displayed, but tempo not adjusted according to the BPM value. </td> + </tr> + <tr> + <td valign="top"> + <pre>-quick</pre> + </td> + <td valign="top">Use quicker tempo change algorithm. Gains speed + but loses sound quality. </td> + </tr> + <tr> + <td valign="top"> + <pre>-naa</pre> + </td> + <td valign="top">Don't use anti-alias filtering in sample rate + transposing. Gains speed but loses sound quality. </td> + </tr> + <tr> + <td valign="top"> + <pre>-license</pre> + </td> + <td valign="top">Displays the program license text (LGPL)</td> + </tr> + </tbody> + </table> + <p>Notes:</p> + <ul> + <li> To use standard input/output pipes for processing, give "stdin" + and "stdout" as input/output filenames correspondingly. The standard + input/output pipes will still carry the audio data in .wav audio file + format.</li> + <li> The numerical switches allow both integer (e.g. "-tempo=123") + and decimal (e.g. "-tempo=123.45") numbers.</li> + <li> The "-naa" and/or "-quick" switches can be used to reduce CPU + usage while compromising some sound quality</li> + <li> The BPM detection algorithm works by detecting repeating bass or + drum patterns at low frequencies of <250Hz. A lower-than-expected + BPM figure may be reported for music with uneven or complex bass + patterns.</li> + </ul> + <h3>4.2. SoundStretch usage examples </h3> + <p><strong>Example 1</strong></p> + <p>The following command increases tempo of the sound file + "originalfile.wav" by 12.5% and stores result to file + "destinationfile.wav":</p> + <blockquote> + <pre>soundstretch originalfile.wav destinationfile.wav -tempo=12.5</pre> + </blockquote> + <p><strong>Example 2</strong></p> + <p>The following command decreases the sound pitch (key) of the sound + file "orig.wav" by two semitones and stores the result to file + "dest.wav":</p> + <blockquote> + <pre>soundstretch orig.wav dest.wav -pitch=-2</pre> + </blockquote> + <p><strong>Example 3</strong></p> + <p>The following command processes the file "orig.wav" by decreasing + the sound tempo by 25.3% and increasing the sound pitch (key) by 1.5 + semitones. Resulting .wav audio data is directed to standard output + pipe:</p> + <blockquote> + <pre>soundstretch orig.wav stdout -tempo=-25.3 -pitch=1.5</pre> + </blockquote> + <p><strong>Example 4</strong></p> + <p>The following command detects the BPM rate of the file "orig.wav" + and adjusts the tempo to match 100 beats per minute. Result is stored + to file "dest.wav":</p> + <blockquote> + <pre>soundstretch orig.wav dest.wav -bpm=100</pre> + </blockquote> + <p><strong>Example 5</strong></p> + <p>The following command reads .wav sound data from standard input pipe + and estimates the BPM rate:</p> + <blockquote> + <pre>soundstretch stdin -bpm</pre> + </blockquote> + <p><strong>Example 6</strong></p> + <p>The following command tunes song from original 440Hz tuning to 432Hz tuning: + this corresponds to lowering the pitch by -0.318 semitones:</p> + <blockquote> + <pre>soundstretch original.wav output.wav -pitch=-0.318</pre> + </blockquote> + <hr> + <h2>5. Change History</h2> + <h3>5.1. SoundTouch library Change History </h3> + <p><b>2.3.1:</b></p> + <ul> + <li>Adjusted cmake build settings and header files that cmake installs</li> + </ul> + <p><b>2.3.0:</b></p> + <ul> + <li>Disable setting "SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION" by default. The original + purpose of this setting was to avoid performance penalty due to unaligned SIMD memory + accesses in old CPUs, but that is not any more issue in concurrent CPU SIMD implementations + and having this setting enabled can cause slight compromise in result quality. + </li> + <li>Bugfix: soundtouch.clear() to really clear whole processing pipeline state. Earlier + individual variables were left uncleared, which caused slightly different result if + the same audio stream were processed again after calling clear(). + </li> + <li>Bugfix: TDstretch to align initial offset position to be in middle of correlation search + window. This ensures that with zero tempo change the output will be same as input. + </li> + <li>Bugfix: Fix a bug in TDstrectch with too small initial skipFract value that occurred + with certain processing parameter settings: Replace assert with assignment that + corrects the situation. + </li> + <li>Remove OpenMP "_init_threading" workaround from Android build as it's not needed with concurrent + Android SDKs any more.</li> + </ul> + <p><b>2.2:</b></p> + <ul> + <li>Improved source codes so that compiler can autovectorize them more effectively. + This brings remarkable improvement e.g. ARM cpus equipped with NEON vfpu: Bencmarked + 2.4x improvement in execution speed in ARMv7l vs the previous SoundTouch version + for both integer and floating point sample types. + </li> + <li>Bugfix: Resolved bad sound quality when using integer sample types in non-x86 CPU</li> + <li>Bugfix: Fixed possible reading past end of array in BPM peak detection algorithm</li> + </ul> + <p><b>2.1.2:</b></p> + <ul> + <li>Bump version to 2.1.2 also in configure.ac. The earlier release had old version info for GNU autotools.</li> + </ul> + <p><b>2.1.1:</b></p> + <ul> + <li>Bugfixes: Fixed potential buffer overwrite bugs in WavFile routines. Replaced asserts with runtime exceptions. + </li> + <li>Android: Migrated the SoundTouch Android example to new Android Studio</li> + <li>Automake: unset ACLOCAL in bootstrap script in case earlier build script has set it</li> + + </ul> + <p><b>2.1:</b></p> + <ul> + <li>Refactored C# interface example</li> + <li>Disable anti-alias filter when switch + SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER defined because anti-alias + filter cause slight click if the rate change crosses zero during + processing</li> + <li>Added script for building SoundTouchDll dynamic-link-library for GNU platforms</li> + <li>Rewrote Beats-per-Minute analysis algorithm for more reliable BPM detection</li> + <li>Added BPM functions to SoundTouchDll API</li> + <li>Migrated Visual Studio project files to MSVC 201x format</li> + <li>Replaced function parameter value asserts with runtime exceptions</li> + <li>Code maintenance & style cleanup</li> + </ul> + <p><b>2.0:</b></p> + <ul> + <li>Added functions to get initial processing latency, duration ratio between the original input and processed + output tracks, and clarified reporting of input/output batch sizes</li> + <li>Fixed issue that added brief sequence of silence to beginning of output audio</li> + <li>Adjusted algorithm parameters to reduce reverberating effect at tempo slowdown</li> + <li>Bugfix: Fixed a glitch that could cause negative array indexing in quick seek algorithm</li> + <li>Bugfix: flush() didn't properly flush final samples from the pipeline on 2nd time in case that soundtouch + object instance was recycled and used for processing a second audio stream.</li> + <li>Bugfix: Pi value had incorrect 9th/10th decimals</li> + <li>Added C# example application that uses SoundTouch dll library for processing MP3 files</li> + </ul> + <p><b>1.9.2:</b></p> + <ul> + <li>Fix in GNU package configuration</li> + </ul> + <p><b>1.9.1:</b></p> + <ul> + <li>Improved SoundTouch::flush() function so that it returns precisely the desired amount of samples for exact + output duration control</li> + <li>Redesigned quickseek algorithm for improved sound quality when using the quickseek mode. The new quickseek + algorithm can find 99% as good results as the + default full-scan mode, while the quickseek algorithm is remarkable less + CPU intensive.</li> + <li>Added adaptive integer divider scaling for improved sound quality when using integer processing algorithm + </li> + </ul> + <p><b>1.9:</b></p> + <ul> + <li>Added support for parallel computation support via OpenMP primitives for better performance in multicore + systems. + Benchmarks show that achieved parallel processing speedup improvement + typically range from +30% (x86 dual-core) to +180% (ARM quad-core). The + OpenMP optimizations are disabled by default, see OpenMP notes above in this + readme file how to enabled these optimizations.</li> + <li>Android: Added support for Android devices featuring X86 and MIPS CPUs, + in addition to ARM CPUs.</li> + <li>Android: More versatile Android example application that processes WAV + audio files with SoundTouch library</li> + <li>Replaced Windows-like 'BOOL' types with native 'bool'</li> + <li>Changed documentation token to "dist_doc_DATA" in Makefile.am file</li> + <li>Miscellaneous small fixes and improvements</li> + </ul> + <p><b>1.8.0:</b></p> + <ul> + <li>Added support for multi-channel audio processing</li> + <li>Added support for <b>cubic</b> and <b>shannon</b> interpolation for rate and pitch shift effects besides + the original <b>linear</b> interpolation, to reduce aliasing at high frequencies due to interpolation. + Cubic interpolation is used as default for floating point processing, and linear interpolation for integer + processing.</li> + <li>Fixed bug in anti-alias filtering that limited stop-band attenuation to -10 dB instead of <-50dB, and + increased filter length from 32 to 64 taps to further reduce aliasing due to frequency folding.</li> + <li>Performance improvements in cross-correlation algorithm</li> + <li>Other bug and compatibility fixes</li> + </ul> + <p><b>1.7.1:</b></p> + <ul> + <li>Added files for Android compilation + </ul> + <p><b>1.7.0:</b></p> + <ul> + <li>Sound quality improvements/li> + <li>Improved flush() to adjust output sound stream duration to match better with + ideal duration</li> + <li>Rewrote x86 cpu feature check to resolve compatibility problems</li> + <li>Configure script automatically checks if CPU supports mmx & sse compatibility for GNU platform, and + the script support now "--enable-x86-optimizations" switch to allow disabling x86-specific optimizations.</li> + <li>Revised #define conditions for 32bit/64bit compatibility</li> + <li>gnu autoconf/automake script compatibility fixes</li> + <li>Tuned beat-per-minute detection algorithm</li> + </ul> + <p><b>1.6.0:</b></p> + <ul> + <li> Added automatic cutoff threshold adaptation to beat detection + routine to better adapt BPM calculation to different types of music</li> + <li> Retired 3DNow! optimization support as 3DNow! is nowadays + obsoleted and assembler code is nuisance to maintain</li> + <li>Retired "configure" file from source code package due to + autoconf/automake versio conflicts, so that it is from now on to be + generated by invoking "boostrap" script that uses locally available + toolchain version for generating the "configure" file</li> + <li>Resolved namespace/label naming conflicts with other libraries by + replacing global labels such as INTEGER_SAMPLES with more specific + SOUNDTOUCH_INTEGER_SAMPLES etc.<br> + </li> + <li>Updated windows build scripts & project files for Visual + Studio 2008 support</li> + <li> Updated SoundTouch.dll API for .NET compatibility</li> + <li> Added API for querying nominal processing input & output + sample batch sizes</li> + </ul> + <p><strong>1.5.0:</strong></p> + <ul> + <li> Added normalization to correlation calculation and improvement + automatic seek/sequence parameter calculation to improve sound quality</li> + <li> Bugfixes: + <ul> + <li> Fixed negative array indexing in quick seek algorithm</li> + <li> FIR autoalias filter running too far in processing buffer</li> + <li> Check against zero sample count in rate transposing</li> + <li> Fix for x86-64 support: Removed pop/push instructions from + the cpu detection algorithm.</li> + <li> Check against empty buffers in FIFOSampleBuffer</li> + <li> Other minor fixes & code cleanup</li> + </ul> + </li> + <li> Fixes in compilation scripts for non-Intel platforms</li> + <li> Added Dynamic-Link-Library (DLL) version of SoundTouch library + build, provided with Delphi/Pascal wrapper for calling the dll routines + </li> + <li> Added #define PREVENT_CLICK_AT_RATE_CROSSOVER that prevents a + click artifact when crossing the nominal pitch from either positive to + negative side or vice versa</li> + </ul> + <p><strong>1.4.1:</strong></p> + <ul> + <li> Fixed a buffer overflow bug in BPM detect algorithm routines if + processing more than 2048 samples at one call</li> + </ul> + <p><strong>1.4.0:</strong></p> + <ul> + <li> Improved sound quality by automatic calculation of time stretch + algorithm processing parameters according to tempo setting</li> + <li> Moved BPM detection routines from SoundStretch application into + SoundTouch library</li> + <li> Bugfixes: Usage of uninitialied variables, GNU build scripts, + compiler errors due to 'const' keyword mismatch.</li> + <li> Source code cleanup</li> + </ul> + <p><strong>1.3.1: </strong> </p> + <ul> + <li> Changed static class declaration to GCC 4.x compiler compatible + syntax.</li> + <li> Enabled MMX/SSE-optimized routines also for GCC compilers. + Earlier the MMX/SSE-optimized routines were written in + compiler-specific inline assembler, now these routines are migrated to + use compiler intrinsic syntax which allows compiling the same + MMX/SSE-optimized source code with both Visual C++ and GCC compilers.</li> + <li> Set floating point as the default sample format and added switch + to the GNU configure script for selecting the other sample format.</li> + </ul> + <p><strong>1.3.0: </strong> </p> + <ul> + <li> Fixed tempo routine output duration inaccuracy due to rounding + error</li> + <li> Implemented separate processing routines for integer and + floating arithmetic to allow improvements to floating point routines + (earlier used algorithms mostly optimized for integer arithmetic also + for floating point samples)</li> + <li> Fixed a bug that distorts sound if sample rate changes during + the sound stream</li> + <li> Fixed a memory leak that appeared in MMX/SSE/3DNow! optimized + routines</li> + <li> Reduced redundant code pieces in MMX/SSE/3DNow! optimized + routines vs. the standard C routines.</li> + <li> MMX routine incompatibility with new gcc compiler versions</li> + <li> Other miscellaneous bug fixes</li> + </ul> + <p><strong>1.2.1: </strong> </p> + <ul> + <li> Added automake/autoconf scripts for GNU platforms (in courtesy + of David Durham)</li> + <li> Fixed SCALE overflow bug in rate transposer routine.</li> + <li> Fixed 64bit address space bugs.</li> + <li> Created a 'soundtouch' namespace for SAMPLETYPE definitions.</li> + </ul> + <p><strong>1.2.0: </strong> </p> + <ul> + <li> Added support for 32bit floating point sample data type with + SSE/3DNow! optimizations for Win32 platform (SSE/3DNow! optimizations + currently not supported in GCC environment)</li> + <li> Replaced 'make-gcc' script for GNU environment by master + Makefile</li> + <li> Added time-stretch routine configurability to SoundTouch main + class</li> + <li> Bugfixes</li> + </ul> + <p><strong>1.1.1: </strong> </p> + <ul> + <li> Moved SoundTouch under lesser GPL license (LGPL). This allows + using SoundTouch library in programs that aren't released under GPL + license.</li> + <li> Changed MMX routine organiation so that MMX optimized routines + are now implemented in classes that are derived from the basic classes + having the standard non-mmx routines.</li> + <li> MMX routines to support gcc version 3.</li> + <li> Replaced windows makefiles by script using the .dsw files</li> + </ul> + <p><strong>1.0.1: </strong> </p> + <ul> + <li> "mmx_gcc.cpp": Added "using namespace std" and removed "return + 0" from a function with void return value to fix compiler errors when + compiling the library in Solaris environment.</li> + <li> Moved file "FIFOSampleBuffer.h" to "include" directory to allow + accessing the FIFOSampleBuffer class from external files.</li> + </ul> + <p><strong>1.0: </strong> </p> + <ul> + <li> Initial release</li> + </ul> + <h3>5.2. SoundStretch application Change History </h3> + <p><b>1.9:</b></p> + <ul> + <li>Added support for WAV file 'fact' information chunk.</li> + </ul> + + <p><b>1.7.0:</b></p> + <ul> + <li>Bugfixes in Wavfile: exception string formatting, avoid getLengthMs() integer + precision overflow, support WAV files using 24/32bit sample format.</li> + </ul> + <p><b>1.5.0:</b></p> + <ul> + <li> Added "-speech" switch to activate algorithm parameters more + suitable for speech processing than the default parameters tuned for + music processing.</li> + </ul> + <p><strong>1.4.0:</strong></p> + <ul> + <li> Moved BPM detection routines from SoundStretch application into + SoundTouch library</li> + <li> Allow using standard input/output pipes as audio processing + input/output streams</li> + </ul> + <p><strong>1.3.0:</strong></p> + <ul> + <li> Simplified accessing WAV files with floating point sample + format.</li> + </ul> + <p><strong>1.2.1: </strong> </p> + <ul> + <li> Fixed 64bit address space bugs.</li> + </ul> + <p><strong>1.2.0: </strong> </p> + <ul> + <li> Added support for 32bit floating point sample data type</li> + <li> Restructured the BPM routines into separate library</li> + <li> Fixed big-endian conversion bugs in WAV file routines (hopefully + :)</li> + </ul> + <p><strong>1.1.1: </strong> </p> + <ul> + <li> Fixed bugs in WAV file reading & added byte-order conversion + for big-endian processors.</li> + <li> Moved SoundStretch source code under 'example' directory to + highlight difference from SoundTouch stuff.</li> + <li> Replaced windows makefiles by script using the .dsw files</li> + <li> Output file name isn't required if output isn't desired (e.g. if + using the switch '-bpm' in plain format only)</li> + </ul> + <p><strong>1.1:</strong></p> + <ul> + <li> Fixed "Release" settings in Microsoft Visual C++ project file + (.dsp)</li> + <li> Added beats-per-minute (BPM) detection routine and command-line + switch "-bpm"</li> + </ul> + <p><strong>1.01: </strong> </p> + <ul> + <li> Initial release</li> + </ul> + <hr> + <h2>6. Acknowledgements </h2> + <p>Kudos for these people who have contributed to development or + submitted bugfixes:</p> + <ul> + <li> Arthur A</li> + <li> Paul Adenot</li> + <li> Richard Ash</li> + <li> Stanislav Brabec</li> + <li> Christian Budde</li> + <li> Jamie Bullock</li> + <li> Chris Bryan</li> + <li> Jacek Caban</li> + <li> Marketa Calabkova</li> + <li> Brian Cameron</li> + <li> Jason Champion</li> + <li> Giuseppe Cigala</li> + <li> David Clark</li> + <li> Patrick Colis</li> + <li> Miquel Colon</li> + <li> Jim Credland</li> + <li> Sandro Cumerlato</li> + <li> Gerry Fan</li> + <li> Justin Frankel</li> + <li> Masa H.</li> + <li> Jason Garland</li> + <li> Takashi Iwai</li> + <li> Thomas Klausner</li> + <li> Lu Zhihe</li> + <li> Luzpaz</li> + <li> Tony Mechelynck </li> + <li> Mathias Möhl</li> + <li> Yuval Naveh</li> + <li> Mats Palmgren </li> + <li> Chandni Patel</li> + <li> Paulo Pizarro</li> + <li> Andrey Ponomarenko</li> + <li> Blaise Potard</li> + <li> Michael Pruett</li> + <li> Rajeev Puran</li> + <li> RJ Ryan</li> + <li> John Sheehy</li> + <li> Tim Shuttleworth</li> + <li> Albert Sirvent</li> + <li> Tyson Smith</li> + <li> John Stumpo</li> + <li> Mario di Vece</li> + <li> Rémi Verschelde</li> + <li> Katja Vetter</li> + <li> Wu Q.</li> + </ul> + <p>Moral greetings to all other contributors and users also!</p> + <hr> + <h2>7. LICENSE </h2> + <p>SoundTouch audio processing library<br> + Copyright (c) Olli Parviainen</p> + <p>This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1 + as published by the Free Software Foundation.</p> + <p>This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + General Public License for more details.</p> + <p>You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p> + <p>---</p> + <p>commercial license alternative also available, contact author for details.</p> + <hr> +</body> + +</html>
\ No newline at end of file diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/BPMDetect.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/BPMDetect.h new file mode 100644 index 00000000..f025fbd1 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/BPMDetect.h @@ -0,0 +1,205 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _BPMDetect_H_ +#define _BPMDetect_H_ + +#include <vector> +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +namespace soundtouch +{ + + /// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit. + #define MIN_BPM 45 + + /// Maximum allowed BPM rate range. Used for calculating algorithm parametrs + #define MAX_BPM_RANGE 200 + + /// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit. + #define MAX_BPM_VALID 190 + +//////////////////////////////////////////////////////////////////////////////// + + typedef struct + { + float pos; + float strength; + } BEAT; + + + class IIR2_filter + { + double coeffs[5]; + double prev[5]; + + public: + IIR2_filter(const double *lpf_coeffs); + float update(float x); + }; + + + /// Class for calculating BPM rate for audio data. + class BPMDetect + { + protected: + /// Auto-correlation accumulator bins. + float *xcorr; + + /// Sample average counter. + int decimateCount; + + /// Sample average accumulator for FIFO-like decimation. + soundtouch::LONG_SAMPLETYPE decimateSum; + + /// Decimate sound by this coefficient to reach approx. 500 Hz. + int decimateBy; + + /// Auto-correlation window length + int windowLen; + + /// Number of channels (1 = mono, 2 = stereo) + int channels; + + /// sample rate + int sampleRate; + + /// Beginning of auto-correlation window: Autocorrelation isn't being updated for + /// the first these many correlation bins. + int windowStart; + + /// window functions for data preconditioning + float *hamw; + float *hamw2; + + // beat detection variables + int pos; + int peakPos; + int beatcorr_ringbuffpos; + int init_scaler; + float peakVal; + float *beatcorr_ringbuff; + + /// FIFO-buffer for decimated processing samples. + soundtouch::FIFOSampleBuffer *buffer; + + /// Collection of detected beat positions + //BeatCollection beats; + std::vector<BEAT> beats; + + // 2nd order low-pass-filter + IIR2_filter beat_lpf; + + /// Updates auto-correlation function for given number of decimated samples that + /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe + /// though). + void updateXCorr(int process_samples /// How many samples are processed. + ); + + /// Decimates samples to approx. 500 Hz. + /// + /// \return Number of output samples. + int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer + const soundtouch::SAMPLETYPE *src, ///< Source sample buffer + int numsamples ///< Number of source samples. + ); + + /// Calculates amplitude envelope for the buffer of samples. + /// Result is output to 'samples'. + void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer + int numsamples ///< Number of samples in buffer + ); + + /// remove constant bias from xcorr data + void removeBias(); + + // Detect individual beat positions + void updateBeatPos(int process_samples); + + + public: + /// Constructor. + BPMDetect(int numChannels, ///< Number of channels in sample data. + int sampleRate ///< Sample rate in Hz. + ); + + /// Destructor. + virtual ~BPMDetect(); + + /// Inputs a block of samples for analyzing: Envelopes the samples and then + /// updates the autocorrelation estimation. When whole song data has been input + /// in smaller blocks using this function, read the resulting bpm with 'getBpm' + /// function. + /// + /// Notice that data in 'samples' array can be disrupted in processing. + void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer + int numSamples ///< Number of samples in buffer + ); + + /// Analyzes the results and returns the BPM rate. Use this function to read result + /// after whole song data has been input to the class by consecutive calls of + /// 'inputSamples' function. + /// + /// \return Beats-per-minute rate, or zero if detection failed. + float getBpm(); + + /// Get beat position arrays. Note: The array includes also really low beat detection values + /// in absence of clear strong beats. Consumer may wish to filter low values away. + /// - "pos" receive array of beat positions + /// - "values" receive array of beat detection strengths + /// - max_num indicates max.size of "pos" and "values" array. + /// + /// You can query a suitable array sized by calling this with NULL in "pos" & "values". + /// + /// \return number of beats in the arrays. + int getBeats(float *pos, float *strength, int max_num); + }; +} +#endif // _BPMDetect_H_ diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/FIFOSampleBuffer.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/FIFOSampleBuffer.h new file mode 100644 index 00000000..537a7b87 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/FIFOSampleBuffer.h @@ -0,0 +1,180 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// output samples from the buffer as well as grows the storage size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSampleBuffer_H +#define FIFOSampleBuffer_H + +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes +/// care of storage size adjustment and data moving during input/output operations. +/// +/// Notice that in case of stereo audio, one sample is considered to consist of +/// both channel data. +class FIFOSampleBuffer : public FIFOSamplePipe +{ +private: + /// Sample buffer. + SAMPLETYPE *buffer; + + // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first + // 16-byte aligned location of this buffer + SAMPLETYPE *bufferUnaligned; + + /// Sample buffer size in bytes + uint sizeInBytes; + + /// How many samples are currently in buffer. + uint samplesInBuffer; + + /// Channels, 1=mono, 2=stereo. + uint channels; + + /// Current position pointer to the buffer. This pointer is increased when samples are + /// removed from the pipe so that it's necessary to actually rewind buffer (move data) + /// only new data when is put to the pipe. + uint bufferPos; + + /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real + /// beginning of the buffer. + void rewind(); + + /// Ensures that the buffer has capacity for at least this many samples. + void ensureCapacity(uint capacityRequirement); + + /// Returns current capacity. + uint getCapacity() const; + +public: + + /// Constructor + FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo. + ///< Default is stereo. + ); + + /// destructor + ~FIFOSampleBuffer(); + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin(); + + /// Returns a pointer to the end of the used part of the sample buffer (i.e. + /// where the new samples are to be inserted). This function may be used for + /// inserting new samples into the sample buffer directly. Please be careful + /// not corrupt the book-keeping! + /// + /// When using this function as means for inserting new samples, also remember + /// to increase the sample count afterwards, by calling the + /// 'putSamples(numSamples)' function. + SAMPLETYPE *ptrEnd( + uint slackCapacity ///< How much free capacity (in samples) there _at least_ + ///< should be so that the caller can successfully insert the + ///< desired samples to the buffer. If necessary, the function + ///< grows the buffer size to comply with this requirement. + ); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ); + + /// Adjusts the book-keeping to increase number of samples in the buffer without + /// copying any actual samples. + /// + /// This function is used to update the number of samples in the sample buffer + /// when accessing the buffer directly with 'ptrEnd' function. Please be + /// careful though! + virtual void putSamples(uint numSamples ///< Number of samples been inserted. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Returns number of samples currently available. + virtual uint numSamples() const; + + /// Sets number of channels, 1 = mono, 2 = stereo. + void setChannels(int numChannels); + + /// Get number of channels + int getChannels() + { + return channels; + } + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const; + + /// Clears all the samples. + virtual void clear(); + + /// allow trimming (downwards) amount of samples in pipeline. + /// Returns adjusted amount of samples + uint adjustAmountOfSamples(uint numSamples); + + /// Add silence to end of buffer + void addSilent(uint nSamples); +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/FIFOSamplePipe.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/FIFOSamplePipe.h new file mode 100644 index 00000000..3def42d1 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/FIFOSamplePipe.h @@ -0,0 +1,230 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound +/// samples by operating like a first-in-first-out pipe: New samples are fed +/// into one end of the pipe with the 'putSamples' function, and the processed +/// samples are received from the other end with the 'receiveSamples' function. +/// +/// 'FIFOProcessor' : A base class for classes the do signal processing with +/// the samples while operating like a first-in-first-out pipe. When samples +/// are input with the 'putSamples' function, the class processes them +/// and moves the processed samples to the given 'output' pipe object, which +/// may be either another processing stage, or a fifo sample buffer object. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIFOSamplePipe_H +#define FIFOSamplePipe_H + +#include <assert.h> +#include <stdlib.h> +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for FIFO (first-in-first-out) sample processing classes. +class FIFOSamplePipe +{ +protected: + + bool verifyNumberOfChannels(int nChannels) const + { + if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS)) + { + return true; + } + ST_THROW_RT_ERROR("Error: Illegal number of channels"); + return false; + } + +public: + // virtual default destructor + virtual ~FIFOSamplePipe() {} + + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() = 0; + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position to + /// the sample buffer. + virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. + uint numSamples ///< Number of samples to insert. + ) = 0; + + + // Moves samples from the 'other' pipe instance to this instance. + void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. + ) + { + int oNumSamples = other.numSamples(); + + putSamples(other.ptrBegin(), oNumSamples); + other.receiveSamples(oNumSamples); + }; + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) = 0; + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) = 0; + + /// Returns number of samples currently available. + virtual uint numSamples() const = 0; + + // Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const = 0; + + /// Clears all the samples. + virtual void clear() = 0; + + /// allow trimming (downwards) amount of samples in pipeline. + /// Returns adjusted amount of samples + virtual uint adjustAmountOfSamples(uint numSamples) = 0; + +}; + + +/// Base-class for sound processing routines working in FIFO principle. With this base +/// class it's easy to implement sound processing stages that can be chained together, +/// so that samples that are fed into beginning of the pipe automatically go through +/// all the processing stages. +/// +/// When samples are input to this class, they're first processed and then put to +/// the FIFO pipe that's defined as output of this class. This output pipe can be +/// either other processing stage or a FIFO sample buffer. +class FIFOProcessor :public FIFOSamplePipe +{ +protected: + /// Internal pipe where processed samples are put. + FIFOSamplePipe *output; + + /// Sets output pipe. + void setOutPipe(FIFOSamplePipe *pOutput) + { + assert(output == NULL); + assert(pOutput != NULL); + output = pOutput; + } + + /// Constructor. Doesn't define output pipe; it has to be set be + /// 'setOutPipe' function. + FIFOProcessor() + { + output = NULL; + } + + /// Constructor. Configures output pipe. + FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe. + ) + { + output = pOutput; + } + + /// Destructor. + virtual ~FIFOProcessor() + { + } + + /// Returns a pointer to the beginning of the output samples. + /// This function is provided for accessing the output samples directly. + /// Please be careful for not to corrupt the book-keeping! + /// + /// When using this function to output samples, also remember to 'remove' the + /// output samples from the buffer by calling the + /// 'receiveSamples(numSamples)' function + virtual SAMPLETYPE *ptrBegin() + { + return output->ptrBegin(); + } + +public: + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ) + { + return output->receiveSamples(outBuffer, maxSamples); + } + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ) + { + return output->receiveSamples(maxSamples); + } + + /// Returns number of samples currently available. + virtual uint numSamples() const + { + return output->numSamples(); + } + + /// Returns nonzero if there aren't any samples available for outputting. + virtual int isEmpty() const + { + return output->isEmpty(); + } + + /// allow trimming (downwards) amount of samples in pipeline. + /// Returns adjusted amount of samples + virtual uint adjustAmountOfSamples(uint numSamples) + { + return output->adjustAmountOfSamples(numSamples); + } +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/Makefile.am new file mode 100644 index 00000000..4a0b5f43 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/Makefile.am @@ -0,0 +1,22 @@ +## Process this file with automake to create Makefile.in +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch is free software; you can redistribute it and/or modify it under the +## terms of the GNU General Public License as published by the Free Software +## Foundation; either version 2 of the License, or (at your option) any later +## version. +## +## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY +## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +## A PARTICULAR PURPOSE. See the GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License along with +## this program; if not, write to the Free Software Foundation, Inc., 59 Temple +## Place - Suite 330, Boston, MA 02111-1307, USA + +## I used config/am_include.mk for common definitions +include $(top_srcdir)/config/am_include.mk + +pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h + diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/STTypes.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/STTypes.h new file mode 100644 index 00000000..dc964b02 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/STTypes.h @@ -0,0 +1,190 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Common type definitions for SoundTouch audio processing library. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef STTypes_H +#define STTypes_H + +typedef unsigned int uint; +typedef unsigned long ulong; + +// Patch for MinGW: on Win64 long is 32-bit +#ifdef _WIN64 + typedef unsigned long long ulongptr; +#else + typedef ulong ulongptr; +#endif + + +// Helper macro for aligning pointer up to next 16-byte boundary +#define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 ) + + +#if (defined(__GNUC__) && !defined(ANDROID)) + // In GCC, include soundtouch_config.h made by config scritps. + // Skip this in Android compilation that uses GCC but without configure scripts. + #include "soundtouch_config.h" +#endif + + +namespace soundtouch +{ + /// Max allowed number of channels + #define SOUNDTOUCH_MAX_CHANNELS 16 + + /// Activate these undef's to overrule the possible sampletype + /// setting inherited from some other header file: + //#undef SOUNDTOUCH_INTEGER_SAMPLES + //#undef SOUNDTOUCH_FLOAT_SAMPLES + + /// If following flag is defined, always uses multichannel processing + /// routines also for mono and stero sound. This is for routine testing + /// purposes; output should be same with either routines, yet disabling + /// the dedicated mono/stereo processing routines will result in slower + /// runtime performance so recommendation is to keep this off. + // #define USE_MULTICH_ALWAYS + + #if (defined(__SOFTFP__) && defined(ANDROID)) + // For Android compilation: Force use of Integer samples in case that + // compilation uses soft-floating point emulation - soft-fp is way too slow + #undef SOUNDTOUCH_FLOAT_SAMPLES + #define SOUNDTOUCH_INTEGER_SAMPLES 1 + #endif + + #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES) + + /// Choose either 32bit floating point or 16bit integer sampletype + /// by choosing one of the following defines, unless this selection + /// has already been done in some other file. + //// + /// Notes: + /// - In Windows environment, choose the sample format with the + /// following defines. + /// - In GNU environment, the floating point samples are used by + /// default, but integer samples can be chosen by giving the + /// following switch to the configure script: + /// ./configure --enable-integer-samples + /// However, if you still prefer to select the sample format here + /// also in GNU environment, then please #undef the INTEGER_SAMPLE + /// and FLOAT_SAMPLE defines first as in comments above. + //#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples + #define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples + + #endif + + #if (_M_IX86 || __i386__ || __x86_64__ || _M_X64) + /// Define this to allow X86-specific assembler/intrinsic optimizations. + /// Notice that library contains also usual C++ versions of each of these + /// these routines, so if you're having difficulties getting the optimized + /// routines compiled for whatever reason, you may disable these optimizations + /// to make the library compile. + + #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1 + + /// In GNU environment, allow the user to override this setting by + /// giving the following switch to the configure script: + /// ./configure --disable-x86-optimizations + /// ./configure --enable-x86-optimizations=no + #ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS + #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS + #endif + #else + /// Always disable optimizations when not using a x86 systems. + #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS + + #endif + + // If defined, allows the SIMD-optimized routines to skip unevenly aligned + // memory offsets that can cause performance penalty in some SIMD implementations. + // Causes slight compromise in sound quality. + // #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 + + + #ifdef SOUNDTOUCH_INTEGER_SAMPLES + // 16bit integer sample type + typedef short SAMPLETYPE; + // data type for sample accumulation: Use 32bit integer to prevent overflows + typedef long LONG_SAMPLETYPE; + + #ifdef SOUNDTOUCH_FLOAT_SAMPLES + // check that only one sample type is defined + #error "conflicting sample types defined" + #endif // SOUNDTOUCH_FLOAT_SAMPLES + + #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS + // Allow MMX optimizations (not available in X64 mode) + #if (!_M_X64) + #define SOUNDTOUCH_ALLOW_MMX 1 + #endif + #endif + + #else + + // floating point samples + typedef float SAMPLETYPE; + // data type for sample accumulation: Use float also here to enable + // efficient autovectorization + typedef float LONG_SAMPLETYPE; + + #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS + // Allow SSE optimizations + #define SOUNDTOUCH_ALLOW_SSE 1 + #endif + + #endif // SOUNDTOUCH_INTEGER_SAMPLES + + #if ((SOUNDTOUCH_ALLOW_SSE) || (__SSE__) || (SOUNDTOUCH_USE_NEON)) + #if SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION + #define ST_SIMD_AVOID_UNALIGNED + #endif + #endif + +} + +// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions: +// #define ST_NO_EXCEPTION_HANDLING 1 +#ifdef ST_NO_EXCEPTION_HANDLING + // Exceptions disabled. Throw asserts instead if enabled. + #include <assert.h> + #define ST_THROW_RT_ERROR(x) {assert((const char *)x);} +#else + // use c++ standard exceptions + #include <stdexcept> + #include <string> + #define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);} +#endif + +// When this #define is active, eliminates a clicking sound when the "rate" or "pitch" +// parameter setting crosses from value <1 to >=1 or vice versa during processing. +// Default is off as such crossover is untypical case and involves a slight sound +// quality compromise. +//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1 + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/SoundTouch.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/SoundTouch.h new file mode 100644 index 00000000..f5cc5d6b --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/include/SoundTouch.h @@ -0,0 +1,348 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef SoundTouch_H +#define SoundTouch_H + +#include "FIFOSamplePipe.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Soundtouch library version string +#define SOUNDTOUCH_VERSION "2.3.1" + +/// SoundTouch library version id +#define SOUNDTOUCH_VERSION_ID (20301) + +// +// Available setting IDs for the 'setSetting' & 'get_setting' functions: + +/// Enable/disable anti-alias filter in pitch transposer (0 = disable) +#define SETTING_USE_AA_FILTER 0 + +/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32) +#define SETTING_AA_FILTER_LENGTH 1 + +/// Enable/disable quick seeking algorithm in tempo changer routine +/// (enabling quick seeking lowers CPU utilization but causes a minor sound +/// quality compromising) +#define SETTING_USE_QUICKSEEK 2 + +/// Time-stretch algorithm single processing sequence length in milliseconds. This determines +/// to how long sequences the original sound is chopped in the time-stretch algorithm. +/// See "STTypes.h" or README for more information. +#define SETTING_SEQUENCE_MS 3 + +/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the +/// best possible overlapping location. This determines from how wide window the algorithm +/// may look for an optimal joining location when mixing the sound sequences back together. +/// See "STTypes.h" or README for more information. +#define SETTING_SEEKWINDOW_MS 4 + +/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences +/// are mixed back together, to form a continuous sound stream, this parameter defines over +/// how long period the two consecutive sequences are let to overlap each other. +/// See "STTypes.h" or README for more information. +#define SETTING_OVERLAP_MS 5 + + +/// Call "getSetting" with this ID to query processing sequence size in samples. +/// This value gives approximate value of how many input samples you'll need to +/// feed into SoundTouch after initial buffering to get out a new batch of +/// output samples. +/// +/// This value does not include initial buffering at beginning of a new processing +/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size. +/// +/// Notices: +/// - This is read-only parameter, i.e. setSetting ignores this parameter +/// - This parameter value is not constant but change depending on +/// tempo/pitch/rate/samplerate settings. +#define SETTING_NOMINAL_INPUT_SEQUENCE 6 + + +/// Call "getSetting" with this ID to query nominal average processing output +/// size in samples. This value tells approcimate value how many output samples +/// SoundTouch outputs once it does DSP processing run for a batch of input samples. +/// +/// Notices: +/// - This is read-only parameter, i.e. setSetting ignores this parameter +/// - This parameter value is not constant but change depending on +/// tempo/pitch/rate/samplerate settings. +#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7 + + +/// Call "getSetting" with this ID to query initial processing latency, i.e. +/// approx. how many samples you'll need to enter to SoundTouch pipeline before +/// you can expect to get first batch of ready output samples out. +/// +/// After the first output batch, you can then expect to get approx. +/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every +/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch. +/// +/// Example: +/// processing with parameter -tempo=5 +/// => initial latency = 5509 samples +/// input sequence = 4167 samples +/// output sequence = 3969 samples +/// +/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of +/// the stream, and then you'll get out the first 3969 samples. After that, for +/// every approx. 4167 samples that you'll put in, you'll receive again approx. +/// 3969 samples out. +/// +/// This also means that average latency during stream processing is +/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2 +/// = 3524 samples +/// +/// Notices: +/// - This is read-only parameter, i.e. setSetting ignores this parameter +/// - This parameter value is not constant but change depending on +/// tempo/pitch/rate/samplerate settings. +#define SETTING_INITIAL_LATENCY 8 + + +class SoundTouch : public FIFOProcessor +{ +private: + /// Rate transposer class instance + class RateTransposer *pRateTransposer; + + /// Time-stretch class instance + class TDStretch *pTDStretch; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + double virtualRate; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + double virtualTempo; + + /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters. + double virtualPitch; + + /// Flag: Has sample rate been set? + bool bSrateSet; + + /// Accumulator for how many samples in total will be expected as output vs. samples put in, + /// considering current processing settings. + double samplesExpectedOut; + + /// Accumulator for how many samples in total have been read out from the processing so far + long samplesOutput; + + /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and + /// 'virtualPitch' parameters. + void calcEffectiveRateAndTempo(); + +protected : + /// Number of channels + uint channels; + + /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + double rate; + + /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch' + double tempo; + +public: + SoundTouch(); + virtual ~SoundTouch(); + + /// Get SoundTouch library version string + static const char *getVersionString(); + + /// Get SoundTouch library version Id + static uint getVersionId(); + + /// Sets new rate control value. Normal rate = 1.0, smaller values + /// represent slower rate, larger faster rates. + void setRate(double newRate); + + /// Sets new tempo control value. Normal tempo = 1.0, smaller values + /// represent slower tempo, larger faster tempo. + void setTempo(double newTempo); + + /// Sets new rate control value as a difference in percents compared + /// to the original rate (-50 .. +100 %) + void setRateChange(double newRate); + + /// Sets new tempo control value as a difference in percents compared + /// to the original tempo (-50 .. +100 %) + void setTempoChange(double newTempo); + + /// Sets new pitch control value. Original pitch = 1.0, smaller values + /// represent lower pitches, larger values higher pitch. + void setPitch(double newPitch); + + /// Sets pitch change in octaves compared to the original pitch + /// (-1.00 .. +1.00) + void setPitchOctaves(double newPitch); + + /// Sets pitch change in semi-tones compared to the original pitch + /// (-12 .. +12) + void setPitchSemiTones(int newPitch); + void setPitchSemiTones(double newPitch); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(uint numChannels); + + /// Sets sample rate. + void setSampleRate(uint srate); + + /// Get ratio between input and output audio durations, useful for calculating + /// processed output duration: if you'll process a stream of N samples, then + /// you can expect to get out N * getInputOutputSampleRatio() samples. + /// + /// This ratio will give accurate target duration ratio for a full audio track, + /// given that the the whole track is processed with same processing parameters. + /// + /// If this ratio is applied to calculate intermediate offsets inside a processing + /// stream, then this ratio is approximate and can deviate +- some tens of milliseconds + /// from ideal offset, yet by end of the audio stream the duration ratio will become + /// exact. + /// + /// Example: if processing with parameters "-tempo=15 -pitch=-3", the function + /// will return value 0.8695652... Now, if processing an audio stream whose duration + /// is exactly one million audio samples, then you can expect the processed + /// output duration be 0.869565 * 1000000 = 869565 samples. + double getInputOutputSampleRatio(); + + /// Flushes the last samples from the processing pipeline to the output. + /// Clears also the internal processing buffers. + // + /// Note: This function is meant for extracting the last samples of a sound + /// stream. This function may introduce additional blank samples in the end + /// of the sound stream, and thus it's not recommended to call this function + /// in the middle of a sound stream. + void flush(); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. Notice that sample rate _has_to_ be set before + /// calling this function, otherwise throws a runtime_error exception. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + uint numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + + /// Output samples from beginning of the sample buffer. Copies requested samples to + /// output buffer and removes them from the sample buffer. If there are less than + /// 'numsample' samples in the buffer, returns all that available. + /// + /// \return Number of samples returned. + virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. + uint maxSamples ///< How many samples to receive at max. + ); + + /// Adjusts book-keeping so that given number of samples are removed from beginning of the + /// sample buffer without copying them anywhere. + /// + /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly + /// with 'ptrBegin' function. + virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. + ); + + /// Clears all the samples in the object's output and internal processing + /// buffers. + virtual void clear(); + + /// Changes a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return 'true' if the setting was successfully changed + bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines. + int value ///< New setting value. + ); + + /// Reads a setting controlling the processing system behaviour. See the + /// 'SETTING_...' defines for available setting ID's. + /// + /// \return the setting value. + int getSetting(int settingId ///< Setting ID number, see SETTING_... defines. + ) const; + + /// Returns number of samples currently unprocessed. + virtual uint numUnprocessedSamples() const; + + /// Return number of channels + uint numChannels() const + { + return channels; + } + + /// Other handy functions that are implemented in the ancestor classes (see + /// classes 'FIFOProcessor' and 'FIFOSamplePipe') + /// + /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch. + /// - numSamples() : Get number of 'ready' samples that can be received with + /// function 'receiveSamples()' + /// - isEmpty() : Returns nonzero if there aren't any 'ready' samples. + /// - clear() : Clears all samples from ready/processing buffers. +}; + +} +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/Makefile.am new file mode 100644 index 00000000..8a974bf3 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/Makefile.am @@ -0,0 +1,24 @@ +## Process this file with automake to create Makefile.in +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch is free software; you can redistribute it and/or modify it under the +## terms of the GNU General Public License as published by the Free Software +## Foundation; either version 2 of the License, or (at your option) any later +## version. +## +## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY +## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +## A PARTICULAR PURPOSE. See the GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License along with +## this program; if not, write to the Free Software Foundation, Inc., 59 Temple +## Place - Suite 330, Boston, MA 02111-1307, USA + +include $(top_srcdir)/config/am_include.mk + +SUBDIRS=SoundTouch SoundStretch + +# set to something if you want other stuff to be included in the distribution tarball +#EXTRA_DIST= + diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/AAFilter.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/AAFilter.cpp new file mode 100644 index 00000000..71011bb1 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/AAFilter.cpp @@ -0,0 +1,222 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// FIR low-pass (anti-alias) filter with filter coefficient design routine and +/// MMX optimization. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <memory.h> +#include <assert.h> +#include <math.h> +#include <stdlib.h> +#include "AAFilter.h" +#include "FIRFilter.h" + +using namespace soundtouch; + +#define PI 3.14159265358979323846 +#define TWOPI (2 * PI) + +// define this to save AA filter coefficients to a file +// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1 + +#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS + #include <stdio.h> + + static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) + { + FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); + if (fptr == NULL) return; + + for (int i = 0; i < len; i ++) + { + double temp = coeffs[i]; + fprintf(fptr, "%lf\n", temp); + } + fclose(fptr); + } + +#else + #define _DEBUG_SAVE_AAFIR_COEFFS(x, y) +#endif + +/***************************************************************************** + * + * Implementation of the class 'AAFilter' + * + *****************************************************************************/ + +AAFilter::AAFilter(uint len) +{ + pFIR = FIRFilter::newInstance(); + cutoffFreq = 0.5; + setLength(len); +} + + +AAFilter::~AAFilter() +{ + delete pFIR; +} + + +// Sets new anti-alias filter cut-off edge frequency, scaled to +// sampling frequency (nyquist frequency = 0.5). +// The filter will cut frequencies higher than the given frequency. +void AAFilter::setCutoffFreq(double newCutoffFreq) +{ + cutoffFreq = newCutoffFreq; + calculateCoeffs(); +} + + +// Sets number of FIR filter taps +void AAFilter::setLength(uint newLength) +{ + length = newLength; + calculateCoeffs(); +} + + +// Calculates coefficients for a low-pass FIR filter using Hamming window +void AAFilter::calculateCoeffs() +{ + uint i; + double cntTemp, temp, tempCoeff,h, w; + double wc; + double scaleCoeff, sum; + double *work; + SAMPLETYPE *coeffs; + + assert(length >= 2); + assert(length % 4 == 0); + assert(cutoffFreq >= 0); + assert(cutoffFreq <= 0.5); + + work = new double[length]; + coeffs = new SAMPLETYPE[length]; + + wc = 2.0 * PI * cutoffFreq; + tempCoeff = TWOPI / (double)length; + + sum = 0; + for (i = 0; i < length; i ++) + { + cntTemp = (double)i - (double)(length / 2); + + temp = cntTemp * wc; + if (temp != 0) + { + h = sin(temp) / temp; // sinc function + } + else + { + h = 1.0; + } + w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window + + temp = w * h; + work[i] = temp; + + // calc net sum of coefficients + sum += temp; + } + + // ensure the sum of coefficients is larger than zero + assert(sum > 0); + + // ensure we've really designed a lowpass filter... + assert(work[length/2] > 0); + assert(work[length/2 + 1] > -1e-6); + assert(work[length/2 - 1] > -1e-6); + + // Calculate a scaling coefficient in such a way that the result can be + // divided by 16384 + scaleCoeff = 16384.0f / sum; + + for (i = 0; i < length; i ++) + { + temp = work[i] * scaleCoeff; + // scale & round to nearest integer + temp += (temp >= 0) ? 0.5 : -0.5; + // ensure no overfloods + assert(temp >= -32768 && temp <= 32767); + coeffs[i] = (SAMPLETYPE)temp; + } + + // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384 + pFIR->setCoefficients(coeffs, length, 14); + + _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length); + + delete[] work; + delete[] coeffs; +} + + +// Applies the filter to the given sequence of samples. +// Note : The amount of outputted samples is by value of 'filter length' +// smaller than the amount of input samples. +uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const +{ + return pFIR->evaluate(dest, src, numSamples, numChannels); +} + + +/// Applies the filter to the given src & dest pipes, so that processed amount of +/// samples get removed from src, and produced amount added to dest +/// Note : The amount of outputted samples is by value of 'filter length' +/// smaller than the amount of input samples. +uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const +{ + SAMPLETYPE *pdest; + const SAMPLETYPE *psrc; + uint numSrcSamples; + uint result; + int numChannels = src.getChannels(); + + assert(numChannels == dest.getChannels()); + + numSrcSamples = src.numSamples(); + psrc = src.ptrBegin(); + pdest = dest.ptrEnd(numSrcSamples); + result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels); + src.receiveSamples(result); + dest.putSamples(result); + + return result; +} + + +uint AAFilter::getLength() const +{ + return pFIR->getLength(); +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/AAFilter.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/AAFilter.h new file mode 100644 index 00000000..81d836b7 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/AAFilter.h @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Anti-alias filter is used to prevent folding of high frequencies when +/// transposing the sample rate with interpolation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef AAFilter_H +#define AAFilter_H + +#include "STTypes.h" +#include "FIFOSampleBuffer.h" + +namespace soundtouch +{ + +class AAFilter +{ +protected: + class FIRFilter *pFIR; + + /// Low-pass filter cut-off frequency, negative = invalid + double cutoffFreq; + + /// num of filter taps + uint length; + + /// Calculate the FIR coefficients realizing the given cutoff-frequency + void calculateCoeffs(); +public: + AAFilter(uint length); + + ~AAFilter(); + + /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling + /// frequency (nyquist frequency = 0.5). The filter will cut off the + /// frequencies than that. + void setCutoffFreq(double newCutoffFreq); + + /// Sets number of FIR filter taps, i.e. ~filter complexity + void setLength(uint newLength); + + uint getLength() const; + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels) const; + + /// Applies the filter to the given src & dest pipes, so that processed amount of + /// samples get removed from src, and produced amount added to dest + /// Note : The amount of outputted samples is by value of 'filter length' + /// smaller than the amount of input samples. + uint evaluate(FIFOSampleBuffer &dest, + FIFOSampleBuffer &src) const; + +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/BPMDetect.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/BPMDetect.cpp new file mode 100644 index 00000000..959f36e3 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/BPMDetect.cpp @@ -0,0 +1,573 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Beats-per-minute (BPM) detection routine. +/// +/// The beat detection algorithm works as follows: +/// - Use function 'inputSamples' to input a chunks of samples to the class for +/// analysis. It's a good idea to enter a large sound file or stream in smallish +/// chunks of around few kilosamples in order not to extinguish too much RAM memory. +/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden, +/// which is basically ok as low (bass) frequencies mostly determine the beat rate. +/// Simple averaging is used for anti-alias filtering because the resulting signal +/// quality isn't of that high importance. +/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by +/// taking absolute value that's smoothed by sliding average. Signal levels that +/// are below a couple of times the general RMS amplitude level are cut away to +/// leave only notable peaks there. +/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term +/// autocorrelation function of the enveloped signal. +/// - After whole sound data file has been analyzed as above, the bpm level is +/// detected by function 'getBpm' that finds the highest peak of the autocorrelation +/// function, calculates it's precise location and converts this reading to bpm's. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#define _USE_MATH_DEFINES + +#include <math.h> +#include <assert.h> +#include <string.h> +#include <stdio.h> +#include <cfloat> +#include "FIFOSampleBuffer.h" +#include "PeakFinder.h" +#include "BPMDetect.h" + +using namespace soundtouch; + +// algorithm input sample block size +static const int INPUT_BLOCK_SIZE = 2048; + +// decimated sample block size +static const int DECIMATED_BLOCK_SIZE = 256; + +/// Target sample rate after decimation +static const int TARGET_SRATE = 1000; + +/// XCorr update sequence size, update in about 200msec chunks +static const int XCORR_UPDATE_SEQUENCE = (int)(TARGET_SRATE / 5); + +/// Moving average N size +static const int MOVING_AVERAGE_N = 15; + +/// XCorr decay time constant, decay to half in 30 seconds +/// If it's desired to have the system adapt quicker to beat rate +/// changes within a continuing music stream, then the +/// 'xcorr_decay_time_constant' value can be reduced, yet that +/// can increase possibility of glitches in bpm detection. +static const double XCORR_DECAY_TIME_CONSTANT = 30.0; + +/// Data overlap factor for beat detection algorithm +static const int OVERLAP_FACTOR = 4; + +static const double TWOPI = (2 * M_PI); + +//////////////////////////////////////////////////////////////////////////////// + +// Enable following define to create bpm analysis file: + +//#define _CREATE_BPM_DEBUG_FILE + +#ifdef _CREATE_BPM_DEBUG_FILE + + static void _SaveDebugData(const char *name, const float *data, int minpos, int maxpos, double coeff) + { + FILE *fptr = fopen(name, "wt"); + int i; + + if (fptr) + { + printf("\nWriting BPM debug data into file %s\n", name); + for (i = minpos; i < maxpos; i ++) + { + fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]); + } + fclose(fptr); + } + } + + void _SaveDebugBeatPos(const char *name, const std::vector<BEAT> &beats) + { + printf("\nWriting beat detections data into file %s\n", name); + + FILE *fptr = fopen(name, "wt"); + if (fptr) + { + for (uint i = 0; i < beats.size(); i++) + { + BEAT b = beats[i]; + fprintf(fptr, "%lf\t%lf\n", b.pos, b.strength); + } + fclose(fptr); + } + } +#else + #define _SaveDebugData(name, a,b,c,d) + #define _SaveDebugBeatPos(name, b) +#endif + +// Hamming window +void hamming(float *w, int N) +{ + for (int i = 0; i < N; i++) + { + w[i] = (float)(0.54 - 0.46 * cos(TWOPI * i / (N - 1))); + } + +} + +//////////////////////////////////////////////////////////////////////////////// +// +// IIR2_filter - 2nd order IIR filter + +IIR2_filter::IIR2_filter(const double *lpf_coeffs) +{ + memcpy(coeffs, lpf_coeffs, 5 * sizeof(double)); + memset(prev, 0, sizeof(prev)); +} + + +float IIR2_filter::update(float x) +{ + prev[0] = x; + double y = x * coeffs[0]; + + for (int i = 4; i >= 1; i--) + { + y += coeffs[i] * prev[i]; + prev[i] = prev[i - 1]; + } + + prev[3] = y; + return (float)y; +} + + +// IIR low-pass filter coefficients, calculated with matlab/octave cheby2(2,40,0.05) +const double _LPF_coeffs[5] = { 0.00996655391939, -0.01944529148401, 0.00996655391939, 1.96867605796247, -0.96916387431724 }; + +//////////////////////////////////////////////////////////////////////////////// + +BPMDetect::BPMDetect(int numChannels, int aSampleRate) : + beat_lpf(_LPF_coeffs) +{ + beats.reserve(250); // initial reservation to prevent frequent reallocation + + this->sampleRate = aSampleRate; + this->channels = numChannels; + + decimateSum = 0; + decimateCount = 0; + + // choose decimation factor so that result is approx. 1000 Hz + decimateBy = sampleRate / TARGET_SRATE; + if ((decimateBy <= 0) || (decimateBy * DECIMATED_BLOCK_SIZE < INPUT_BLOCK_SIZE)) + { + ST_THROW_RT_ERROR("Too small samplerate"); + } + + // Calculate window length & starting item according to desired min & max bpms + windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); + windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM_RANGE); + + assert(windowLen > windowStart); + + // allocate new working objects + xcorr = new float[windowLen]; + memset(xcorr, 0, windowLen * sizeof(float)); + + pos = 0; + peakPos = 0; + peakVal = 0; + init_scaler = 1; + beatcorr_ringbuffpos = 0; + beatcorr_ringbuff = new float[windowLen]; + memset(beatcorr_ringbuff, 0, windowLen * sizeof(float)); + + // allocate processing buffer + buffer = new FIFOSampleBuffer(); + // we do processing in mono mode + buffer->setChannels(1); + buffer->clear(); + + // calculate hamming windows + hamw = new float[XCORR_UPDATE_SEQUENCE]; + hamming(hamw, XCORR_UPDATE_SEQUENCE); + hamw2 = new float[XCORR_UPDATE_SEQUENCE / 2]; + hamming(hamw2, XCORR_UPDATE_SEQUENCE / 2); +} + + +BPMDetect::~BPMDetect() +{ + delete[] xcorr; + delete[] beatcorr_ringbuff; + delete[] hamw; + delete[] hamw2; + delete buffer; +} + + +/// convert to mono, low-pass filter & decimate to about 500 Hz. +/// return number of outputted samples. +/// +/// Decimation is used to remove the unnecessary frequencies and thus to reduce +/// the amount of data needed to be processed as calculating autocorrelation +/// function is a very-very heavy operation. +/// +/// Anti-alias filtering is done simply by averaging the samples. This is really a +/// poor-man's anti-alias filtering, but it's not so critical in this kind of application +/// (it'd also be difficult to design a high-quality filter with steep cut-off at very +/// narrow band) +int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples) +{ + int count, outcount; + LONG_SAMPLETYPE out; + + assert(channels > 0); + assert(decimateBy > 0); + outcount = 0; + for (count = 0; count < numsamples; count ++) + { + int j; + + // convert to mono and accumulate + for (j = 0; j < channels; j ++) + { + decimateSum += src[j]; + } + src += j; + + decimateCount ++; + if (decimateCount >= decimateBy) + { + // Store every Nth sample only + out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels)); + decimateSum = 0; + decimateCount = 0; +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + // check ranges for sure (shouldn't actually be necessary) + if (out > 32767) + { + out = 32767; + } + else if (out < -32768) + { + out = -32768; + } +#endif // SOUNDTOUCH_INTEGER_SAMPLES + dest[outcount] = (SAMPLETYPE)out; + outcount ++; + } + } + return outcount; +} + + +// Calculates autocorrelation function of the sample history buffer +void BPMDetect::updateXCorr(int process_samples) +{ + int offs; + SAMPLETYPE *pBuffer; + + assert(buffer->numSamples() >= (uint)(process_samples + windowLen)); + assert(process_samples == XCORR_UPDATE_SEQUENCE); + + pBuffer = buffer->ptrBegin(); + + // calculate decay factor for xcorr filtering + float xcorr_decay = (float)pow(0.5, 1.0 / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE / process_samples)); + + // prescale pbuffer + float tmp[XCORR_UPDATE_SEQUENCE]; + for (int i = 0; i < process_samples; i++) + { + tmp[i] = hamw[i] * hamw[i] * pBuffer[i]; + } + + #pragma omp parallel for + for (offs = windowStart; offs < windowLen; offs ++) + { + float sum; + int i; + + sum = 0; + for (i = 0; i < process_samples; i ++) + { + 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] += (float)fabs(sum); + } +} + + +// 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); + + // 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++) + { + float sum = 0; + for (int i = 0; i < process_samples; i++) + { + sum += tmp[i] * pBuffer[offs + i]; + } + beatcorr_ringbuff[(beatcorr_ringbuffpos + offs) % windowLen] += (float)((sum > 0) ? sum : 0); // accumulate only positive correlations + } + + int skipstep = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR; + + // compensate empty buffer at beginning by scaling coefficient + float scale = (float)windowLen / (float)(skipstep * init_scaler); + if (scale > 1.0f) + { + init_scaler++; + } + else + { + scale = 1.0f; + } + + // detect beats + for (int i = 0; i < skipstep; i++) + { + LONG_SAMPLETYPE max = 0; + + float sum = beatcorr_ringbuff[beatcorr_ringbuffpos]; + sum -= beat_lpf.update(sum); + + if (sum > peakVal) + { + // found new local largest value + peakVal = sum; + peakPos = pos; + } + if (pos > peakPos + resetDur) + { + // largest value not updated for 200msec => accept as beat + peakPos += skipstep; + if (peakVal > 0) + { + // add detected beat to end of "beats" vector + BEAT temp = { (float)(peakPos * posScale), (float)(peakVal * scale) }; + beats.push_back(temp); + } + + peakVal = 0; + peakPos = pos; + } + + beatcorr_ringbuff[beatcorr_ringbuffpos] = 0; + pos++; + beatcorr_ringbuffpos = (beatcorr_ringbuffpos + 1) % windowLen; + } +} + + +#define max(x,y) ((x) > (y) ? (x) : (y)) + +void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples) +{ + SAMPLETYPE decimated[DECIMATED_BLOCK_SIZE]; + + // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration + while (numSamples > 0) + { + int block; + int decSamples; + + block = (numSamples > INPUT_BLOCK_SIZE) ? INPUT_BLOCK_SIZE : numSamples; + + // decimate. note that converts to mono at the same time + decSamples = decimate(decimated, samples, block); + samples += block * channels; + numSamples -= block; + + buffer->putSamples(decimated, decSamples); + } + + // when the buffer has enough samples for processing... + int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE); + while ((int)buffer->numSamples() >= req) + { + // ... update autocorrelations... + updateXCorr(XCORR_UPDATE_SEQUENCE); + // ...update beat position calculation... + updateBeatPos(XCORR_UPDATE_SEQUENCE / 2); + // ... and remove proceessed samples from the buffer + int n = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR; + buffer->receiveSamples(n); + } +} + + +void BPMDetect::removeBias() +{ + int i; + + // Remove linear bias: calculate linear regression coefficient + // 1. calc mean of 'xcorr' and 'i' + double mean_i = 0; + double mean_x = 0; + for (i = windowStart; i < windowLen; i++) + { + mean_x += xcorr[i]; + } + mean_x /= (windowLen - windowStart); + mean_i = 0.5 * (windowLen - 1 + windowStart); + + // 2. calculate linear regression coefficient + double b = 0; + double div = 0; + for (i = windowStart; i < windowLen; i++) + { + double xt = xcorr[i] - mean_x; + double xi = i - mean_i; + b += xt * xi; + div += xi * xi; + } + b /= div; + + // subtract linear regression and resolve min. value bias + float minval = FLT_MAX; // arbitrary large number + for (i = windowStart; i < windowLen; i ++) + { + xcorr[i] -= (float)(b * i); + if (xcorr[i] < minval) + { + minval = xcorr[i]; + } + } + + // subtract min.value + for (i = windowStart; i < windowLen; i ++) + { + xcorr[i] -= minval; + } +} + + +// Calculate N-point moving average for "source" values +void MAFilter(float *dest, const float *source, int start, int end, int N) +{ + for (int i = start; i < end; i++) + { + int i1 = i - N / 2; + int i2 = i + N / 2 + 1; + if (i1 < start) i1 = start; + if (i2 > end) i2 = end; + + double sum = 0; + for (int j = i1; j < i2; j ++) + { + sum += source[j]; + } + dest[i] = (float)(sum / (i2 - i1)); + } +} + + +float BPMDetect::getBpm() +{ + double peakPos; + double coeff; + PeakFinder peakFinder; + + // remove bias from xcorr data + removeBias(); + + coeff = 60.0 * ((double)sampleRate / (double)decimateBy); + + // save bpm debug data if debug data writing enabled + _SaveDebugData("soundtouch-bpm-xcorr.txt", xcorr, windowStart, windowLen, coeff); + + // Smoothen by N-point moving-average + float *data = new float[windowLen]; + memset(data, 0, sizeof(float) * windowLen); + MAFilter(data, xcorr, windowStart, windowLen, MOVING_AVERAGE_N); + + // find peak position + peakPos = peakFinder.detectPeak(data, windowStart, windowLen); + + // save bpm debug data if debug data writing enabled + _SaveDebugData("soundtouch-bpm-smoothed.txt", data, windowStart, windowLen, coeff); + + delete[] data; + + assert(decimateBy != 0); + if (peakPos < 1e-9) return 0.0; // detection failed. + + _SaveDebugBeatPos("soundtouch-detected-beats.txt", beats); + + // calculate BPM + 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 = (int)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; +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp new file mode 100644 index 00000000..ad368754 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIFOSampleBuffer.cpp @@ -0,0 +1,275 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A buffer class for temporarily storaging sound samples, operates as a +/// first-in-first-out pipe. +/// +/// Samples are added to the end of the sample buffer with the 'putSamples' +/// function, and are received from the beginning of the buffer by calling +/// the 'receiveSamples' function. The class automatically removes the +/// outputted samples from the buffer, as well as grows the buffer size +/// whenever necessary. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <stdlib.h> +#include <memory.h> +#include <string.h> +#include <assert.h> + +#include "FIFOSampleBuffer.h" + +using namespace soundtouch; + +// Constructor +FIFOSampleBuffer::FIFOSampleBuffer(int numChannels) +{ + assert(numChannels > 0); + sizeInBytes = 0; // reasonable initial value + buffer = NULL; + bufferUnaligned = NULL; + samplesInBuffer = 0; + bufferPos = 0; + channels = (uint)numChannels; + ensureCapacity(32); // allocate initial capacity +} + + +// destructor +FIFOSampleBuffer::~FIFOSampleBuffer() +{ + delete[] bufferUnaligned; + bufferUnaligned = NULL; + buffer = NULL; +} + + +// Sets number of channels, 1 = mono, 2 = stereo +void FIFOSampleBuffer::setChannels(int numChannels) +{ + uint usedBytes; + + if (!verifyNumberOfChannels(numChannels)) return; + + usedBytes = channels * samplesInBuffer; + channels = (uint)numChannels; + samplesInBuffer = usedBytes / channels; +} + + +// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and +// zeroes this pointer by copying samples from the 'bufferPos' pointer +// location on to the beginning of the buffer. +void FIFOSampleBuffer::rewind() +{ + if (buffer && bufferPos) + { + memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer); + bufferPos = 0; + } +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position to +// the sample buffer. +void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples) +{ + memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels); + samplesInBuffer += nSamples; +} + + +// Increases the number of samples in the buffer without copying any actual +// samples. +// +// This function is used to update the number of samples in the sample buffer +// when accessing the buffer directly with 'ptrEnd' function. Please be +// careful though! +void FIFOSampleBuffer::putSamples(uint nSamples) +{ + uint req; + + req = samplesInBuffer + nSamples; + ensureCapacity(req); + samplesInBuffer += nSamples; +} + + +// Returns a pointer to the end of the used part of the sample buffer (i.e. +// where the new samples are to be inserted). This function may be used for +// inserting new samples into the sample buffer directly. Please be careful! +// +// Parameter 'slackCapacity' tells the function how much free capacity (in +// terms of samples) there _at least_ should be, in order to the caller to +// successfully insert all the required samples to the buffer. When necessary, +// the function grows the buffer size to comply with this requirement. +// +// When using this function as means for inserting new samples, also remember +// to increase the sample count afterwards, by calling the +// 'putSamples(numSamples)' function. +SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) +{ + ensureCapacity(samplesInBuffer + slackCapacity); + return buffer + samplesInBuffer * channels; +} + + +// Returns a pointer to the beginning of the currently non-outputted samples. +// This function is provided for accessing the output samples directly. +// Please be careful! +// +// When using this function to output samples, also remember to 'remove' the +// outputted samples from the buffer by calling the +// 'receiveSamples(numSamples)' function +SAMPLETYPE *FIFOSampleBuffer::ptrBegin() +{ + assert(buffer); + return buffer + bufferPos * channels; +} + + +// Ensures that the buffer has enough capacity, i.e. space for _at least_ +// 'capacityRequirement' number of samples. The buffer is grown in steps of +// 4 kilobytes to eliminate the need for frequently growing up the buffer, +// as well as to round the buffer size up to the virtual memory page size. +void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement) +{ + SAMPLETYPE *tempUnaligned, *temp; + + if (capacityRequirement > getCapacity()) + { + // enlarge the buffer in 4kbyte steps (round up to next 4k boundary) + sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; + assert(sizeInBytes % 2 == 0); + tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; + if (tempUnaligned == NULL) + { + ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); + } + // Align the buffer to begin at 16byte cache line boundary for optimal performance + temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned); + if (samplesInBuffer) + { + memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE)); + } + delete[] bufferUnaligned; + buffer = temp; + bufferUnaligned = tempUnaligned; + bufferPos = 0; + } + else + { + // simply rewind the buffer (if necessary) + rewind(); + } +} + + +// Returns the current buffer capacity in terms of samples +uint FIFOSampleBuffer::getCapacity() const +{ + return sizeInBytes / (channels * sizeof(SAMPLETYPE)); +} + + +// Returns the number of samples currently in the buffer +uint FIFOSampleBuffer::numSamples() const +{ + return samplesInBuffer; +} + + +// Output samples from beginning of the sample buffer. Copies demanded number +// of samples to output and removes them from the sample buffer. If there +// are less than 'numsample' samples in the buffer, returns all available. +// +// Returns number of samples copied. +uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint num; + + num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples; + + memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num); + return receiveSamples(num); +} + + +// Removes samples from the beginning of the sample buffer without copying them +// anywhere. Used to reduce the number of samples in the buffer, when accessing +// the sample buffer with the 'ptrBegin' function. +uint FIFOSampleBuffer::receiveSamples(uint maxSamples) +{ + if (maxSamples >= samplesInBuffer) + { + uint temp; + + temp = samplesInBuffer; + samplesInBuffer = 0; + return temp; + } + + samplesInBuffer -= maxSamples; + bufferPos += maxSamples; + + return maxSamples; +} + + +// Returns nonzero if the sample buffer is empty +int FIFOSampleBuffer::isEmpty() const +{ + return (samplesInBuffer == 0) ? 1 : 0; +} + + +// Clears the sample buffer +void FIFOSampleBuffer::clear() +{ + samplesInBuffer = 0; + bufferPos = 0; +} + + +/// allow trimming (downwards) amount of samples in pipeline. +/// Returns adjusted amount of samples +uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples) +{ + if (numSamples < samplesInBuffer) + { + samplesInBuffer = numSamples; + } + return samplesInBuffer; +} + + +/// Add silence to end of buffer +void FIFOSampleBuffer::addSilent(uint nSamples) +{ + memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels); + samplesInBuffer += nSamples; +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIRFilter.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIRFilter.cpp new file mode 100644 index 00000000..24cc33bf --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIRFilter.cpp @@ -0,0 +1,329 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Notes : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// This source file contains OpenMP optimizations that allow speeding up the +/// corss-correlation algorithm by executing it in several threads / CPU cores +/// in parallel. See the following article link for more detailed discussion +/// about SoundTouch OpenMP optimizations: +/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <memory.h> +#include <assert.h> +#include <math.h> +#include <stdlib.h> +#include "FIRFilter.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/***************************************************************************** + * + * Implementation of the class 'FIRFilter' + * + *****************************************************************************/ + +FIRFilter::FIRFilter() +{ + resultDivFactor = 0; + resultDivider = 0; + length = 0; + lengthDiv8 = 0; + filterCoeffs = NULL; + filterCoeffsStereo = NULL; +} + + +FIRFilter::~FIRFilter() +{ + delete[] filterCoeffs; + delete[] filterCoeffsStereo; +} + + +// Usual C-version of the filter routine for stereo sound +uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + int j, end; +#ifdef SOUNDTOUCH_FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + // hint compiler autovectorization that loop length is divisible by 8 + int ilength = length & -8; + + assert((length != 0) && (length == ilength) && (src != NULL) && (dest != NULL) && (filterCoeffs != NULL)); + + end = 2 * (numSamples - ilength); + + #pragma omp parallel for + for (j = 0; j < end; j += 2) + { + const SAMPLETYPE *ptr; + LONG_SAMPLETYPE suml, sumr; + + suml = sumr = 0; + ptr = src + j; + + for (int i = 0; i < ilength; i ++) + { + suml += ptr[2 * i] * filterCoeffsStereo[2 * i]; + sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1]; + } + +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + suml >>= resultDivFactor; + sumr >>= resultDivFactor; + // saturate to 16 bit integer limits + suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; + // saturate to 16 bit integer limits + sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; +#endif // SOUNDTOUCH_INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)suml; + dest[j + 1] = (SAMPLETYPE)sumr; + } + return numSamples - ilength; +} + + +// Usual C-version of the filter routine for mono sound +uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const +{ + int j, end; +#ifdef SOUNDTOUCH_FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + // hint compiler autovectorization that loop length is divisible by 8 + int ilength = length & -8; + + assert(ilength != 0); + + end = numSamples - ilength; + #pragma omp parallel for + for (j = 0; j < end; j ++) + { + const SAMPLETYPE *pSrc = src + j; + LONG_SAMPLETYPE sum; + int i; + + sum = 0; + for (i = 0; i < ilength; i ++) + { + sum += pSrc[i] * filterCoeffs[i]; + } +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + sum >>= resultDivFactor; + // saturate to 16 bit integer limits + sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; +#endif // SOUNDTOUCH_INTEGER_SAMPLES + dest[j] = (SAMPLETYPE)sum; + } + return end; +} + + +uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) +{ + int j, end; + +#ifdef SOUNDTOUCH_FLOAT_SAMPLES + // when using floating point samples, use a scaler instead of a divider + // because division is much slower operation than multiplying. + double dScaler = 1.0 / (double)resultDivider; +#endif + + assert(length != 0); + assert(src != NULL); + assert(dest != NULL); + assert(filterCoeffs != NULL); + assert(numChannels < 16); + + // hint compiler autovectorization that loop length is divisible by 8 + int ilength = length & -8; + + end = numChannels * (numSamples - ilength); + + #pragma omp parallel for + for (j = 0; j < end; j += numChannels) + { + const SAMPLETYPE *ptr; + LONG_SAMPLETYPE sums[16]; + uint c; + int i; + + for (c = 0; c < numChannels; c ++) + { + sums[c] = 0; + } + + ptr = src + j; + + for (i = 0; i < ilength; i ++) + { + SAMPLETYPE coef=filterCoeffs[i]; + for (c = 0; c < numChannels; c ++) + { + sums[c] += ptr[0] * coef; + ptr ++; + } + } + + for (c = 0; c < numChannels; c ++) + { +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + sums[c] >>= resultDivFactor; +#endif // SOUNDTOUCH_INTEGER_SAMPLES + dest[j+c] = (SAMPLETYPE)sums[c]; + } + } + return numSamples - ilength; +} + + +// Set filter coeffiecients and length. +// +// Throws an exception if filter length isn't divisible by 8 +void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor) +{ + assert(newLength > 0); + if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8"); + + #ifdef SOUNDTOUCH_FLOAT_SAMPLES + // scale coefficients already here if using floating samples + double scale = 1.0 / resultDivider; + #else + short scale = 1; + #endif + + lengthDiv8 = newLength / 8; + length = lengthDiv8 * 8; + assert(length == newLength); + + resultDivFactor = uResultDivFactor; + resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor); + + delete[] filterCoeffs; + filterCoeffs = new SAMPLETYPE[length]; + delete[] filterCoeffsStereo; + filterCoeffsStereo = new SAMPLETYPE[length*2]; + for (uint i = 0; i < length; i ++) + { + filterCoeffs[i] = (SAMPLETYPE)(coeffs[i] * scale); + // create also stereo set of filter coefficients: this allows compiler + // to autovectorize filter evaluation much more efficiently + filterCoeffsStereo[2 * i] = (SAMPLETYPE)(coeffs[i] * scale); + filterCoeffsStereo[2 * i + 1] = (SAMPLETYPE)(coeffs[i] * scale); + } +} + + +uint FIRFilter::getLength() const +{ + return length; +} + + +// Applies the filter to the given sequence of samples. +// +// Note : The amount of outputted samples is by value of 'filter_length' +// smaller than the amount of input samples. +uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) +{ + assert(length > 0); + assert(lengthDiv8 * 8 == length); + + if (numSamples < length) return 0; + +#ifndef USE_MULTICH_ALWAYS + if (numChannels == 1) + { + return evaluateFilterMono(dest, src, numSamples); + } + else if (numChannels == 2) + { + return evaluateFilterStereo(dest, src, numSamples); + } + else +#endif // USE_MULTICH_ALWAYS + { + assert(numChannels > 0); + return evaluateFilterMulti(dest, src, numSamples, numChannels); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX-capable CPU available or not. +void * FIRFilter::operator new(size_t s) +{ + // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! + ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!"); + return newInstance(); +} + + +FIRFilter * FIRFilter::newInstance() +{ + uint uExtensions; + + uExtensions = detectCPUextensions(); + + // Check if MMX/SSE instruction set extensions supported by CPU + +#ifdef SOUNDTOUCH_ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new FIRFilterMMX; + } + else +#endif // SOUNDTOUCH_ALLOW_MMX + +#ifdef SOUNDTOUCH_ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new FIRFilterSSE; + } + else +#endif // SOUNDTOUCH_ALLOW_SSE + + { + // ISA optimizations not supported, use plain C version + return ::new FIRFilter; + } +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIRFilter.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIRFilter.h new file mode 100644 index 00000000..39c2cc75 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/FIRFilter.h @@ -0,0 +1,140 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// General FIR digital filter routines with MMX optimization. +/// +/// Note : MMX optimized functions reside in a separate, platform-specific file, +/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef FIRFilter_H +#define FIRFilter_H + +#include <stddef.h> +#include "STTypes.h" + +namespace soundtouch +{ + +class FIRFilter +{ +protected: + // Number of FIR filter taps + uint length; + // Number of FIR filter taps divided by 8 + uint lengthDiv8; + + // Result divider factor in 2^k format + uint resultDivFactor; + + // Result divider value. + SAMPLETYPE resultDivider; + + // Memory for filter coefficients + SAMPLETYPE *filterCoeffs; + SAMPLETYPE *filterCoeffsStereo; + + virtual uint evaluateFilterStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples) const; + virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels); + +public: + FIRFilter(); + virtual ~FIRFilter(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX-capable CPU available or not. + static void * operator new(size_t s); + + static FIRFilter *newInstance(); + + /// Applies the filter to the given sequence of samples. + /// Note : The amount of outputted samples is by value of 'filter_length' + /// smaller than the amount of input samples. + /// + /// \return Number of samples copied to 'dest'. + uint evaluate(SAMPLETYPE *dest, + const SAMPLETYPE *src, + uint numSamples, + uint numChannels); + + uint getLength() const; + + virtual void setCoefficients(const SAMPLETYPE *coeffs, + uint newLength, + uint uResultDivFactor); +}; + + +// Optional subclasses that implement CPU-specific optimizations: + +#ifdef SOUNDTOUCH_ALLOW_MMX + +/// Class that implements MMX optimized functions exclusive for 16bit integer samples type. + class FIRFilterMMX : public FIRFilter + { + protected: + short *filterCoeffsUnalign; + short *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; + public: + FIRFilterMMX(); + ~FIRFilterMMX(); + + virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // SOUNDTOUCH_ALLOW_MMX + + +#ifdef SOUNDTOUCH_ALLOW_SSE + /// Class that implements SSE optimized functions exclusive for floating point samples type. + class FIRFilterSSE : public FIRFilter + { + protected: + float *filterCoeffsUnalign; + float *filterCoeffsAlign; + + virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; + public: + FIRFilterSSE(); + ~FIRFilterSSE(); + + virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); + }; + +#endif // SOUNDTOUCH_ALLOW_SSE + +} + +#endif // FIRFilter_H diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateCubic.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateCubic.cpp new file mode 100644 index 00000000..b37b0fa8 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateCubic.cpp @@ -0,0 +1,196 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Cubic interpolation routine. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <stddef.h> +#include <math.h> +#include "InterpolateCubic.h" +#include "STTypes.h" + +using namespace soundtouch; + +// cubic interpolation coefficients +static const float _coeffs[]= +{ -0.5f, 1.0f, -0.5f, 0.0f, + 1.5f, -2.5f, 0.0f, 1.0f, + -1.5f, 2.0f, 0.5f, 0.0f, + 0.5f, -0.5f, 0.0f, 0.0f}; + + +InterpolateCubic::InterpolateCubic() +{ + fract = 0; +} + + +void InterpolateCubic::resetRegisters() +{ + fract = 0; +} + + +/// Transpose mono audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 4; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + float out; + const float x3 = 1.0f; + const float x2 = (float)fract; // x + const float x1 = x2*x2; // x^2 + const float x0 = x1*x2; // x^3 + float y0, y1, y2, y3; + + assert(fract < 1.0); + + y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; + y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; + y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; + y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; + + out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3]; + + pdest[i] = (SAMPLETYPE)out; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose stereo audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 4; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + const float x3 = 1.0f; + const float x2 = (float)fract; // x + const float x1 = x2*x2; // x^2 + const float x0 = x1*x2; // x^3 + float y0, y1, y2, y3; + float out0, out1; + + assert(fract < 1.0); + + y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; + y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; + y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; + y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; + + out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6]; + out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7]; + + pdest[2*i] = (SAMPLETYPE)out0; + pdest[2*i+1] = (SAMPLETYPE)out1; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += 2*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose multi-channel audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 4; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + const float x3 = 1.0f; + const float x2 = (float)fract; // x + const float x1 = x2*x2; // x^2 + const float x0 = x1*x2; // x^3 + float y0, y1, y2, y3; + + assert(fract < 1.0); + + y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3; + y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3; + y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3; + y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3; + + for (int c = 0; c < numChannels; c ++) + { + float out; + out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels]; + pdest[0] = (SAMPLETYPE)out; + pdest ++; + } + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += numChannels*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateCubic.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateCubic.h new file mode 100644 index 00000000..481abd64 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateCubic.h @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Cubic interpolation routine. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _InterpolateCubic_H_ +#define _InterpolateCubic_H_ + +#include "RateTransposer.h" +#include "STTypes.h" + +namespace soundtouch +{ + +class InterpolateCubic : public TransposerBase +{ +protected: + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeMulti(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + + double fract; + +public: + InterpolateCubic(); + + virtual void resetRegisters(); + + int getLatency() const + { + return 1; + } +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateLinear.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateLinear.cpp new file mode 100644 index 00000000..9533e79b --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateLinear.cpp @@ -0,0 +1,296 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Linear interpolation algorithm. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <assert.h> +#include <stdlib.h> +#include "InterpolateLinear.h" + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// InterpolateLinearInteger - integer arithmetic implementation +// + +/// fixed-point interpolation routine precision +#define SCALE 65536 + + +// Constructor +InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase() +{ + // Notice: use local function calling syntax for sake of clarity, + // to indicate the fact that C++ constructor can't call virtual functions. + resetRegisters(); + setRate(1.0f); +} + + +void InterpolateLinearInteger::resetRegisters() +{ + iFract = 0; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + LONG_SAMPLETYPE temp; + + assert(iFract < SCALE); + + temp = (SCALE - iFract) * src[0] + iFract * src[1]; + dest[i] = (SAMPLETYPE)(temp / SCALE); + i++; + + iFract += iRate; + + int iWhole = iFract / SCALE; + iFract -= iWhole * SCALE; + srcCount += iWhole; + src += iWhole; + } + srcSamples = srcCount; + + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Stereo' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + LONG_SAMPLETYPE temp0; + LONG_SAMPLETYPE temp1; + + assert(iFract < SCALE); + + temp0 = (SCALE - iFract) * src[0] + iFract * src[2]; + temp1 = (SCALE - iFract) * src[1] + iFract * src[3]; + dest[0] = (SAMPLETYPE)(temp0 / SCALE); + dest[1] = (SAMPLETYPE)(temp1 / SCALE); + dest += 2; + i++; + + iFract += iRate; + + int iWhole = iFract / SCALE; + iFract -= iWhole * SCALE; + srcCount += iWhole; + src += 2*iWhole; + } + srcSamples = srcCount; + + return i; +} + + +int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + LONG_SAMPLETYPE temp, vol1; + + assert(iFract < SCALE); + vol1 = (LONG_SAMPLETYPE)(SCALE - iFract); + for (int c = 0; c < numChannels; c ++) + { + temp = vol1 * src[c] + iFract * src[c + numChannels]; + dest[0] = (SAMPLETYPE)(temp / SCALE); + dest ++; + } + i++; + + iFract += iRate; + + int iWhole = iFract / SCALE; + iFract -= iWhole * SCALE; + srcCount += iWhole; + src += iWhole * numChannels; + } + srcSamples = srcCount; + + return i; +} + + +// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower +// iRate, larger faster iRates. +void InterpolateLinearInteger::setRate(double newRate) +{ + iRate = (int)(newRate * SCALE + 0.5); + TransposerBase::setRate(newRate); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// InterpolateLinearFloat - floating point arithmetic implementation +// +////////////////////////////////////////////////////////////////////////////// + + +// Constructor +InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase() +{ + // Notice: use local function calling syntax for sake of clarity, + // to indicate the fact that C++ constructor can't call virtual functions. + resetRegisters(); + setRate(1.0); +} + + +void InterpolateLinearFloat::resetRegisters() +{ + fract = 0; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out; + assert(fract < 1.0); + + out = (1.0 - fract) * src[0] + fract * src[1]; + dest[i] = (SAMPLETYPE)out; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + src += whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// 'Mono' version of the routine. Returns the number of samples returned in +// the "dest" buffer +int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out0, out1; + assert(fract < 1.0); + + out0 = (1.0 - fract) * src[0] + fract * src[2]; + out1 = (1.0 - fract) * src[1] + fract * src[3]; + dest[2*i] = (SAMPLETYPE)out0; + dest[2*i+1] = (SAMPLETYPE)out1; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + src += 2*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 1; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + float temp, vol1, fract_float; + + vol1 = (float)(1.0 - fract); + fract_float = (float)fract; + for (int c = 0; c < numChannels; c ++) + { + temp = vol1 * src[c] + fract_float * src[c + numChannels]; + *dest = (SAMPLETYPE)temp; + dest ++; + } + i++; + + fract += rate; + + int iWhole = (int)fract; + fract -= iWhole; + srcCount += iWhole; + src += iWhole * numChannels; + } + srcSamples = srcCount; + + return i; +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateLinear.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateLinear.h new file mode 100644 index 00000000..ff362e84 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateLinear.h @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Linear interpolation routine. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _InterpolateLinear_H_ +#define _InterpolateLinear_H_ + +#include "RateTransposer.h" +#include "STTypes.h" + +namespace soundtouch +{ + +/// Linear transposer class that uses integer arithmetic +class InterpolateLinearInteger : public TransposerBase +{ +protected: + int iFract; + int iRate; + + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); +public: + InterpolateLinearInteger(); + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(double newRate); + + virtual void resetRegisters(); + + int getLatency() const + { + return 0; + } +}; + + +/// Linear transposer class that uses floating point arithmetic +class InterpolateLinearFloat : public TransposerBase +{ +protected: + double fract; + + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); + +public: + InterpolateLinearFloat(); + + virtual void resetRegisters(); + + int getLatency() const + { + return 0; + } +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateShannon.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateShannon.cpp new file mode 100644 index 00000000..975d872a --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateShannon.cpp @@ -0,0 +1,181 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample interpolation routine using 8-tap band-limited Shannon interpolation +/// with kaiser window. +/// +/// Notice. This algorithm is remarkably much heavier than linear or cubic +/// interpolation, and not remarkably better than cubic algorithm. Thus mostly +/// for experimental purposes +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <math.h> +#include "InterpolateShannon.h" +#include "STTypes.h" + +using namespace soundtouch; + + +/// Kaiser window with beta = 2.0 +/// Values scaled down by 5% to avoid overflows +static const double _kaiser8[8] = +{ + 0.41778693317814, + 0.64888025049173, + 0.83508562409944, + 0.93887857733412, + 0.93887857733412, + 0.83508562409944, + 0.64888025049173, + 0.41778693317814 +}; + + +InterpolateShannon::InterpolateShannon() +{ + fract = 0; +} + + +void InterpolateShannon::resetRegisters() +{ + fract = 0; +} + + +#define PI 3.1415926536 +#define sinc(x) (sin(PI * (x)) / (PI * (x))) + +/// Transpose mono audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 8; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out; + assert(fract < 1.0); + + out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0]; + out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1]; + out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2]; + if (fract < 1e-6) + { + out += psrc[3] * _kaiser8[3]; // sinc(0) = 1 + } + else + { + out += psrc[3] * sinc(- fract) * _kaiser8[3]; + } + out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4]; + out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5]; + out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6]; + out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7]; + + pdest[i] = (SAMPLETYPE)out; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose stereo audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + int i; + int srcSampleEnd = srcSamples - 8; + int srcCount = 0; + + i = 0; + while (srcCount < srcSampleEnd) + { + double out0, out1, w; + assert(fract < 1.0); + + w = sinc(-3.0 - fract) * _kaiser8[0]; + out0 = psrc[0] * w; out1 = psrc[1] * w; + w = sinc(-2.0 - fract) * _kaiser8[1]; + out0 += psrc[2] * w; out1 += psrc[3] * w; + w = sinc(-1.0 - fract) * _kaiser8[2]; + out0 += psrc[4] * w; out1 += psrc[5] * w; + w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1 + out0 += psrc[6] * w; out1 += psrc[7] * w; + w = sinc( 1.0 - fract) * _kaiser8[4]; + out0 += psrc[8] * w; out1 += psrc[9] * w; + w = sinc( 2.0 - fract) * _kaiser8[5]; + out0 += psrc[10] * w; out1 += psrc[11] * w; + w = sinc( 3.0 - fract) * _kaiser8[6]; + out0 += psrc[12] * w; out1 += psrc[13] * w; + w = sinc( 4.0 - fract) * _kaiser8[7]; + out0 += psrc[14] * w; out1 += psrc[15] * w; + + pdest[2*i] = (SAMPLETYPE)out0; + pdest[2*i+1] = (SAMPLETYPE)out1; + i ++; + + // update position fraction + fract += rate; + // update whole positions + int whole = (int)fract; + fract -= whole; + psrc += 2*whole; + srcCount += whole; + } + srcSamples = srcCount; + return i; +} + + +/// Transpose stereo audio. Returns number of produced output samples, and +/// updates "srcSamples" to amount of consumed source samples +int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, + const SAMPLETYPE *psrc, + int &srcSamples) +{ + // not implemented + assert(false); + return 0; +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateShannon.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateShannon.h new file mode 100644 index 00000000..72ab0b52 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/InterpolateShannon.h @@ -0,0 +1,74 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample interpolation routine using 8-tap band-limited Shannon interpolation +/// with kaiser window. +/// +/// Notice. This algorithm is remarkably much heavier than linear or cubic +/// interpolation, and not remarkably better than cubic algorithm. Thus mostly +/// for experimental purposes +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _InterpolateShannon_H_ +#define _InterpolateShannon_H_ + +#include "RateTransposer.h" +#include "STTypes.h" + +namespace soundtouch +{ + +class InterpolateShannon : public TransposerBase +{ +protected: + int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + int transposeMulti(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples); + + double fract; + +public: + InterpolateShannon(); + + void resetRegisters(); + + int getLatency() const + { + return 3; + } +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/Makefile.am b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/Makefile.am new file mode 100644 index 00000000..59960f1d --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/Makefile.am @@ -0,0 +1,74 @@ +## Process this file with automake to create Makefile.in +## +## This file is part of SoundTouch, an audio processing library for pitch/time adjustments +## +## SoundTouch is free software; you can redistribute it and/or modify it under the +## terms of the GNU General Public License as published by the Free Software +## Foundation; either version 2 of the License, or (at your option) any later +## version. +## +## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY +## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +## A PARTICULAR PURPOSE. See the GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License along with +## this program; if not, write to the Free Software Foundation, Inc., 59 Temple +## Place - Suite 330, Boston, MA 02111-1307, USA + + +include $(top_srcdir)/config/am_include.mk + + +# set to something if you want other stuff to be included in the distribution tarball +EXTRA_DIST=SoundTouch.sln SoundTouch.vcxproj + +noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h \ + InterpolateCubic.h InterpolateLinear.h InterpolateShannon.h + +lib_LTLIBRARIES=libSoundTouch.la +# +libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp \ + RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp \ + BPMDetect.cpp PeakFinder.cpp InterpolateLinear.cpp InterpolateCubic.cpp \ + InterpolateShannon.cpp + +# Compiler flags +#AM_CXXFLAGS+= + +# Compile the files that need MMX and SSE individually. +libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la +noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la +libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp +libSoundTouchSSE_la_SOURCES=sse_optimized.cpp + +# We enable optimizations by default. +# If MMX is supported compile with -mmmx. +# Do not assume -msse is also supported. +if HAVE_MMX +libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS) +else +libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS) +endif + +# We enable optimizations by default. +# If SSE is supported compile with -msse. +if HAVE_SSE +libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS) +else +libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS) +endif + +# Let the user disable optimizations if he wishes to. +if !X86_OPTIMIZATIONS +libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS) +libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS) +endif + +# Modify the default 0.0.0 to LIB_SONAME.0.0 +libSoundTouch_la_LDFLAGS=-version-info @LIB_SONAME@ + +# other linking flags to add +# noinst_LTLIBRARIES = libSoundTouchOpt.la +# libSoundTouch_la_LIBADD = libSoundTouchOpt.la +# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp +# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/PeakFinder.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/PeakFinder.cpp new file mode 100644 index 00000000..44dc937a --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/PeakFinder.cpp @@ -0,0 +1,277 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Peak detection routine. +/// +/// The routine detects highest value on an array of values and calculates the +/// precise peak location as a mass-center of the 'hump' around the peak value. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <math.h> +#include <assert.h> + +#include "PeakFinder.h" + +using namespace soundtouch; + +#define max(x, y) (((x) > (y)) ? (x) : (y)) + + +PeakFinder::PeakFinder() +{ + minPos = maxPos = 0; +} + + +// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. +int PeakFinder::findTop(const float *data, int peakpos) const +{ + int i; + int start, end; + float refvalue; + + refvalue = data[peakpos]; + + // seek within ±10 points + start = peakpos - 10; + if (start < minPos) start = minPos; + end = peakpos + 10; + if (end > maxPos) end = maxPos; + + for (i = start; i <= end; i ++) + { + if (data[i] > refvalue) + { + peakpos = i; + refvalue = data[i]; + } + } + + // failure if max value is at edges of seek range => it's not peak, it's at slope. + if ((peakpos == start) || (peakpos == end)) return 0; + + return peakpos; +} + + +// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding +// to direction defined by 'direction' until next 'hump' after minimum value will +// begin +int PeakFinder::findGround(const float *data, int peakpos, int direction) const +{ + int lowpos; + int pos; + int climb_count; + float refvalue; + float delta; + + climb_count = 0; + refvalue = data[peakpos]; + lowpos = peakpos; + + pos = peakpos; + + while ((pos > minPos+1) && (pos < maxPos-1)) + { + int prevpos; + + prevpos = pos; + pos += direction; + + // calculate derivate + delta = data[pos] - data[prevpos]; + if (delta <= 0) + { + // going downhill, ok + if (climb_count) + { + climb_count --; // decrease climb count + } + + // check if new minimum found + if (data[pos] < refvalue) + { + // new minimum found + lowpos = pos; + refvalue = data[pos]; + } + } + else + { + // going uphill, increase climbing counter + climb_count ++; + if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit + } + } + return lowpos; +} + + +// Find offset where the value crosses the given level, when starting from 'peakpos' and +// proceeds to direction defined in 'direction' +int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const +{ + float peaklevel; + int pos; + + peaklevel = data[peakpos]; + assert(peaklevel >= level); + pos = peakpos; + while ((pos >= minPos) && (pos + direction < maxPos)) + { + if (data[pos + direction] < level) return pos; // crossing found + pos += direction; + } + return -1; // not found +} + + +// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos' +double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const +{ + int i; + float sum; + float wsum; + + sum = 0; + wsum = 0; + for (i = firstPos; i <= lastPos; i ++) + { + sum += (float)i * data[i]; + wsum += data[i]; + } + + if (wsum < 1e-6) return 0; + return sum / wsum; +} + + +/// get exact center of peak near given position by calculating local mass of center +double PeakFinder::getPeakCenter(const float *data, int peakpos) const +{ + float peakLevel; // peak level + int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level + float cutLevel; // cutting value + float groundLevel; // ground level of the peak + int gp1, gp2; // bottom positions of the peak 'hump' + + // find ground positions. + gp1 = findGround(data, peakpos, -1); + gp2 = findGround(data, peakpos, 1); + + peakLevel = data[peakpos]; + + if (gp1 == gp2) + { + // avoid rounding errors when all are equal + assert(gp1 == peakpos); + cutLevel = groundLevel = peakLevel; + } else { + // get average of the ground levels + groundLevel = 0.5f * (data[gp1] + data[gp2]); + + // calculate 70%-level of the peak + cutLevel = 0.70f * peakLevel + 0.30f * groundLevel; + } + + // find mid-level crossings + crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1); + crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1); + + if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak.. + + // calculate mass center of the peak surroundings + return calcMassCenter(data, crosspos1, crosspos2); +} + + +double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) +{ + + int i; + int peakpos; // position of peak level + double highPeak, peak; + + this->minPos = aminPos; + this->maxPos = amaxPos; + + // find absolute peak + peakpos = minPos; + peak = data[minPos]; + for (i = minPos + 1; i < maxPos; i ++) + { + if (data[i] > peak) + { + peak = data[i]; + peakpos = i; + } + } + + // Calculate exact location of the highest peak mass center + highPeak = getPeakCenter(data, peakpos); + peak = highPeak; + + // Now check if the highest peak were in fact harmonic of the true base beat peak + // - sometimes the highest peak can be Nth harmonic of the true base peak yet + // just a slightly higher than the true base + + for (i = 1; i < 3; i ++) + { + double peaktmp, harmonic; + int i1,i2; + + harmonic = (double)pow(2.0, i); + peakpos = (int)(highPeak / harmonic + 0.5f); + if (peakpos < minPos) break; + peakpos = findTop(data, peakpos); // seek true local maximum index + if (peakpos == 0) continue; // no local max here + + // calculate mass-center of possible harmonic peak + peaktmp = getPeakCenter(data, peakpos); + + // accept harmonic peak if + // (a) it is found + // (b) is within ±4% of the expected harmonic interval + // (c) has at least half x-corr value of the max. peak + + double diff = harmonic * peaktmp / highPeak; + if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected + + // now compare to highest detected peak + i1 = (int)(highPeak + 0.5); + i2 = (int)(peaktmp + 0.5); + if (data[i2] >= 0.4*data[i1]) + { + // The harmonic is at least half as high primary peak, + // thus use the harmonic peak instead + peak = peaktmp; + } + } + + return peak; +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/PeakFinder.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/PeakFinder.h new file mode 100644 index 00000000..bf46daa1 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/PeakFinder.h @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// The routine detects highest value on an array of values and calculates the +/// precise peak location as a mass-center of the 'hump' around the peak value. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _PeakFinder_H_ +#define _PeakFinder_H_ + +namespace soundtouch +{ + +class PeakFinder +{ +protected: + /// Min, max allowed peak positions within the data vector + int minPos, maxPos; + + /// Calculates the mass center between given vector items. + double calcMassCenter(const float *data, ///< Data vector. + int firstPos, ///< Index of first vector item belonging to the peak. + int lastPos ///< Index of last vector item belonging to the peak. + ) const; + + /// Finds the data vector index where the monotoniously decreasing signal crosses the + /// given level. + int findCrossingLevel(const float *data, ///< Data vector. + float level, ///< Goal crossing level. + int peakpos, ///< Peak position index within the data vector. + int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. + ) const; + + // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'. + int findTop(const float *data, int peakpos) const; + + + /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- + /// or left-hand side of the given peak position. + int findGround(const float *data, /// Data vector. + int peakpos, /// Peak position index within the data vector. + int direction /// Direction where to proceed from the peak: 1 = right, -1 = left. + ) const; + + /// get exact center of peak near given position by calculating local mass of center + double getPeakCenter(const float *data, int peakpos) const; + +public: + /// Constructor. + PeakFinder(); + + /// Detect exact peak position of the data vector by finding the largest peak 'hump' + /// and calculating the mass-center location of the peak hump. + /// + /// \return The location of the largest base harmonic peak hump. + double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has + /// to be at least 'maxPos' items long. + int minPos, ///< Min allowed peak location within the vector data. + int maxPos ///< Max allowed peak location within the vector data. + ); +}; + +} + +#endif // _PeakFinder_H_ diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/RateTransposer.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/RateTransposer.cpp new file mode 100644 index 00000000..4c202391 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/RateTransposer.cpp @@ -0,0 +1,315 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application) +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <memory.h> +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include "RateTransposer.h" +#include "InterpolateLinear.h" +#include "InterpolateCubic.h" +#include "InterpolateShannon.h" +#include "AAFilter.h" + +using namespace soundtouch; + +// Define default interpolation algorithm here +TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC; + + +// Constructor +RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer) +{ + bUseAAFilter = +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + true; +#else + // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover + false; +#endif + + // Instantiates the anti-alias filter + pAAFilter = new AAFilter(64); + pTransposer = TransposerBase::newInstance(); + clear(); +} + + +RateTransposer::~RateTransposer() +{ + delete pAAFilter; + delete pTransposer; +} + + +/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable +void RateTransposer::enableAAFilter(bool newMode) +{ +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover + bUseAAFilter = newMode; + clear(); +#endif +} + + +/// Returns nonzero if anti-alias filter is enabled. +bool RateTransposer::isAAFilterEnabled() const +{ + return bUseAAFilter; +} + + +AAFilter *RateTransposer::getAAFilter() +{ + return pAAFilter; +} + + +// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower +// iRate, larger faster iRates. +void RateTransposer::setRate(double newRate) +{ + double fCutoff; + + pTransposer->setRate(newRate); + + // design a new anti-alias filter + if (newRate > 1.0) + { + fCutoff = 0.5 / newRate; + } + else + { + fCutoff = 0.5 * newRate; + } + pAAFilter->setCutoffFreq(fCutoff); +} + + +// Adds 'nSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples) +{ + processSamples(samples, nSamples); +} + + +// Transposes sample rate by applying anti-alias filter to prevent folding. +// Returns amount of samples returned in the "dest" buffer. +// The maximum amount of samples that can be returned at a time is set by +// the 'set_returnBuffer_size' function. +void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) +{ + uint count; + + if (nSamples == 0) return; + + // Store samples to input buffer + inputBuffer.putSamples(src, nSamples); + + // If anti-alias filter is turned off, simply transpose without applying + // the filter + if (bUseAAFilter == false) + { + count = pTransposer->transpose(outputBuffer, inputBuffer); + return; + } + + assert(pAAFilter); + + // Transpose with anti-alias filter + if (pTransposer->rate < 1.0f) + { + // If the parameter 'Rate' value is smaller than 1, first transpose + // the samples and then apply the anti-alias filter to remove aliasing. + + // Transpose the samples, store the result to end of "midBuffer" + pTransposer->transpose(midBuffer, inputBuffer); + + // Apply the anti-alias filter for transposed samples in midBuffer + pAAFilter->evaluate(outputBuffer, midBuffer); + } + else + { + // If the parameter 'Rate' value is larger than 1, first apply the + // anti-alias filter to remove high frequencies (prevent them from folding + // over the lover frequencies), then transpose. + + // Apply the anti-alias filter for samples in inputBuffer + pAAFilter->evaluate(midBuffer, inputBuffer); + + // Transpose the AA-filtered samples in "midBuffer" + pTransposer->transpose(outputBuffer, midBuffer); + } +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void RateTransposer::setChannels(int nChannels) +{ + if (!verifyNumberOfChannels(nChannels) || + (pTransposer->numChannels == nChannels)) return; + + pTransposer->setChannels(nChannels); + inputBuffer.setChannels(nChannels); + midBuffer.setChannels(nChannels); + outputBuffer.setChannels(nChannels); +} + + +// Clears all the samples in the object +void RateTransposer::clear() +{ + outputBuffer.clear(); + midBuffer.clear(); + inputBuffer.clear(); + pTransposer->resetRegisters(); + + // prefill buffer to avoid losing first samples at beginning of stream + int prefill = getLatency(); + inputBuffer.addSilent(prefill); +} + + +// Returns nonzero if there aren't any samples available for outputting. +int RateTransposer::isEmpty() const +{ + int res; + + res = FIFOProcessor::isEmpty(); + if (res == 0) return 0; + return inputBuffer.isEmpty(); +} + + +/// Return approximate initial input-output latency +int RateTransposer::getLatency() const +{ + return pTransposer->getLatency() + + ((bUseAAFilter) ? (pAAFilter->getLength() / 2) : 0); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// TransposerBase - Base class for interpolation +// + +// static function to set interpolation algorithm +void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a) +{ + TransposerBase::algorithm = a; +} + + +// Transposes the sample rate of the given samples using linear interpolation. +// Returns the number of samples returned in the "dest" buffer +int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) +{ + int numSrcSamples = src.numSamples(); + int sizeDemand = (int)((double)numSrcSamples / rate) + 8; + int numOutput; + SAMPLETYPE *psrc = src.ptrBegin(); + SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand); + +#ifndef USE_MULTICH_ALWAYS + if (numChannels == 1) + { + numOutput = transposeMono(pdest, psrc, numSrcSamples); + } + else if (numChannels == 2) + { + numOutput = transposeStereo(pdest, psrc, numSrcSamples); + } + else +#endif // USE_MULTICH_ALWAYS + { + assert(numChannels > 0); + numOutput = transposeMulti(pdest, psrc, numSrcSamples); + } + dest.putSamples(numOutput); + src.receiveSamples(numSrcSamples); + return numOutput; +} + + +TransposerBase::TransposerBase() +{ + numChannels = 0; + rate = 1.0f; +} + + +TransposerBase::~TransposerBase() +{ +} + + +void TransposerBase::setChannels(int channels) +{ + numChannels = channels; + resetRegisters(); +} + + +void TransposerBase::setRate(double newRate) +{ + rate = newRate; +} + + +// static factory function +TransposerBase *TransposerBase::newInstance() +{ +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + // Notice: For integer arithmetic support only linear algorithm (due to simplest calculus) + return ::new InterpolateLinearInteger; +#else + switch (algorithm) + { + case LINEAR: + return new InterpolateLinearFloat; + + case CUBIC: + return new InterpolateCubic; + + case SHANNON: + return new InterpolateShannon; + + default: + assert(false); + return NULL; + } +#endif +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/RateTransposer.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/RateTransposer.h new file mode 100644 index 00000000..59381fab --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/RateTransposer.h @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sample rate transposer. Changes sample rate by using linear interpolation +/// together with anti-alias filtering (first order interpolation with anti- +/// alias filtering should be quite adequate for this application). +/// +/// Use either of the derived classes of 'RateTransposerInteger' or +/// 'RateTransposerFloat' for corresponding integer/floating point tranposing +/// algorithm implementation. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef RateTransposer_H +#define RateTransposer_H + +#include <stddef.h> +#include "AAFilter.h" +#include "FIFOSamplePipe.h" +#include "FIFOSampleBuffer.h" + +#include "STTypes.h" + +namespace soundtouch +{ + +/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc) +class TransposerBase +{ +public: + enum ALGORITHM { + LINEAR = 0, + CUBIC, + SHANNON + }; + +protected: + virtual int transposeMono(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples) = 0; + virtual int transposeStereo(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples) = 0; + virtual int transposeMulti(SAMPLETYPE *dest, + const SAMPLETYPE *src, + int &srcSamples) = 0; + + static ALGORITHM algorithm; + +public: + double rate; + int numChannels; + + TransposerBase(); + virtual ~TransposerBase(); + + virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src); + virtual void setRate(double newRate); + virtual void setChannels(int channels); + virtual int getLatency() const = 0; + + virtual void resetRegisters() = 0; + + // static factory function + static TransposerBase *newInstance(); + + // static function to set interpolation algorithm + static void setAlgorithm(ALGORITHM a); +}; + + +/// A common linear samplerate transposer class. +/// +class RateTransposer : public FIFOProcessor +{ +protected: + /// Anti-alias filter object + AAFilter *pAAFilter; + TransposerBase *pTransposer; + + /// Buffer for collecting samples to feed the anti-alias filter between + /// two batches + FIFOSampleBuffer inputBuffer; + + /// Buffer for keeping samples between transposing & anti-alias filter + FIFOSampleBuffer midBuffer; + + /// Output sample buffer + FIFOSampleBuffer outputBuffer; + + bool bUseAAFilter; + + + /// Transposes sample rate by applying anti-alias filter to prevent folding. + /// Returns amount of samples returned in the "dest" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(const SAMPLETYPE *src, + uint numSamples); + +public: + RateTransposer(); + virtual ~RateTransposer(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Return anti-alias filter object + AAFilter *getAAFilter(); + + /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable + void enableAAFilter(bool newMode); + + /// Returns nonzero if anti-alias filter is enabled. + bool isAAFilterEnabled() const; + + /// Sets new target rate. Normal rate = 1.0, smaller values represent slower + /// rate, larger faster rates. + virtual void setRate(double newRate); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(int channels); + + /// Adds 'numSamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + void putSamples(const SAMPLETYPE *samples, uint numSamples); + + /// Clears all the samples in the object + void clear(); + + /// Returns nonzero if there aren't any samples available for outputting. + int isEmpty() const; + + /// Return approximate initial input-output latency + int getLatency() const; +}; + +} + +#endif diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/SoundTouch.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/SoundTouch.cpp new file mode 100644 index 00000000..69fba8b9 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/SoundTouch.cpp @@ -0,0 +1,538 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch - main class for tempo/pitch/rate adjusting routines. +/// +/// Notes: +/// - Initialize the SoundTouch object instance by setting up the sound stream +/// parameters with functions 'setSampleRate' and 'setChannels', then set +/// desired tempo/pitch/rate settings with the corresponding functions. +/// +/// - The SoundTouch class behaves like a first-in-first-out pipeline: The +/// samples that are to be processed are fed into one of the pipe by calling +/// function 'putSamples', while the ready processed samples can be read +/// from the other end of the pipeline with function 'receiveSamples'. +/// +/// - The SoundTouch processing classes require certain sized 'batches' of +/// samples in order to process the sound. For this reason the classes buffer +/// incoming samples until there are enough of samples available for +/// processing, then they carry out the processing step and consequently +/// make the processed samples available for outputting. +/// +/// - For the above reason, the processing routines introduce a certain +/// 'latency' between the input and output, so that the samples input to +/// SoundTouch may not be immediately available in the output, and neither +/// the amount of outputtable samples may not immediately be in direct +/// relationship with the amount of previously input samples. +/// +/// - The tempo/pitch/rate control parameters can be altered during processing. +/// Please notice though that they aren't currently protected by semaphores, +/// so in multi-thread application external semaphore protection may be +/// required. +/// +/// - This class utilizes classes 'TDStretch' for tempo change (without modifying +/// pitch) and 'RateTransposer' for changing the playback rate (that is, both +/// tempo and pitch in the same ratio) of the sound. The third available control +/// 'pitch' (change pitch but maintain tempo) is produced by a combination of +/// combining the two other controls. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <assert.h> +#include <stdlib.h> +#include <memory.h> +#include <math.h> +#include <stdio.h> + +#include "SoundTouch.h" +#include "TDStretch.h" +#include "RateTransposer.h" +#include "cpu_detect.h" + +using namespace soundtouch; + +/// test if two floating point numbers are equal +#define TEST_FLOAT_EQUAL(a, b) (fabs(a - b) < 1e-10) + + +/// Print library version string for autoconf +extern "C" void soundtouch_ac_test() +{ + printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION); +} + + +SoundTouch::SoundTouch() +{ + // Initialize rate transposer and tempo changer instances + + pRateTransposer = new RateTransposer(); + pTDStretch = TDStretch::newInstance(); + + setOutPipe(pTDStretch); + + rate = tempo = 0; + + virtualPitch = + virtualRate = + virtualTempo = 1.0; + + calcEffectiveRateAndTempo(); + + samplesExpectedOut = 0; + samplesOutput = 0; + + channels = 0; + bSrateSet = false; +} + + +SoundTouch::~SoundTouch() +{ + delete pRateTransposer; + delete pTDStretch; +} + + +/// Get SoundTouch library version string +const char *SoundTouch::getVersionString() +{ + static const char *_version = SOUNDTOUCH_VERSION; + + return _version; +} + + +/// Get SoundTouch library version Id +uint SoundTouch::getVersionId() +{ + return SOUNDTOUCH_VERSION_ID; +} + + +// Sets the number of channels, 1 = mono, 2 = stereo +void SoundTouch::setChannels(uint numChannels) +{ + if (!verifyNumberOfChannels(numChannels)) return; + + channels = numChannels; + pRateTransposer->setChannels((int)numChannels); + pTDStretch->setChannels((int)numChannels); +} + + +// Sets new rate control value. Normal rate = 1.0, smaller values +// represent slower rate, larger faster rates. +void SoundTouch::setRate(double newRate) +{ + virtualRate = newRate; + calcEffectiveRateAndTempo(); +} + + +// Sets new rate control value as a difference in percents compared +// to the original rate (-50 .. +100 %) +void SoundTouch::setRateChange(double newRate) +{ + virtualRate = 1.0 + 0.01 * newRate; + calcEffectiveRateAndTempo(); +} + + +// Sets new tempo control value. Normal tempo = 1.0, smaller values +// represent slower tempo, larger faster tempo. +void SoundTouch::setTempo(double newTempo) +{ + virtualTempo = newTempo; + calcEffectiveRateAndTempo(); +} + + +// Sets new tempo control value as a difference in percents compared +// to the original tempo (-50 .. +100 %) +void SoundTouch::setTempoChange(double newTempo) +{ + virtualTempo = 1.0 + 0.01 * newTempo; + calcEffectiveRateAndTempo(); +} + + +// Sets new pitch control value. Original pitch = 1.0, smaller values +// represent lower pitches, larger values higher pitch. +void SoundTouch::setPitch(double newPitch) +{ + virtualPitch = newPitch; + calcEffectiveRateAndTempo(); +} + + +// Sets pitch change in octaves compared to the original pitch +// (-1.00 .. +1.00) +void SoundTouch::setPitchOctaves(double newPitch) +{ + virtualPitch = exp(0.69314718056 * newPitch); + calcEffectiveRateAndTempo(); +} + + +// Sets pitch change in semi-tones compared to the original pitch +// (-12 .. +12) +void SoundTouch::setPitchSemiTones(int newPitch) +{ + setPitchOctaves((double)newPitch / 12.0); +} + + +void SoundTouch::setPitchSemiTones(double newPitch) +{ + setPitchOctaves(newPitch / 12.0); +} + + +// Calculates 'effective' rate and tempo values from the +// nominal control values. +void SoundTouch::calcEffectiveRateAndTempo() +{ + double oldTempo = tempo; + double oldRate = rate; + + tempo = virtualTempo / virtualPitch; + rate = virtualPitch * virtualRate; + + if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate); + if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo); + +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + if (rate <= 1.0f) + { + if (output != pTDStretch) + { + FIFOSamplePipe *tempoOut; + + assert(output == pRateTransposer); + // move samples in the current output buffer to the output of pTDStretch + tempoOut = pTDStretch->getOutput(); + tempoOut->moveSamples(*output); + // move samples in pitch transposer's store buffer to tempo changer's input + // deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore()); + + output = pTDStretch; + } + } + else +#endif + { + if (output != pRateTransposer) + { + FIFOSamplePipe *transOut; + + assert(output == pTDStretch); + // move samples in the current output buffer to the output of pRateTransposer + transOut = pRateTransposer->getOutput(); + transOut->moveSamples(*output); + // move samples in tempo changer's input to pitch transposer's input + pRateTransposer->moveSamples(*pTDStretch->getInput()); + + output = pRateTransposer; + } + } +} + + +// Sets sample rate. +void SoundTouch::setSampleRate(uint srate) +{ + // set sample rate, leave other tempo changer parameters as they are. + pTDStretch->setParameters((int)srate); + bSrateSet = true; +} + + +// Adds 'numSamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples) +{ + if (bSrateSet == false) + { + ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined"); + } + else if (channels == 0) + { + ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined"); + } + + // accumulate how many samples are expected out from processing, given the current + // processing setting + samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo); + +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + if (rate <= 1.0f) + { + // transpose the rate down, output the transposed sound to tempo changer buffer + assert(output == pTDStretch); + pRateTransposer->putSamples(samples, nSamples); + pTDStretch->moveSamples(*pRateTransposer); + } + else +#endif + { + // evaluate the tempo changer, then transpose the rate up, + assert(output == pRateTransposer); + pTDStretch->putSamples(samples, nSamples); + pRateTransposer->moveSamples(*pTDStretch); + } +} + + +// Flushes the last samples from the processing pipeline to the output. +// Clears also the internal processing buffers. +// +// Note: This function is meant for extracting the last samples of a sound +// stream. This function may introduce additional blank samples in the end +// of the sound stream, and thus it's not recommended to call this function +// in the middle of a sound stream. +void SoundTouch::flush() +{ + int i; + int numStillExpected; + SAMPLETYPE *buff = new SAMPLETYPE[128 * channels]; + + // how many samples are still expected to output + numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput); + if (numStillExpected < 0) numStillExpected = 0; + + memset(buff, 0, 128 * channels * sizeof(SAMPLETYPE)); + // "Push" the last active samples out from the processing pipeline by + // feeding blank samples into the processing pipeline until new, + // processed samples appear in the output (not however, more than + // 24ksamples in any case) + for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i ++) + { + putSamples(buff, 128); + } + + adjustAmountOfSamples(numStillExpected); + + delete[] buff; + + // Clear input buffers + pTDStretch->clearInput(); + // yet leave the output intouched as that's where the + // flushed samples are! +} + + +// Changes a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +bool SoundTouch::setSetting(int settingId, int value) +{ + int sampleRate, sequenceMs, seekWindowMs, overlapMs; + + // read current tdstretch routine parameters + pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs); + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + // enables / disabless anti-alias filter + pRateTransposer->enableAAFilter((value != 0) ? true : false); + return true; + + case SETTING_AA_FILTER_LENGTH : + // sets anti-alias filter length + pRateTransposer->getAAFilter()->setLength(value); + return true; + + case SETTING_USE_QUICKSEEK : + // enables / disables tempo routine quick seeking algorithm + pTDStretch->enableQuickSeek((value != 0) ? true : false); + return true; + + case SETTING_SEQUENCE_MS: + // change time-stretch sequence duration parameter + pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs); + return true; + + case SETTING_SEEKWINDOW_MS: + // change time-stretch seek window length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs); + return true; + + case SETTING_OVERLAP_MS: + // change time-stretch overlap length parameter + pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value); + return true; + + default : + return false; + } +} + + +// Reads a setting controlling the processing system behaviour. See the +// 'SETTING_...' defines for available setting ID's. +// +// Returns the setting value. +int SoundTouch::getSetting(int settingId) const +{ + int temp; + + switch (settingId) + { + case SETTING_USE_AA_FILTER : + return (uint)pRateTransposer->isAAFilterEnabled(); + + case SETTING_AA_FILTER_LENGTH : + return pRateTransposer->getAAFilter()->getLength(); + + case SETTING_USE_QUICKSEEK : + return (uint)pTDStretch->isQuickSeekEnabled(); + + case SETTING_SEQUENCE_MS: + pTDStretch->getParameters(NULL, &temp, NULL, NULL); + return temp; + + case SETTING_SEEKWINDOW_MS: + pTDStretch->getParameters(NULL, NULL, &temp, NULL); + return temp; + + case SETTING_OVERLAP_MS: + pTDStretch->getParameters(NULL, NULL, NULL, &temp); + return temp; + + case SETTING_NOMINAL_INPUT_SEQUENCE : + { + int size = pTDStretch->getInputSampleReq(); + +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + if (rate <= 1.0) + { + // transposing done before timestretch, which impacts latency + return (int)(size * rate + 0.5); + } +#endif + return size; + } + + case SETTING_NOMINAL_OUTPUT_SEQUENCE : + { + int size = pTDStretch->getOutputBatchSize(); + + if (rate > 1.0) + { + // transposing done after timestretch, which impacts latency + return (int)(size / rate + 0.5); + } + return size; + } + + case SETTING_INITIAL_LATENCY: + { + double latency = pTDStretch->getLatency(); + int latency_tr = pRateTransposer->getLatency(); + +#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER + if (rate <= 1.0) + { + // transposing done before timestretch, which impacts latency + latency = (latency + latency_tr) * rate; + } + else +#endif + { + latency += (double)latency_tr / rate; + } + + return (int)(latency + 0.5); + } + + default : + return 0; + } +} + + +// Clears all the samples in the object's output and internal processing +// buffers. +void SoundTouch::clear() +{ + samplesExpectedOut = 0; + samplesOutput = 0; + pRateTransposer->clear(); + pTDStretch->clear(); +} + + +/// Returns number of samples currently unprocessed. +uint SoundTouch::numUnprocessedSamples() const +{ + FIFOSamplePipe * psp; + if (pTDStretch) + { + psp = pTDStretch->getInput(); + if (psp) + { + return psp->numSamples(); + } + } + return 0; +} + + +/// Output samples from beginning of the sample buffer. Copies requested samples to +/// output buffer and removes them from the sample buffer. If there are less than +/// 'numsample' samples in the buffer, returns all that available. +/// +/// \return Number of samples returned. +uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples) +{ + uint ret = FIFOProcessor::receiveSamples(output, maxSamples); + samplesOutput += (long)ret; + return ret; +} + + +/// Adjusts book-keeping so that given number of samples are removed from beginning of the +/// sample buffer without copying them anywhere. +/// +/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly +/// with 'ptrBegin' function. +uint SoundTouch::receiveSamples(uint maxSamples) +{ + uint ret = FIFOProcessor::receiveSamples(maxSamples); + samplesOutput += (long)ret; + return ret; +} + + +/// Get ratio between input and output audio durations, useful for calculating +/// processed output duration: if you'll process a stream of N samples, then +/// you can expect to get out N * getInputOutputSampleRatio() samples. +double SoundTouch::getInputOutputSampleRatio() +{ + return 1.0 / (tempo * rate); +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/TDStretch.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/TDStretch.cpp new file mode 100644 index 00000000..c903a92f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/TDStretch.cpp @@ -0,0 +1,1106 @@ +/////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like +/// method with several performance-increasing tweaks. +/// +/// Notes : MMX optimized functions reside in a separate, platform-specific +/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'. +/// +/// This source file contains OpenMP optimizations that allow speeding up the +/// corss-correlation algorithm by executing it in several threads / CPU cores +/// in parallel. See the following article link for more detailed discussion +/// about SoundTouch OpenMP optimizations: +/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include <string.h> +#include <limits.h> +#include <assert.h> +#include <math.h> +#include <float.h> + +#include "STTypes.h" +#include "cpu_detect.h" +#include "TDStretch.h" + +using namespace soundtouch; + +#define max(x, y) (((x) > (y)) ? (x) : (y)) + +/***************************************************************************** + * + * Constant definitions + * + *****************************************************************************/ + +// Table for the hierarchical mixing position seeking algorithm +const short _scanOffsets[5][24]={ + { 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806, + 868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0}, + {-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 121, 114, 97, 114, 98, 105, 108, 32, 104, 99, 117, 111, + 116, 100, 110, 117, 111, 115, 0, 0, 0, 0, 0, 0}}; + +/***************************************************************************** + * + * Implementation of the class 'TDStretch' + * + *****************************************************************************/ + + +TDStretch::TDStretch() : FIFOProcessor(&outputBuffer) +{ + bQuickSeek = false; + channels = 2; + + pMidBuffer = NULL; + pMidBufferUnaligned = NULL; + overlapLength = 0; + + bAutoSeqSetting = true; + bAutoSeekSetting = true; + + tempo = 1.0f; + setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); + setTempo(1.0f); + + clear(); +} + + + +TDStretch::~TDStretch() +{ + delete[] pMidBufferUnaligned; +} + + + +// Sets routine control parameters. These control are certain time constants +// defining how the sound is stretched to the desired duration. +// +// 'sampleRate' = sample rate of the sound +// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms) +// 'seekwindowMS' = seeking window length for scanning the best overlapping +// position (default = 28 ms) +// 'overlapMS' = overlapping length (default = 12 ms) + +void TDStretch::setParameters(int aSampleRate, int aSequenceMS, + int aSeekWindowMS, int aOverlapMS) +{ + // accept only positive parameter values - if zero or negative, use old values instead + if (aSampleRate > 0) + { + if (aSampleRate > 192000) ST_THROW_RT_ERROR("Error: Excessive samplerate"); + this->sampleRate = aSampleRate; + } + + if (aOverlapMS > 0) this->overlapMs = aOverlapMS; + + if (aSequenceMS > 0) + { + this->sequenceMs = aSequenceMS; + bAutoSeqSetting = false; + } + else if (aSequenceMS == 0) + { + // if zero, use automatic setting + bAutoSeqSetting = true; + } + + if (aSeekWindowMS > 0) + { + this->seekWindowMs = aSeekWindowMS; + bAutoSeekSetting = false; + } + else if (aSeekWindowMS == 0) + { + // if zero, use automatic setting + bAutoSeekSetting = true; + } + + calcSeqParameters(); + + calculateOverlapLength(overlapMs); + + // set tempo to recalculate 'sampleReq' + setTempo(tempo); +} + + + +/// Get routine control parameters, see setParameters() function. +/// Any of the parameters to this function can be NULL, in such case corresponding parameter +/// value isn't returned. +void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const +{ + if (pSampleRate) + { + *pSampleRate = sampleRate; + } + + if (pSequenceMs) + { + *pSequenceMs = (bAutoSeqSetting) ? (USE_AUTO_SEQUENCE_LEN) : sequenceMs; + } + + if (pSeekWindowMs) + { + *pSeekWindowMs = (bAutoSeekSetting) ? (USE_AUTO_SEEKWINDOW_LEN) : seekWindowMs; + } + + if (pOverlapMs) + { + *pOverlapMs = overlapMs; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'pInput' +void TDStretch::overlapMono(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput) const +{ + int i; + SAMPLETYPE m1, m2; + + m1 = (SAMPLETYPE)0; + m2 = (SAMPLETYPE)overlapLength; + + for (i = 0; i < overlapLength ; i ++) + { + pOutput[i] = (pInput[i] * m1 + pMidBuffer[i] * m2 ) / overlapLength; + m1 += 1; + m2 -= 1; + } +} + + + +void TDStretch::clearMidBuffer() +{ + memset(pMidBuffer, 0, channels * sizeof(SAMPLETYPE) * overlapLength); +} + + +void TDStretch::clearInput() +{ + inputBuffer.clear(); + clearMidBuffer(); + isBeginning = true; + maxnorm = 0; + maxnormf = 1e8; + skipFract = 0; +} + + +// Clears the sample buffers +void TDStretch::clear() +{ + outputBuffer.clear(); + clearInput(); +} + + + +// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero +// to enable +void TDStretch::enableQuickSeek(bool enable) +{ + bQuickSeek = enable; +} + + +// Returns nonzero if the quick seeking algorithm is enabled. +bool TDStretch::isQuickSeekEnabled() const +{ + return bQuickSeek; +} + + +// Seeks for the optimal overlap-mixing position. +int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos) +{ + if (bQuickSeek) + { + return seekBestOverlapPositionQuick(refPos); + } + else + { + return seekBestOverlapPositionFull(refPos); + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'pInputBuffer' at position +// of 'ovlPos'. +inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, uint ovlPos) const +{ +#ifndef USE_MULTICH_ALWAYS + if (channels == 1) + { + // mono sound. + overlapMono(pOutput, pInput + ovlPos); + } + else if (channels == 2) + { + // stereo sound + overlapStereo(pOutput, pInput + 2 * ovlPos); + } + else +#endif // USE_MULTICH_ALWAYS + { + assert(channels > 0); + overlapMulti(pOutput, pInput + channels * ovlPos); + } +} + + +// Seeks for the optimal overlap-mixing position. The 'stereo' version of the +// routine +// +// The best position is determined as the position where the two overlapped +// sample sequences are 'most alike', in terms of the highest cross-correlation +// value over the overlapping period +int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) +{ + int bestOffs; + double bestCorr; + int i; + double norm; + + bestCorr = -FLT_MAX; + bestOffs = 0; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. + bestCorr = calcCrossCorr(refPos, pMidBuffer, norm); + bestCorr = (bestCorr + 0.1) * 0.75; + + #pragma omp parallel for + for (i = 1; i < seekLength; i ++) + { + double corr; + // Calculates correlation value for the mixing position corresponding to 'i' +#if defined(_OPENMP) || defined(ST_SIMD_AVOID_UNALIGNED) + // in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't + // iterate the loop in sequential order + // in SIMD mode, avoid accumulator version to allow avoiding unaligned positions + corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm); +#else + // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same + // as "calcCrossCorr", but saves time by reusing & updating previously stored + // "norm" value + corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm); +#endif + // heuristic rule to slightly favour values close to mid of the range + double tmp = (double)(2 * i - seekLength) / (double)seekLength; + corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp)); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + // For optimal performance, enter critical section only in case that best value found. + // in such case repeat 'if' condition as it's possible that parallel execution may have + // updated the bestCorr value in the mean time + #pragma omp critical + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + } + +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + adaptNormalizer(); +#endif + + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + + return bestOffs; +} + + +// Quick seek algorithm for improved runtime-performance: First roughly scans through the +// correlation area, and then scan surroundings of two best preliminary correlation candidates +// with improved precision +// +// Based on testing: +// - This algorithm gives on average 99% as good match as the full algorithm +// - this quick seek algorithm finds the best match on ~90% of cases +// - on those 10% of cases when this algorithm doesn't find best match, +// it still finds on average ~90% match vs. the best possible match +int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos) +{ +#define _MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define SCANSTEP 16 +#define SCANWIND 8 + + int bestOffs; + int i; + int bestOffs2; + float bestCorr, corr; + float bestCorr2; + double norm; + + // note: 'float' types used in this function in case that the platform would need to use software-fp + + bestCorr = + bestCorr2 = -FLT_MAX; + bestOffs = + bestOffs2 = SCANWIND; + + // Scans for the best correlation value by testing each possible position + // over the permitted range. Look for two best matches on the first pass to + // increase possibility of ideal match. + // + // Begin from "SCANSTEP" instead of SCANWIND to make the calculation + // catch the 'middlepoint' of seekLength vector as that's the a-priori + // expected best match position + // + // Roughly: + // - 15% of cases find best result directly on the first round, + // - 75% cases find better match on 2nd round around the best match from 1st round + // - 10% cases find better match on 2nd round around the 2nd-best-match from 1st round + for (i = SCANSTEP; i < seekLength - SCANWIND - 1; i += SCANSTEP) + { + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm); + // heuristic rule to slightly favour values close to mid of the seek range + float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength; + corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp)); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + // found new best match. keep the previous best as 2nd best match + bestCorr2 = bestCorr; + bestOffs2 = bestOffs; + bestCorr = corr; + bestOffs = i; + } + else if (corr > bestCorr2) + { + // not new best, but still new 2nd best match + bestCorr2 = corr; + bestOffs2 = i; + } + } + + // Scans surroundings of the found best match with small stepping + int end = _MIN(bestOffs + SCANWIND + 1, seekLength); + for (i = bestOffs - SCANWIND; i < end; i++) + { + if (i == bestOffs) continue; // this offset already calculated, thus skip + + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm); + // heuristic rule to slightly favour values close to mid of the range + float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength; + corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp)); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + + // Scans surroundings of the 2nd best match with small stepping + end = _MIN(bestOffs2 + SCANWIND + 1, seekLength); + for (i = bestOffs2 - SCANWIND; i < end; i++) + { + if (i == bestOffs2) continue; // this offset already calculated, thus skip + + // Calculates correlation value for the mixing position corresponding + // to 'i' + corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm); + // heuristic rule to slightly favour values close to mid of the range + float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength; + corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp)); + + // Checks for the highest correlation value + if (corr > bestCorr) + { + bestCorr = corr; + bestOffs = i; + } + } + + // clear cross correlation routine state if necessary (is so e.g. in MMX routines). + clearCrossCorrState(); + +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + adaptNormalizer(); +#endif + + return bestOffs; +} + + + + +/// For integer algorithm: adapt normalization factor divider with music so that +/// it'll not be pessimistically restrictive that can degrade quality on quieter sections +/// yet won't cause integer overflows either +void TDStretch::adaptNormalizer() +{ + // Do not adapt normalizer over too silent sequences to avoid averaging filter depleting to + // too low values during pauses in music + if ((maxnorm > 1000) || (maxnormf > 40000000)) + { + //norm averaging filter + maxnormf = 0.9f * maxnormf + 0.1f * (float)maxnorm; + + if ((maxnorm > 800000000) && (overlapDividerBitsNorm < 16)) + { + // large values, so increase divider + overlapDividerBitsNorm++; + if (maxnorm > 1600000000) overlapDividerBitsNorm++; // extra large value => extra increase + } + else if ((maxnormf < 1000000) && (overlapDividerBitsNorm > 0)) + { + // extra small values, decrease divider + overlapDividerBitsNorm--; + } + } + + maxnorm = 0; +} + + +/// clear cross correlation routine state if necessary +void TDStretch::clearCrossCorrState() +{ + // default implementation is empty. +} + + +/// Calculates processing sequence length according to tempo setting +void TDStretch::calcSeqParameters() +{ + // Adjust tempo param according to tempo, so that variating processing sequence length is used + // at various tempo settings, between the given low...top limits + #define AUTOSEQ_TEMPO_LOW 0.5 // auto setting low tempo range (-50%) + #define AUTOSEQ_TEMPO_TOP 2.0 // auto setting top tempo range (+100%) + + // sequence-ms setting values at above low & top tempo + #define AUTOSEQ_AT_MIN 90.0 + #define AUTOSEQ_AT_MAX 40.0 + #define AUTOSEQ_K ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) + #define AUTOSEQ_C (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW)) + + // seek-window-ms setting values at above low & top tempoq + #define AUTOSEEK_AT_MIN 20.0 + #define AUTOSEEK_AT_MAX 15.0 + #define AUTOSEEK_K ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW)) + #define AUTOSEEK_C (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW)) + + #define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x))) + + double seq, seek; + + if (bAutoSeqSetting) + { + seq = AUTOSEQ_C + AUTOSEQ_K * tempo; + seq = CHECK_LIMITS(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN); + sequenceMs = (int)(seq + 0.5); + } + + if (bAutoSeekSetting) + { + seek = AUTOSEEK_C + AUTOSEEK_K * tempo; + seek = CHECK_LIMITS(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN); + seekWindowMs = (int)(seek + 0.5); + } + + // Update seek window lengths + seekWindowLength = (sampleRate * sequenceMs) / 1000; + if (seekWindowLength < 2 * overlapLength) + { + seekWindowLength = 2 * overlapLength; + } + seekLength = (sampleRate * seekWindowMs) / 1000; +} + + + +// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower +// tempo, larger faster tempo. +void TDStretch::setTempo(double newTempo) +{ + int intskip; + + tempo = newTempo; + + // Calculate new sequence duration + calcSeqParameters(); + + // Calculate ideal skip length (according to tempo value) + nominalSkip = tempo * (seekWindowLength - overlapLength); + intskip = (int)(nominalSkip + 0.5); + + // Calculate how many samples are needed in the 'inputBuffer' to + // process another batch of samples + //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2; + sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength; +} + + + +// Sets the number of channels, 1 = mono, 2 = stereo +void TDStretch::setChannels(int numChannels) +{ + if (!verifyNumberOfChannels(numChannels) || + (channels == numChannels)) return; + + channels = numChannels; + inputBuffer.setChannels(channels); + outputBuffer.setChannels(channels); + + // re-init overlap/buffer + overlapLength=0; + setParameters(sampleRate); +} + + +// nominal tempo, no need for processing, just pass the samples through +// to outputBuffer +/* +void TDStretch::processNominalTempo() +{ + assert(tempo == 1.0f); + + if (bMidBufferDirty) + { + // If there are samples in pMidBuffer waiting for overlapping, + // do a single sliding overlapping with them in order to prevent a + // clicking distortion in the output sound + if (inputBuffer.numSamples() < overlapLength) + { + // wait until we've got overlapLength input samples + return; + } + // Mix the samples in the beginning of 'inputBuffer' with the + // samples in 'midBuffer' using sliding overlapping + overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0); + outputBuffer.putSamples(overlapLength); + inputBuffer.receiveSamples(overlapLength); + clearMidBuffer(); + // now we've caught the nominal sample flow and may switch to + // bypass mode + } + + // Simply bypass samples from input to output + outputBuffer.moveSamples(inputBuffer); +} +*/ + + +// Processes as many processing frames of the samples 'inputBuffer', store +// the result into 'outputBuffer' +void TDStretch::processSamples() +{ + int ovlSkip; + int offset = 0; + int temp; + + /* Removed this small optimization - can introduce a click to sound when tempo setting + crosses the nominal value + if (tempo == 1.0f) + { + // tempo not changed from the original, so bypass the processing + processNominalTempo(); + return; + } + */ + + // Process samples as long as there are enough samples in 'inputBuffer' + // to form a processing frame. + while ((int)inputBuffer.numSamples() >= sampleReq) + { + if (isBeginning == false) + { + // apart from the very beginning of the track, + // scan for the best overlapping position & do overlap-add + offset = seekBestOverlapPosition(inputBuffer.ptrBegin()); + + // Mix the samples in the 'inputBuffer' at position of 'offset' with the + // samples in 'midBuffer' using sliding overlapping + // ... first partially overlap with the end of the previous sequence + // (that's in 'midBuffer') + overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset); + outputBuffer.putSamples((uint)overlapLength); + offset += overlapLength; + } + else + { + // Adjust processing offset at beginning of track by not perform initial overlapping + // and compensating that in the 'input buffer skip' calculation + isBeginning = false; + int skip = (int)(tempo * overlapLength + 0.5 * seekLength + 0.5); + + #ifdef ST_SIMD_AVOID_UNALIGNED + // in SIMD mode, round the skip amount to value corresponding to aligned memory address + if (channels == 1) + { + skip &= -4; + } + else if (channels == 2) + { + skip &= -2; + } + #endif + skipFract -= skip; + if (skipFract <= -nominalSkip) + { + skipFract = -nominalSkip; + } + } + + // ... then copy sequence samples from 'inputBuffer' to output: + + // crosscheck that we don't have buffer overflow... + if ((int)inputBuffer.numSamples() < (offset + seekWindowLength - overlapLength)) + { + continue; // just in case, shouldn't really happen + } + + // length of sequence + temp = (seekWindowLength - 2 * overlapLength); + outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * offset, (uint)temp); + + // Copies the end of the current sequence from 'inputBuffer' to + // 'midBuffer' for being mixed with the beginning of the next + // processing sequence and so on + assert((offset + temp + overlapLength) <= (int)inputBuffer.numSamples()); + memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp), + channels * sizeof(SAMPLETYPE) * overlapLength); + + // Remove the processed samples from the input buffer. Update + // the difference between integer & nominal skip step to 'skipFract' + // in order to prevent the error from accumulating over time. + skipFract += nominalSkip; // real skip size + ovlSkip = (int)skipFract; // rounded to integer skip + skipFract -= ovlSkip; // maintain the fraction part, i.e. real vs. integer skip + inputBuffer.receiveSamples((uint)ovlSkip); + } +} + + +// Adds 'numsamples' pcs of samples from the 'samples' memory position into +// the input of the object. +void TDStretch::putSamples(const SAMPLETYPE *samples, uint nSamples) +{ + // Add the samples into the input buffer + inputBuffer.putSamples(samples, nSamples); + // Process the samples in input buffer + processSamples(); +} + + + +/// Set new overlap length parameter & reallocate RefMidBuffer if necessary. +void TDStretch::acceptNewOverlapLength(int newOverlapLength) +{ + int prevOvl; + + assert(newOverlapLength >= 0); + prevOvl = overlapLength; + overlapLength = newOverlapLength; + + if (overlapLength > prevOvl) + { + delete[] pMidBufferUnaligned; + + pMidBufferUnaligned = new SAMPLETYPE[overlapLength * channels + 16 / sizeof(SAMPLETYPE)]; + // ensure that 'pMidBuffer' is aligned to 16 byte boundary for efficiency + pMidBuffer = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(pMidBufferUnaligned); + + clearMidBuffer(); + } +} + + +// Operator 'new' is overloaded so that it automatically creates a suitable instance +// depending on if we've a MMX/SSE/etc-capable CPU available or not. +void * TDStretch::operator new(size_t s) +{ + // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! + ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"); + return newInstance(); +} + + +TDStretch * TDStretch::newInstance() +{ + uint uExtensions; + + uExtensions = detectCPUextensions(); + + // Check if MMX/SSE instruction set extensions supported by CPU + +#ifdef SOUNDTOUCH_ALLOW_MMX + // MMX routines available only with integer sample types + if (uExtensions & SUPPORT_MMX) + { + return ::new TDStretchMMX; + } + else +#endif // SOUNDTOUCH_ALLOW_MMX + + +#ifdef SOUNDTOUCH_ALLOW_SSE + if (uExtensions & SUPPORT_SSE) + { + // SSE support + return ::new TDStretchSSE; + } + else +#endif // SOUNDTOUCH_ALLOW_SSE + + { + // ISA optimizations not supported, use plain C version + return ::new TDStretch; + } +} + + +////////////////////////////////////////////////////////////////////////////// +// +// Integer arithmetic specific algorithm implementations. +// +////////////////////////////////////////////////////////////////////////////// + +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' +// version of the routine. +void TDStretch::overlapStereo(short *poutput, const short *input) const +{ + int i; + short temp; + int cnt2; + + for (i = 0; i < overlapLength ; i ++) + { + temp = (short)(overlapLength - i); + cnt2 = 2 * i; + poutput[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp ) / overlapLength; + poutput[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Multi' +// version of the routine. +void TDStretch::overlapMulti(short *poutput, const short *input) const +{ + short m1; + int i = 0; + + for (m1 = 0; m1 < overlapLength; m1 ++) + { + short m2 = (short)(overlapLength - m1); + for (int c = 0; c < channels; c ++) + { + poutput[i] = (input[i] * m1 + pMidBuffer[i] * m2) / overlapLength; + i++; + } + } +} + +// Calculates the x having the closest 2^x value for the given value +static int _getClosest2Power(double value) +{ + return (int)(log(value) / log(2.0) + 0.5); +} + + +/// Calculates overlap period length in samples. +/// Integer version rounds overlap length to closest power of 2 +/// for a divide scaling operation. +void TDStretch::calculateOverlapLength(int aoverlapMs) +{ + int newOvl; + + assert(aoverlapMs >= 0); + + // calculate overlap length so that it's power of 2 - thus it's easy to do + // integer division by right-shifting. Term "-1" at end is to account for + // the extra most significatnt bit left unused in result by signed multiplication + overlapDividerBitsPure = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1; + if (overlapDividerBitsPure > 9) overlapDividerBitsPure = 9; + if (overlapDividerBitsPure < 3) overlapDividerBitsPure = 3; + newOvl = (int)pow(2.0, (int)overlapDividerBitsPure + 1); // +1 => account for -1 above + + acceptNewOverlapLength(newOvl); + + overlapDividerBitsNorm = overlapDividerBitsPure; + + // calculate sloping divider so that crosscorrelation operation won't + // overflow 32-bit register. Max. sum of the crosscorrelation sum without + // divider would be 2^30*(N^3-N)/3, where N = overlap length + slopingDivider = (newOvl * newOvl - 1) / 3; +} + + +double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, double &norm) +{ + long corr; + unsigned long lnorm; + int i; + + #ifdef ST_SIMD_AVOID_UNALIGNED + // in SIMD mode skip 'mixingPos' positions that aren't aligned to 16-byte boundary + if (((ulongptr)mixingPos) & 15) return -1e50; + #endif + + // hint compiler autovectorization that loop length is divisible by 8 + int ilength = (channels * overlapLength) & -8; + + corr = lnorm = 0; + // Same routine for stereo and mono + for (i = 0; i < ilength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; + lnorm += (mixingPos[i] * mixingPos[i] + + mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm; + // do intermediate scalings to avoid integer overflow + } + + if (lnorm > maxnorm) + { + // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode + #pragma omp critical + if (lnorm > maxnorm) + { + maxnorm = lnorm; + } + } + // Normalize result by dividing by sqrt(norm) - this step is easiest + // done using floating point operation + norm = (double)lnorm; + return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); +} + + +/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value +double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) +{ + long corr; + long lnorm; + int i; + + // hint compiler autovectorization that loop length is divisible by 8 + int ilength = (channels * overlapLength) & -8; + + // cancel first normalizer tap from previous round + lnorm = 0; + for (i = 1; i <= channels; i ++) + { + lnorm -= (mixingPos[-i] * mixingPos[-i]) >> overlapDividerBitsNorm; + } + + corr = 0; + // Same routine for stereo and mono. + for (i = 0; i < ilength; i += 2) + { + corr += (mixingPos[i] * compare[i] + + mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; + } + + // update normalizer with last samples of this round + for (int j = 0; j < channels; j ++) + { + i --; + lnorm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBitsNorm; + } + + norm += (double)lnorm; + if (norm > maxnorm) + { + maxnorm = (unsigned long)norm; + } + + // Normalize result by dividing by sqrt(norm) - this step is easiest + // done using floating point operation + return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm); +} + +#endif // SOUNDTOUCH_INTEGER_SAMPLES + +////////////////////////////////////////////////////////////////////////////// +// +// Floating point arithmetic specific algorithm implementations. +// + +#ifdef SOUNDTOUCH_FLOAT_SAMPLES + +// Overlaps samples in 'midBuffer' with the samples in 'pInput' +void TDStretch::overlapStereo(float *pOutput, const float *pInput) const +{ + int i; + float fScale; + float f1; + float f2; + + fScale = 1.0f / (float)overlapLength; + + f1 = 0; + f2 = 1.0f; + + for (i = 0; i < 2 * (int)overlapLength ; i += 2) + { + pOutput[i + 0] = pInput[i + 0] * f1 + pMidBuffer[i + 0] * f2; + pOutput[i + 1] = pInput[i + 1] * f1 + pMidBuffer[i + 1] * f2; + + f1 += fScale; + f2 -= fScale; + } +} + + +// Overlaps samples in 'midBuffer' with the samples in 'input'. +void TDStretch::overlapMulti(float *pOutput, const float *pInput) const +{ + int i; + float fScale; + float f1; + float f2; + + fScale = 1.0f / (float)overlapLength; + + f1 = 0; + f2 = 1.0f; + + i=0; + for (int i2 = 0; i2 < overlapLength; i2 ++) + { + // note: Could optimize this slightly by taking into account that always channels > 2 + for (int c = 0; c < channels; c ++) + { + pOutput[i] = pInput[i] * f1 + pMidBuffer[i] * f2; + i++; + } + f1 += fScale; + f2 -= fScale; + } +} + + +/// Calculates overlapInMsec period length in samples. +void TDStretch::calculateOverlapLength(int overlapInMsec) +{ + int newOvl; + + assert(overlapInMsec >= 0); + newOvl = (sampleRate * overlapInMsec) / 1000; + if (newOvl < 16) newOvl = 16; + + // must be divisible by 8 + newOvl -= newOvl % 8; + + acceptNewOverlapLength(newOvl); +} + + +/// Calculate cross-correlation +double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, double &anorm) +{ + float corr; + float norm; + int i; + + #ifdef ST_SIMD_AVOID_UNALIGNED + // in SIMD mode skip 'mixingPos' positions that aren't aligned to 16-byte boundary + if (((ulongptr)mixingPos) & 15) return -1e50; + #endif + + // hint compiler autovectorization that loop length is divisible by 8 + int ilength = (channels * overlapLength) & -8; + + corr = norm = 0; + // Same routine for stereo and mono + for (i = 0; i < ilength; i ++) + { + corr += mixingPos[i] * compare[i]; + norm += mixingPos[i] * mixingPos[i]; + } + + anorm = norm; + return corr / sqrt((norm < 1e-9 ? 1.0 : norm)); +} + + +/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value +double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) +{ + float corr; + int i; + + corr = 0; + + // cancel first normalizer tap from previous round + for (i = 1; i <= channels; i ++) + { + norm -= mixingPos[-i] * mixingPos[-i]; + } + + // hint compiler autovectorization that loop length is divisible by 8 + int ilength = (channels * overlapLength) & -8; + + // Same routine for stereo and mono + for (i = 0; i < ilength; i ++) + { + corr += mixingPos[i] * compare[i]; + } + + // update normalizer with last samples of this round + for (int j = 0; j < channels; j ++) + { + i --; + norm += mixingPos[i] * mixingPos[i]; + } + + return corr / sqrt((norm < 1e-9 ? 1.0 : norm)); +} + + +#endif // SOUNDTOUCH_FLOAT_SAMPLES diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/TDStretch.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/TDStretch.h new file mode 100644 index 00000000..3ef79c7c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/TDStretch.h @@ -0,0 +1,279 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo +/// while maintaining the original pitch by using a time domain WSOLA-like method +/// with several performance-increasing tweaks. +/// +/// Note : MMX/SSE optimized functions reside in separate, platform-specific files +/// 'mmx_optimized.cpp' and 'sse_optimized.cpp' +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TDStretch_H +#define TDStretch_H + +#include <stddef.h> +#include "STTypes.h" +#include "RateTransposer.h" +#include "FIFOSamplePipe.h" + +namespace soundtouch +{ + +/// Default values for sound processing parameters: +/// Notice that the default parameters are tuned for contemporary popular music +/// processing. For speech processing applications these parameters suit better: +/// #define DEFAULT_SEQUENCE_MS 40 +/// #define DEFAULT_SEEKWINDOW_MS 15 +/// #define DEFAULT_OVERLAP_MS 8 +/// + +/// Default length of a single processing sequence, in milliseconds. This determines to how +/// long sequences the original sound is chopped in the time-stretch algorithm. +/// +/// The larger this value is, the lesser sequences are used in processing. In principle +/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo +/// and vice versa. +/// +/// Increasing this value reduces computational burden & vice versa. +//#define DEFAULT_SEQUENCE_MS 40 +#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN + +/// Giving this value for the sequence length sets automatic parameter value +/// according to tempo setting (recommended) +#define USE_AUTO_SEQUENCE_LEN 0 + +/// Seeking window default length in milliseconds for algorithm that finds the best possible +/// overlapping location. This determines from how wide window the algorithm may look for an +/// optimal joining location when mixing the sound sequences back together. +/// +/// The bigger this window setting is, the higher the possibility to find a better mixing +/// position will become, but at the same time large values may cause a "drifting" artifact +/// because consequent sequences will be taken at more uneven intervals. +/// +/// If there's a disturbing artifact that sounds as if a constant frequency was drifting +/// around, try reducing this setting. +/// +/// Increasing this value increases computational burden & vice versa. +//#define DEFAULT_SEEKWINDOW_MS 15 +#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN + +/// Giving this value for the seek window length sets automatic parameter value +/// according to tempo setting (recommended) +#define USE_AUTO_SEEKWINDOW_LEN 0 + +/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, +/// to form a continuous sound stream, this parameter defines over how long period the two +/// consecutive sequences are let to overlap each other. +/// +/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting +/// by a large amount, you might wish to try a smaller value on this. +/// +/// Increasing this value increases computational burden & vice versa. +#define DEFAULT_OVERLAP_MS 8 + + +/// Class that does the time-stretch (tempo change) effect for the processed +/// sound. +class TDStretch : public FIFOProcessor +{ +protected: + int channels; + int sampleReq; + + int overlapLength; + int seekLength; + int seekWindowLength; + int overlapDividerBitsNorm; + int overlapDividerBitsPure; + int slopingDivider; + int sampleRate; + int sequenceMs; + int seekWindowMs; + int overlapMs; + + unsigned long maxnorm; + float maxnormf; + + double tempo; + double nominalSkip; + double skipFract; + + bool bQuickSeek; + bool bAutoSeqSetting; + bool bAutoSeekSetting; + bool isBeginning; + + SAMPLETYPE *pMidBuffer; + SAMPLETYPE *pMidBufferUnaligned; + + FIFOSampleBuffer outputBuffer; + FIFOSampleBuffer inputBuffer; + + void acceptNewOverlapLength(int newOverlapLength); + + virtual void clearCrossCorrState(); + void calculateOverlapLength(int overlapMs); + + virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm); + virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm); + + virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos); + virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos); + virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos); + + virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const; + virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const; + + void clearMidBuffer(); + void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const; + + void calcSeqParameters(); + void adaptNormalizer(); + + /// Changes the tempo of the given sound samples. + /// Returns amount of samples returned in the "output" buffer. + /// The maximum amount of samples that can be returned at a time is set by + /// the 'set_returnBuffer_size' function. + void processSamples(); + +public: + TDStretch(); + virtual ~TDStretch(); + + /// Operator 'new' is overloaded so that it automatically creates a suitable instance + /// depending on if we've a MMX/SSE/etc-capable CPU available or not. + 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 feature set depending on if the CPU + /// supports MMX/SSE/etc extensions. + static TDStretch *newInstance(); + + /// Returns the output buffer object + FIFOSamplePipe *getOutput() { return &outputBuffer; }; + + /// Returns the input buffer object + FIFOSamplePipe *getInput() { return &inputBuffer; }; + + /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower + /// tempo, larger faster tempo. + void setTempo(double newTempo); + + /// Returns nonzero if there aren't any samples available for outputting. + virtual void clear(); + + /// Clears the input buffer + void clearInput(); + + /// Sets the number of channels, 1 = mono, 2 = stereo + void setChannels(int numChannels); + + /// Enables/disables the quick position seeking algorithm. Zero to disable, + /// nonzero to enable + void enableQuickSeek(bool enable); + + /// Returns nonzero if the quick seeking algorithm is enabled. + bool isQuickSeekEnabled() const; + + /// Sets routine control parameters. These control are certain time constants + /// defining how the sound is stretched to the desired duration. + // + /// 'sampleRate' = sample rate of the sound + /// 'sequenceMS' = one processing sequence length in milliseconds + /// 'seekwindowMS' = seeking window length for scanning the best overlapping + /// position + /// 'overlapMS' = overlapping length + void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz) + int sequenceMS = -1, ///< Single processing sequence length (ms) + int seekwindowMS = -1, ///< Offset seeking window length (ms) + int overlapMS = -1 ///< Sequence overlapping length (ms) + ); + + /// Get routine control parameters, see setParameters() function. + /// Any of the parameters to this function can be NULL, in such case corresponding parameter + /// value isn't returned. + void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const; + + /// Adds 'numsamples' pcs of samples from the 'samples' memory position into + /// the input of the object. + virtual void putSamples( + const SAMPLETYPE *samples, ///< Input sample data + uint numSamples ///< Number of samples in 'samples' so that one sample + ///< contains both channels if stereo + ); + + /// return nominal input sample requirement for triggering a processing batch + int getInputSampleReq() const + { + return (int)(nominalSkip + 0.5); + } + + /// return nominal output sample amount when running a processing batch + int getOutputBatchSize() const + { + return seekWindowLength - overlapLength; + } + + /// return approximate initial input-output latency + int getLatency() const + { + return sampleReq; + } +}; + + +// Implementation-specific class declarations: + +#ifdef SOUNDTOUCH_ALLOW_MMX + /// Class that implements MMX optimized routines for 16bit integer samples type. + class TDStretchMMX : public TDStretch + { + protected: + double calcCrossCorr(const short *mixingPos, const short *compare, double &norm); + double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm); + virtual void overlapStereo(short *output, const short *input) const; + virtual void clearCrossCorrState(); + }; +#endif /// SOUNDTOUCH_ALLOW_MMX + + +#ifdef SOUNDTOUCH_ALLOW_SSE + /// Class that implements SSE optimized routines for floating point samples type. + class TDStretchSSE : public TDStretch + { + protected: + double calcCrossCorr(const float *mixingPos, const float *compare, double &norm); + double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm); + }; + +#endif /// SOUNDTOUCH_ALLOW_SSE + +} +#endif /// TDStretch_H diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/cpu_detect.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/cpu_detect.h new file mode 100644 index 00000000..093b6097 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/cpu_detect.h @@ -0,0 +1,55 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// A header file for detecting the Intel MMX instructions set extension. +/// +/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the +/// routine implementations for x86 Windows, x86 gnu version and non-x86 +/// platforms, respectively. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _CPU_DETECT_H_ +#define _CPU_DETECT_H_ + +#include "STTypes.h" + +#define SUPPORT_MMX 0x0001 +#define SUPPORT_3DNOW 0x0002 +#define SUPPORT_ALTIVEC 0x0004 +#define SUPPORT_SSE 0x0008 +#define SUPPORT_SSE2 0x0010 + +/// Checks which instruction set extensions are supported by the CPU. +/// +/// \return A bitmask of supported extensions, see SUPPORT_... defines. +uint detectCPUextensions(void); + +/// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint wDisableMask); + +#endif // _CPU_DETECT_H_ diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/cpu_detect_x86.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/cpu_detect_x86.cpp new file mode 100644 index 00000000..06c60782 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/cpu_detect_x86.cpp @@ -0,0 +1,130 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Generic version of the x86 CPU extension detection routine. +/// +/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' +/// for the Microsoft compiler version. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + + +#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) + + #if defined(__GNUC__) && defined(__i386__) + // gcc + #include "cpuid.h" + #elif defined(_M_IX86) + // windows non-gcc + #include <intrin.h> + #endif + + #define bit_MMX (1 << 23) + #define bit_SSE (1 << 25) + #define bit_SSE2 (1 << 26) +#endif + + +////////////////////////////////////////////////////////////////////////////// +// +// processor instructions extension detection routines +// +////////////////////////////////////////////////////////////////////////////// + +// Flag variable indicating whick ISA extensions are disabled (for debugging) +static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions + +// Disables given set of instruction extensions. See SUPPORT_... defines. +void disableExtensions(uint dwDisableMask) +{ + _dwDisabledISA = dwDisableMask; +} + + +/// Checks which instruction set extensions are supported by the CPU. +uint detectCPUextensions(void) +{ +/// If building for a 64bit system (no Itanium) and the user wants optimizations. +/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19. +/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). +#if ((defined(__GNUC__) && defined(__x86_64__)) \ + || defined(_M_X64)) \ + && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) + return 0x19 & ~_dwDisabledISA; + +/// If building for a 32bit system and the user wants optimizations. +/// Keep the _dwDisabledISA test (2 more operations, could be eliminated). +#elif ((defined(__GNUC__) && defined(__i386__)) \ + || defined(_M_IX86)) \ + && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS) + + if (_dwDisabledISA == 0xffffffff) return 0; + + uint res = 0; + +#if defined(__GNUC__) + // GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support. + uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable. + + // Check if no cpuid support. + if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions. + + if (edx & bit_MMX) res = res | SUPPORT_MMX; + if (edx & bit_SSE) res = res | SUPPORT_SSE; + if (edx & bit_SSE2) res = res | SUPPORT_SSE2; + +#else + // Window / VS version of cpuid. Notice that Visual Studio 2005 or later required + // for __cpuid intrinsic support. + int reg[4] = {-1}; + + // Check if no cpuid support. + __cpuid(reg,0); + if ((unsigned int)reg[0] == 0) return 0; // always disable extensions. + + __cpuid(reg,1); + if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX; + if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE; + if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2; + +#endif + + return res & ~_dwDisabledISA; + +#else + +/// One of these is true: +/// 1) We don't want optimizations. +/// 2) Using an unsupported compiler. +/// 3) Running on a non-x86 platform. + return 0; + +#endif +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/mmx_optimized.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/mmx_optimized.cpp new file mode 100644 index 00000000..0bc7fe86 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/mmx_optimized.cpp @@ -0,0 +1,396 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// MMX optimized routines. All MMX optimized functions have been gathered into +/// this single source code file, regardless to their class or original source +/// code file, in order to ease porting the library to other compiler and +/// processor platforms. +/// +/// The MMX-optimizations are programmed using MMX compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support compiler intrinsic syntax. The update +/// is available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "STTypes.h" + +#ifdef SOUNDTOUCH_ALLOW_MMX +// MMX routines available only with integer sample type + +using namespace soundtouch; + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'TDStretchMMX' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include <mmintrin.h> +#include <limits.h> +#include <math.h> + + +// Calculates cross correlation of two buffers +double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm) +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu, normaccu; + long corr, norm; + int i; + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBitsNorm); + normaccu = accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples + // during each round for improved CPU-level parallellization. + for (i = 0; i < channels * overlapLength / 16; i ++) + { + __m64 temp, temp2; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter)); + temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec1[1]), shifter)); + accu = _mm_add_pi32(accu, temp); + normaccu = _mm_add_pi32(normaccu, temp2); + + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter)); + temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec1[3]), shifter)); + accu = _mm_add_pi32(accu, temp); + normaccu = _mm_add_pi32(normaccu, temp2); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32)); + norm = _m_to_int(normaccu); + + // Clear MMS state + _m_empty(); + + if (norm > (long)maxnorm) + { + // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode + #pragma omp critical + if (norm > (long)maxnorm) + { + maxnorm = norm; + } + } + + // Normalize result by dividing by sqrt(norm) - this step is easiest + // done using floating point operation + dnorm = (double)norm; + + return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm); + // Note: Warning about the missing EMMS instruction is harmless + // as it'll be called elsewhere. +} + + +/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value +double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm) +{ + const __m64 *pVec1, *pVec2; + __m64 shifter; + __m64 accu; + long corr, lnorm; + int i; + + // cancel first normalizer tap from previous round + lnorm = 0; + for (i = 1; i <= channels; i ++) + { + lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBitsNorm; + } + + pVec1 = (__m64*)pV1; + pVec2 = (__m64*)pV2; + + shifter = _m_from_int(overlapDividerBitsNorm); + accu = _mm_setzero_si64(); + + // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples + // during each round for improved CPU-level parallellization. + for (i = 0; i < channels * overlapLength / 16; i ++) + { + __m64 temp; + + // dictionary of instructions: + // _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3] + // _mm_add_pi32 : 2*32bit add + // _m_psrad : 32bit right-shift + + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter)); + accu = _mm_add_pi32(accu, temp); + + temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter), + _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter)); + accu = _mm_add_pi32(accu, temp); + + pVec1 += 4; + pVec2 += 4; + } + + // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1 + // and finally store the result into the variable "corr" + + accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32)); + corr = _m_to_int(accu); + + // Clear MMS state + _m_empty(); + + // update normalizer with last samples of this round + pV1 = (short *)pVec1; + for (int j = 1; j <= channels; j ++) + { + lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBitsNorm; + } + dnorm += (double)lnorm; + + if (lnorm > (long)maxnorm) + { + maxnorm = lnorm; + } + + // Normalize result by dividing by sqrt(norm) - this step is easiest + // done using floating point operation + return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm); +} + + +void TDStretchMMX::clearCrossCorrState() +{ + // Clear MMS state + _m_empty(); + //_asm EMMS; +} + + +// MMX-optimized version of the function overlapStereo +void TDStretchMMX::overlapStereo(short *output, const short *input) const +{ + const __m64 *pVinput, *pVMidBuf; + __m64 *pVdest; + __m64 mix1, mix2, adder, shifter; + int i; + + pVinput = (const __m64*)input; + pVMidBuf = (const __m64*)pMidBuffer; + pVdest = (__m64*)output; + + // mix1 = mixer values for 1st stereo sample + // mix1 = mixer values for 2nd stereo sample + // adder = adder for updating mixer values after each round + + mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength); + adder = _mm_set_pi16(1, -1, 1, -1); + mix2 = _mm_add_pi16(mix1, adder); + adder = _mm_add_pi16(adder, adder); + + // Overlaplength-division by shifter. "+1" is to account for "-1" deduced in + // overlapDividerBits calculation earlier. + shifter = _m_from_int(overlapDividerBitsPure + 1); + + for (i = 0; i < overlapLength / 4; i ++) + { + __m64 temp1, temp2; + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r + temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + // --- second round begins here --- + + // load & shuffle data so that input & mixbuffer data samples are paired + temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r + temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r + + // temp = (temp .* mix) >> shifter + temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter); + temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter); + pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit + + // update mix += adder + mix1 = _mm_add_pi16(mix1, adder); + mix2 = _mm_add_pi16(mix2, adder); + + pVinput += 2; + pVMidBuf += 2; + pVdest += 2; + } + + _m_empty(); // clear MMS state +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of MMX optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + + +FIRFilterMMX::FIRFilterMMX() : FIRFilter() +{ + filterCoeffsAlign = NULL; + filterCoeffsUnalign = NULL; +} + + +FIRFilterMMX::~FIRFilterMMX() +{ + delete[] filterCoeffsUnalign; +} + + +// (overloaded) Calculates filter coefficients for MMX routine +void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new short[2 * newLength + 8]; + filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); + + // rearrange the filter coefficients for mmx routines + for (i = 0;i < length; i += 4) + { + filterCoeffsAlign[2 * i + 0] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 1] = coeffs[i + 2]; + filterCoeffsAlign[2 * i + 2] = coeffs[i + 0]; + filterCoeffsAlign[2 * i + 3] = coeffs[i + 2]; + + filterCoeffsAlign[2 * i + 4] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 5] = coeffs[i + 3]; + filterCoeffsAlign[2 * i + 6] = coeffs[i + 1]; + filterCoeffsAlign[2 * i + 7] = coeffs[i + 3]; + } +} + + +// mmx-optimized version of the filter routine for stereo sound +uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const +{ + // Create stack copies of the needed member variables for asm routines : + uint i, j; + __m64 *pVdest = (__m64*)dest; + + if (length < 2) return 0; + + for (i = 0; i < (numSamples - length) / 2; i ++) + { + __m64 accu1; + __m64 accu2; + const __m64 *pVsrc = (const __m64*)src; + const __m64 *pVfilter = (const __m64*)filterCoeffsAlign; + + accu1 = accu2 = _mm_setzero_si64(); + for (j = 0; j < lengthDiv8 * 2; j ++) + { + __m64 temp1, temp2; + + temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0 + temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1 + + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0 + accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1 + + temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2 + + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0 + accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1 + + // accu1 += l2*f2+l0*f0 r2*f2+r0*f0 + // += l3*f3+l1*f1 r3*f3+r1*f1 + + // accu2 += l3*f2+l1*f0 r3*f2+r1*f0 + // l4*f3+l2*f1 r4*f3+r2*f1 + + pVfilter += 2; + pVsrc += 2; + } + // accu >>= resultDivFactor + accu1 = _mm_srai_pi32(accu1, resultDivFactor); + accu2 = _mm_srai_pi32(accu2, resultDivFactor); + + // pack 2*2*32bits => 4*16 bits + pVdest[0] = _mm_packs_pi32(accu1, accu2); + src += 4; + pVdest ++; + } + + _m_empty(); // clear emms state + + return (numSamples & 0xfffffffe) - length; +} + +#else + +// workaround to not complain about empty module +bool _dontcomplain_mmx_empty; + +#endif // SOUNDTOUCH_ALLOW_MMX diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/sse_optimized.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/sse_optimized.cpp new file mode 100644 index 00000000..9c16ea8f --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouch/sse_optimized.cpp @@ -0,0 +1,365 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE +/// optimized functions have been gathered into this single source +/// code file, regardless to their class or original source code file, in order +/// to ease porting the library to other compiler and processor platforms. +/// +/// The SSE-optimizations are programmed using SSE compiler intrinsics that +/// are supported both by Microsoft Visual C++ and GCC compilers, so this file +/// should compile with both toolsets. +/// +/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ +/// 6.0 processor pack" update to support SSE instruction set. The update is +/// available for download at Microsoft Developers Network, see here: +/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx +/// +/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and +/// perform a search with keywords "processor pack". +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "cpu_detect.h" +#include "STTypes.h" + +using namespace soundtouch; + +#ifdef SOUNDTOUCH_ALLOW_SSE + +// SSE routines available only with float sample type + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'TDStretchSSE' +// +////////////////////////////////////////////////////////////////////////////// + +#include "TDStretch.h" +#include <xmmintrin.h> +#include <math.h> + +// Calculates cross correlation of two buffers +double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm) +{ + int i; + const float *pVec1; + const __m128 *pVec2; + __m128 vSum, vNorm; + + // Note. It means a major slow-down if the routine needs to tolerate + // unaligned __m128 memory accesses. It's way faster if we can skip + // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps. + // This can mean up to ~ 10-fold difference (incl. part of which is + // due to skipping every second round for stereo sound though). + // + // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided + // for choosing if this little cheating is allowed. + +#ifdef ST_SIMD_AVOID_UNALIGNED + // Little cheating allowed, return valid correlation only for + // aligned locations, meaning every second round for stereo sound. + + #define _MM_LOAD _mm_load_ps + + if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations + +#else + // No cheating allowed, use unaligned load & take the resulting + // performance hit. + #define _MM_LOAD _mm_loadu_ps +#endif + + // ensure overlapLength is divisible by 8 + assert((overlapLength % 8) == 0); + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not. + pVec1 = (const float*)pV1; + pVec2 = (const __m128*)pV2; + vSum = vNorm = _mm_setzero_ps(); + + // Unroll the loop by factor of 4 * 4 operations. Use same routine for + // stereo & mono, for mono it just means twice the amount of unrolling. + for (i = 0; i < channels * overlapLength / 16; i ++) + { + __m128 vTemp; + // vSum += pV1[0..3] * pV2[0..3] + vTemp = _MM_LOAD(pVec1); + vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0])); + vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); + + // vSum += pV1[4..7] * pV2[4..7] + vTemp = _MM_LOAD(pVec1 + 4); + vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1])); + vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); + + // vSum += pV1[8..11] * pV2[8..11] + vTemp = _MM_LOAD(pVec1 + 8); + vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2])); + vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); + + // vSum += pV1[12..15] * pV2[12..15] + vTemp = _MM_LOAD(pVec1 + 12); + vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3])); + vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp)); + + pVec1 += 16; + pVec2 += 4; + } + + // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3] + float *pvNorm = (float*)&vNorm; + float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]); + anorm = norm; + + float *pvSum = (float*)&vSum; + return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm); + + /* This is approximately corresponding routine in C-language yet without normalization: + double corr, norm; + uint i; + + // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors + corr = norm = 0.0; + for (i = 0; i < channels * overlapLength / 16; i ++) + { + corr += pV1[0] * pV2[0] + + pV1[1] * pV2[1] + + pV1[2] * pV2[2] + + pV1[3] * pV2[3] + + pV1[4] * pV2[4] + + pV1[5] * pV2[5] + + pV1[6] * pV2[6] + + pV1[7] * pV2[7] + + pV1[8] * pV2[8] + + pV1[9] * pV2[9] + + pV1[10] * pV2[10] + + pV1[11] * pV2[11] + + pV1[12] * pV2[12] + + pV1[13] * pV2[13] + + pV1[14] * pV2[14] + + pV1[15] * pV2[15]; + + for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j]; + + pV1 += 16; + pV2 += 16; + } + return corr / sqrt(norm); + */ +} + + + +double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm) +{ + // call usual calcCrossCorr function because SSE does not show big benefit of + // accumulating "norm" value, and also the "norm" rolling algorithm would get + // complicated due to SSE-specific alignment-vs-nonexact correlation rules. + return calcCrossCorr(pV1, pV2, norm); +} + + +////////////////////////////////////////////////////////////////////////////// +// +// implementation of SSE optimized functions of class 'FIRFilter' +// +////////////////////////////////////////////////////////////////////////////// + +#include "FIRFilter.h" + +FIRFilterSSE::FIRFilterSSE() : FIRFilter() +{ + filterCoeffsAlign = NULL; + filterCoeffsUnalign = NULL; +} + + +FIRFilterSSE::~FIRFilterSSE() +{ + delete[] filterCoeffsUnalign; + filterCoeffsAlign = NULL; + filterCoeffsUnalign = NULL; +} + + +// (overloaded) Calculates filter coefficients for SSE routine +void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) +{ + uint i; + float fDivider; + + FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); + + // Scale the filter coefficients so that it won't be necessary to scale the filtering result + // also rearrange coefficients suitably for SSE + // Ensure that filter coeffs array is aligned to 16-byte boundary + delete[] filterCoeffsUnalign; + filterCoeffsUnalign = new float[2 * newLength + 4]; + filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); + + fDivider = (float)resultDivider; + + // rearrange the filter coefficients for mmx routines + for (i = 0; i < newLength; i ++) + { + filterCoeffsAlign[2 * i + 0] = + filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; + } +} + + + +// SSE-optimized version of the filter routine for stereo sound +uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const +{ + int count = (int)((numSamples - length) & (uint)-2); + int j; + + assert(count % 2 == 0); + + if (count < 2) return 0; + + assert(source != NULL); + assert(dest != NULL); + assert((length % 8) == 0); + assert(filterCoeffsAlign != NULL); + assert(((ulongptr)filterCoeffsAlign) % 16 == 0); + + // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' + #pragma omp parallel for + for (j = 0; j < count; j += 2) + { + const float *pSrc; + float *pDest; + const __m128 *pFil; + __m128 sum1, sum2; + uint i; + + pSrc = (const float*)source + j * 2; // source audio data + pDest = dest + j * 2; // destination audio data + pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients + // are aligned to 16-byte boundary + sum1 = sum2 = _mm_setzero_ps(); + + for (i = 0; i < length / 8; i ++) + { + // Unroll loop for efficiency & calculate filter for 2*2 stereo samples + // at each pass + + // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset + // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset. + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2])); + + sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3])); + sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3])); + + pSrc += 16; + pFil += 4; + } + + // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need + // to sum the two hi- and lo-floats of these registers together. + + // post-shuffle & add the filtered values and store to dest. + _mm_storeu_ps(pDest, _mm_add_ps( + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2 + _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0 + )); + } + + // Ideas for further improvement: + // 1. If it could be guaranteed that 'source' were always aligned to 16-byte + // boundary, a faster aligned '_mm_load_ps' instruction could be used. + // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte + // boundary, a faster '_mm_store_ps' instruction could be used. + + return (uint)count; + + /* original routine in C-language. please notice the C-version has differently + organized coefficients though. + double suml1, suml2; + double sumr1, sumr2; + uint i, j; + + for (j = 0; j < count; j += 2) + { + const float *ptr; + const float *pFil; + + suml1 = sumr1 = 0.0; + suml2 = sumr2 = 0.0; + ptr = src; + pFil = filterCoeffs; + for (i = 0; i < lengthLocal; i ++) + { + // unroll loop for efficiency. + + suml1 += ptr[0] * pFil[0] + + ptr[2] * pFil[2] + + ptr[4] * pFil[4] + + ptr[6] * pFil[6]; + + sumr1 += ptr[1] * pFil[1] + + ptr[3] * pFil[3] + + ptr[5] * pFil[5] + + ptr[7] * pFil[7]; + + suml2 += ptr[8] * pFil[0] + + ptr[10] * pFil[2] + + ptr[12] * pFil[4] + + ptr[14] * pFil[6]; + + sumr2 += ptr[9] * pFil[1] + + ptr[11] * pFil[3] + + ptr[13] * pFil[5] + + ptr[15] * pFil[7]; + + ptr += 16; + pFil += 8; + } + dest[0] = (float)suml1; + dest[1] = (float)sumr1; + dest[2] = (float)suml2; + dest[3] = (float)sumr2; + + src += 4; + dest += 4; + } + */ +} + +#endif // SOUNDTOUCH_ALLOW_SSE diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.cpp b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.cpp new file mode 100644 index 00000000..f8bba699 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.cpp @@ -0,0 +1,527 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch DLL wrapper - wraps SoundTouch routines into a Dynamic Load +/// Library interface. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + + +#if defined(_WIN32) || defined(WIN32) + #include <windows.h> + + // DLL main in Windows compilation + BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) + { + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; + } +#endif + +#include <limits.h> +#include <string.h> +#include "SoundTouchDLL.h" +#include "SoundTouch.h" +#include "BPMDetect.h" + +using namespace soundtouch; + +#ifdef SOUNDTOUCH_INTEGER_SAMPLES + #error "error - compile the dll version with float samples" +#endif // SOUNDTOUCH_INTEGER_SAMPLES + +////////////// + +typedef struct +{ + DWORD dwMagic; + SoundTouch *pst; +} STHANDLE; + +typedef struct +{ + DWORD dwMagic; + BPMDetect *pbpm; + uint numChannels; +} BPMHANDLE; + +#define STMAGIC 0x1770C001 +#define BPMMAGIC 0x1771C10a + +SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance() +{ + STHANDLE *tmp = new STHANDLE; + + if (tmp) + { + tmp->dwMagic = STMAGIC; + tmp->pst = new SoundTouch(); + if (tmp->pst == NULL) + { + delete tmp; + tmp = NULL; + } + } + return (HANDLE)tmp; +} + + +SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->dwMagic = 0; + if (sth->pst) delete sth->pst; + sth->pst = NULL; + delete sth; +} + + +/// Get SoundTouch library version string +SOUNDTOUCHDLL_API const char *__cdecl soundtouch_getVersionString() +{ + return SoundTouch::getVersionString(); +} + + +/// Get SoundTouch library version string - alternative function for +/// environments that can't properly handle character string as return value +SOUNDTOUCHDLL_API void __cdecl soundtouch_getVersionString2(char* versionString, int bufferSize) +{ + strncpy(versionString, SoundTouch::getVersionString(), bufferSize - 1); + versionString[bufferSize - 1] = 0; +} + + +/// Get SoundTouch library version Id +SOUNDTOUCHDLL_API uint __cdecl soundtouch_getVersionId() +{ + return SoundTouch::getVersionId(); +} + +/// Sets new rate control value. Normal rate = 1.0, smaller values +/// represent slower rate, larger faster rates. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setRate(HANDLE h, float newRate) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setRate(newRate); +} + + +/// Sets new tempo control value. Normal tempo = 1.0, smaller values +/// represent slower tempo, larger faster tempo. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempo(HANDLE h, float newTempo) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setTempo(newTempo); +} + +/// Sets new rate control value as a difference in percents compared +/// to the original rate (-50 .. +100 %) +SOUNDTOUCHDLL_API void __cdecl soundtouch_setRateChange(HANDLE h, float newRate) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setRateChange(newRate); +} + +/// Sets new tempo control value as a difference in percents compared +/// to the original tempo (-50 .. +100 %) +SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempoChange(HANDLE h, float newTempo) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setTempoChange(newTempo); +} + +/// Sets new pitch control value. Original pitch = 1.0, smaller values +/// represent lower pitches, larger values higher pitch. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitch(HANDLE h, float newPitch) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setPitch(newPitch); +} + +/// Sets pitch change in octaves compared to the original pitch +/// (-1.00 .. +1.00) +SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchOctaves(HANDLE h, float newPitch) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setPitchOctaves(newPitch); +} + +/// Sets pitch change in semi-tones compared to the original pitch +/// (-12 .. +12) +SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newPitch) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setPitchSemiTones(newPitch); +} + + +/// Sets the number of channels, 1 = mono, 2 = stereo +SOUNDTOUCHDLL_API void __cdecl soundtouch_setChannels(HANDLE h, uint numChannels) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setChannels(numChannels); +} + +/// Sets sample rate. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, uint srate) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->setSampleRate(srate); +} + +/// Flushes the last samples from the processing pipeline to the output. +/// Clears also the internal processing buffers. +// +/// Note: This function is meant for extracting the last samples of a sound +/// stream. This function may introduce additional blank samples in the end +/// of the sound stream, and thus it's not recommended to call this function +/// in the middle of a sound stream. +SOUNDTOUCHDLL_API void __cdecl soundtouch_flush(HANDLE h) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->flush(); +} + +/// Adds 'numSamples' pcs of samples from the 'samples' memory position into +/// the input of the object. Notice that sample rate _has_to_ be set before +/// calling this function, otherwise throws a runtime_error exception. +SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h, + const SAMPLETYPE *samples, ///< Pointer to sample buffer. + unsigned int numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->putSamples(samples, numSamples); +} + +/// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data +/// and internally converts it to float format before processing +SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples_i16(HANDLE h, + const short *samples, ///< Pointer to sample buffer. + unsigned int numSamples ///< Number of sample frames in buffer. Notice + ///< that in case of multi-channel sound a single sample + ///< contains data for all channels. + ) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + uint numChannels = sth->pst->numChannels(); + + // iterate until all samples converted & put to SoundTouch object + while (numSamples > 0) + { + float convert[8192]; // allocate temporary conversion buffer from stack + + // how many multichannel samples fit into 'convert' buffer: + uint convSamples = 8192 / numChannels; + + // convert max 'nround' values at a time to guarantee that these fit in the 'convert' buffer + uint n = (numSamples > convSamples) ? convSamples : numSamples; + for (uint i = 0; i < n * numChannels; i++) + { + convert[i] = samples[i]; + } + // put the converted samples into SoundTouch + sth->pst->putSamples(convert, n); + + numSamples -= n; + samples += n * numChannels; + } +} + +/// Clears all the samples in the object's output and internal processing +/// buffers. +SOUNDTOUCHDLL_API void __cdecl soundtouch_clear(HANDLE h) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return; + + sth->pst->clear(); +} + +/// Changes a setting controlling the processing system behaviour. See the +/// 'SETTING_...' defines for available setting ID's. +/// +/// \return 'nonzero' if the setting was successfully changed +SOUNDTOUCHDLL_API int __cdecl soundtouch_setSetting(HANDLE h, + int settingId, ///< Setting ID number. see SETTING_... defines. + int value ///< New setting value. + ) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return FALSE; + + return sth->pst->setSetting(settingId, value); +} + +/// Reads a setting controlling the processing system behaviour. See the +/// 'SETTING_...' defines for available setting ID's. +/// +/// \return the setting value. +SOUNDTOUCHDLL_API int __cdecl soundtouch_getSetting(HANDLE h, + int settingId ///< Setting ID number, see SETTING_... defines. + ) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return -1; + + return sth->pst->getSetting(settingId); +} + + +/// Returns number of samples currently unprocessed. +SOUNDTOUCHDLL_API uint __cdecl soundtouch_numUnprocessedSamples(HANDLE h) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return 0; + + return sth->pst->numUnprocessedSamples(); +} + + +/// Adjusts book-keeping so that given number of samples are removed from beginning of the +/// sample buffer without copying them anywhere. +/// +/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly +/// with 'ptrBegin' function. +SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples(HANDLE h, + SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. + unsigned int maxSamples ///< How many samples to receive at max. + ) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return 0; + + if (outBuffer) + { + return sth->pst->receiveSamples(outBuffer, maxSamples); + } + else + { + return sth->pst->receiveSamples(maxSamples); + } +} + + +/// int16 version of soundtouch_receiveSamples(): This converts internal float samples +/// into int16 (short) return data type +SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples_i16(HANDLE h, + short *outBuffer, ///< Buffer where to copy output samples. + unsigned int maxSamples ///< How many samples to receive at max. + ) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return 0; + uint outTotal = 0; + + if (outBuffer == NULL) + { + // only reduce sample count, not receive samples + return sth->pst->receiveSamples(maxSamples); + } + + uint numChannels = sth->pst->numChannels(); + + // iterate until all samples converted & put to SoundTouch object + while (maxSamples > 0) + { + float convert[8192]; // allocate temporary conversion buffer from stack + + // how many multichannel samples fit into 'convert' buffer: + uint convSamples = 8192 / numChannels; + + // request max 'nround' values at a time to guarantee that these fit in the 'convert' buffer + uint n = (maxSamples > convSamples) ? convSamples : maxSamples; + + uint out = sth->pst->receiveSamples(convert, n); + + // convert & saturate received samples to int16 + for (uint i = 0; i < out * numChannels; i++) + { + // first convert value to int32, then saturate to int16 min/max limits + int value = (int)convert[i]; + value = (value < SHRT_MIN) ? SHRT_MIN : (value > SHRT_MAX) ? SHRT_MAX : value; + outBuffer[i] = (short)value; + } + outTotal += out; + if (out < n) break; // didn't get as many as asked => no more samples available => break here + + maxSamples -= n; + outBuffer += out * numChannels; + } + + // return number of processed samples + return outTotal; +} + + +/// Returns number of samples currently available. +SOUNDTOUCHDLL_API uint __cdecl soundtouch_numSamples(HANDLE h) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return 0; + + return sth->pst->numSamples(); +} + + +/// Returns nonzero if there aren't any samples available for outputting. +SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h) +{ + STHANDLE *sth = (STHANDLE*)h; + if (sth->dwMagic != STMAGIC) return -1; + + return sth->pst->isEmpty(); +} + + +SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate) +{ + BPMHANDLE *tmp = new BPMHANDLE; + + if (tmp) + { + tmp->dwMagic = BPMMAGIC; + tmp->pbpm = new BPMDetect(numChannels, sampleRate); + if (tmp->pbpm == NULL) + { + delete tmp; + tmp = NULL; + } + } + return (HANDLE)tmp; +} + + +SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h) +{ + BPMHANDLE *sth = (BPMHANDLE*)h; + if (sth->dwMagic != BPMMAGIC) return; + + sth->dwMagic = 0; + if (sth->pbpm) delete sth->pbpm; + sth->pbpm = NULL; + delete sth; +} + + +/// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler +SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h, + const float *samples, + unsigned int numSamples) +{ + BPMHANDLE *bpmh = (BPMHANDLE*)h; + if (bpmh->dwMagic != BPMMAGIC) return; + + bpmh->pbpm->inputSamples(samples, numSamples); +} + + +/// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler. +/// 16bit int sample format version. +SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h, + const short *samples, + unsigned int numSamples) +{ + BPMHANDLE *bpmh = (BPMHANDLE*)h; + if (bpmh->dwMagic != BPMMAGIC) return; + + uint numChannels = bpmh->numChannels; + + // iterate until all samples converted & put to SoundTouch object + while (numSamples > 0) + { + float convert[8192]; // allocate temporary conversion buffer from stack + + // how many multichannel samples fit into 'convert' buffer: + uint convSamples = 8192 / numChannels; + + // convert max 'nround' values at a time to guarantee that these fit in the 'convert' buffer + uint n = (numSamples > convSamples) ? convSamples : numSamples; + for (uint i = 0; i < n * numChannels; i++) + { + convert[i] = samples[i]; + } + // put the converted samples into SoundTouch + bpmh->pbpm->inputSamples(convert, n); + + numSamples -= n; + samples += n * numChannels; + } +} + + +/// 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. +SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h) +{ + BPMHANDLE *bpmh = (BPMHANDLE*)h; + if (bpmh->dwMagic != BPMMAGIC) return 0; + + return bpmh->pbpm->getBpm(); +} diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.h new file mode 100644 index 00000000..211f5611 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.h @@ -0,0 +1,229 @@ +////////////////////////////////////////////////////////////////////////////// +/// +/// SoundTouch DLL wrapper - wraps SoundTouch routines into a Dynamic Load +/// Library interface. +/// +/// Author : Copyright (c) Olli Parviainen +/// Author e-mail : oparviai 'at' iki.fi +/// SoundTouch WWW: http://www.surina.net/soundtouch +/// +//////////////////////////////////////////////////////////////////////////////// +// +// License : +// +// SoundTouch audio processing library +// Copyright (c) Olli Parviainen +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef _SoundTouchDLL_h_ +#define _SoundTouchDLL_h_ + +#if defined(_WIN32) || defined(WIN32) + // Windows + #ifndef __cplusplus + #error "Expected g++" + #endif + + #ifdef DLL_EXPORTS + #define SOUNDTOUCHDLL_API extern "C" __declspec(dllexport) + #else + #define SOUNDTOUCHDLL_API extern "C" __declspec(dllimport) + #endif + +#else + // GNU version + + #if defined(DLL_EXPORTS) || defined(SoundTouchDLL_EXPORTS) + // GCC declaration for exporting functions + #define SOUNDTOUCHDLL_API extern "C" __attribute__((__visibility__("default"))) + #else + // GCC doesn't require DLL imports + #define SOUNDTOUCHDLL_API + #endif + + // Linux-replacements for Windows declarations: + #define __cdecl + typedef unsigned int DWORD; + #define FALSE 0 + #define TRUE 1 + +#endif + +typedef void * HANDLE; + +/// Create a new instance of SoundTouch processor. +SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance(); + +/// Destroys a SoundTouch processor instance. +SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h); + +/// Get SoundTouch library version string +SOUNDTOUCHDLL_API const char *__cdecl soundtouch_getVersionString(); + +/// Get SoundTouch library version string - alternative function for +/// environments that can't properly handle character string as return value +SOUNDTOUCHDLL_API void __cdecl soundtouch_getVersionString2(char* versionString, int bufferSize); + +/// Get SoundTouch library version Id +SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_getVersionId(); + +/// Sets new rate control value. Normal rate = 1.0, smaller values +/// represent slower rate, larger faster rates. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setRate(HANDLE h, float newRate); + +/// Sets new tempo control value. Normal tempo = 1.0, smaller values +/// represent slower tempo, larger faster tempo. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempo(HANDLE h, float newTempo); + +/// Sets new rate control value as a difference in percents compared +/// to the original rate (-50 .. +100 %); +SOUNDTOUCHDLL_API void __cdecl soundtouch_setRateChange(HANDLE h, float newRate); + +/// Sets new tempo control value as a difference in percents compared +/// to the original tempo (-50 .. +100 %); +SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempoChange(HANDLE h, float newTempo); + +/// Sets new pitch control value. Original pitch = 1.0, smaller values +/// represent lower pitches, larger values higher pitch. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitch(HANDLE h, float newPitch); + +/// Sets pitch change in octaves compared to the original pitch +/// (-1.00 .. +1.00); +SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchOctaves(HANDLE h, float newPitch); + +/// Sets pitch change in semi-tones compared to the original pitch +/// (-12 .. +12); +SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newPitch); + + +/// Sets the number of channels, 1 = mono, 2 = stereo, n = multichannel +SOUNDTOUCHDLL_API void __cdecl soundtouch_setChannels(HANDLE h, unsigned int numChannels); + +/// Sets sample rate. +SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, unsigned int srate); + +/// Flushes the last samples from the processing pipeline to the output. +/// Clears also the internal processing buffers. +// +/// Note: This function is meant for extracting the last samples of a sound +/// stream. This function may introduce additional blank samples in the end +/// of the sound stream, and thus it's not recommended to call this function +/// in the middle of a sound stream. +SOUNDTOUCHDLL_API void __cdecl soundtouch_flush(HANDLE h); + +/// Adds 'numSamples' pcs of samples from the 'samples' memory position into +/// the input of the object. Notice that sample rate _has_to_ be set before +/// calling this function, otherwise throws a runtime_error exception. +SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h, + const float *samples, ///< Pointer to sample buffer. + unsigned int numSamples ///< Number of sample frames in buffer. Notice + ///< that in case of multi-channel sound a single + ///< sample frame contains data for all channels. +); + +/// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data +/// and internally converts it to float format before processing +SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples_i16(HANDLE h, + const short *samples, ///< Pointer to sample buffer. + unsigned int numSamples ///< Number of sample frames in buffer. Notice + ///< that in case of multi-channel sound a single + ///< sample frame contains data for all channels. +); + + +/// Clears all the samples in the object's output and internal processing +/// buffers. +SOUNDTOUCHDLL_API void __cdecl soundtouch_clear(HANDLE h); + +/// Changes a setting controlling the processing system behaviour. See the +/// 'SETTING_...' defines for available setting ID's. +/// +/// \return 'nonzero' if the setting was successfully changed, otherwise zero +SOUNDTOUCHDLL_API int __cdecl soundtouch_setSetting(HANDLE h, + int settingId, ///< Setting ID number. see SETTING_... defines. + int value ///< New setting value. +); + +/// Reads a setting controlling the processing system behaviour. See the +/// 'SETTING_...' defines for available setting ID's. +/// +/// \return the setting value. +SOUNDTOUCHDLL_API int __cdecl soundtouch_getSetting(HANDLE h, + int settingId ///< Setting ID number, see SETTING_... defines. +); + + +/// Returns number of samples currently unprocessed. +SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numUnprocessedSamples(HANDLE h); + +/// Adjusts book-keeping so that given number of samples are removed from beginning of the +/// sample buffer without copying them anywhere. +/// +/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly +/// with 'ptrBegin' function. +SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples(HANDLE h, + float *outBuffer, ///< Buffer where to copy output samples. + unsigned int maxSamples ///< How many samples to receive at max. +); + + +/// int16 version of soundtouch_receiveSamples(): This converts internal float samples +/// into int16 (short) return data type +SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples_i16(HANDLE h, + short *outBuffer, ///< Buffer where to copy output samples. + unsigned int maxSamples ///< How many samples to receive at max. +); + +/// Returns number of samples currently available. +SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numSamples(HANDLE h); + +/// Returns nonzero if there aren't any samples available for outputting. +SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h); + +/// Create a new instance of BPM detector +SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate); + +/// Destroys a BPM detector instance. +SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h); + +/// Feed 'numSamples' sample frames from 'samples' into the BPM detector. +SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h, + const float *samples, ///< Pointer to sample buffer. + unsigned int numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + +/// Feed 'numSamples' sample frames from 'samples' into the BPM detector. +/// 16bit int sample format version. +SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h, + const short *samples, ///< Pointer to sample buffer. + unsigned int numSamples ///< Number of samples in buffer. Notice + ///< that in case of stereo-sound a single sample + ///< contains data for both channels. + ); + +/// 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. +SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h); + +#endif // _SoundTouchDLL_h_ + diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.rc b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.rc new file mode 100644 index 00000000..ec3833d6 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/SoundTouchDLL.rc @@ -0,0 +1,100 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,2,0,0 + PRODUCTVERSION 2,2,0,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "Comments", "SoundTouch Library licensed for 3rd party applications subject to LGPL license v2.1. Visit http://www.surina.net/soundtouch for more information about the SoundTouch library." + VALUE "FileDescription", "SoundTouch Dynamic Link Library" + VALUE "FileVersion", "2.3.1.0" + VALUE "InternalName", "SoundTouch" + VALUE "LegalCopyright", "Copyright (C) Olli Parviainen 2021" + VALUE "OriginalFilename", "SoundTouch.dll" + VALUE "ProductName", " SoundTouch Dynamic Link Library" + VALUE "ProductVersion", "2.3.1.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/resource.h b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/resource.h new file mode 100644 index 00000000..9e07a2b8 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/include/soundtouch/source/SoundTouchDLL/resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by SoundTouchDLL.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif |