Imported Upstream version 2.1.0 upstream 2.1.0
authorEunhye Choi <eunhae1.choi@samsung.com>
Fri, 15 Mar 2019 09:32:10 +0000 (18:32 +0900)
committerEunhye Choi <eunhae1.choi@samsung.com>
Fri, 15 Mar 2019 09:32:10 +0000 (18:32 +0900)
106 files changed:
.gitignore [new file with mode: 0644]
.vscode/tasks.json [new file with mode: 0644]
COPYING.TXT [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README.html [new file with mode: 0644]
bin/run_test [new file with mode: 0755]
bin/run_test.cmd [new file with mode: 0644]
bootstrap [new file with mode: 0755]
config/README.TXT [new file with mode: 0644]
config/am_include.mk [new file with mode: 0644]
configure.ac [new file with mode: 0644]
createsrcpack [new file with mode: 0755]
include/BPMDetect.h [new file with mode: 0644]
include/FIFOSampleBuffer.h [new file with mode: 0644]
include/FIFOSamplePipe.h [new file with mode: 0644]
include/Makefile.am [new file with mode: 0644]
include/STTypes.h [new file with mode: 0644]
include/SoundTouch.h [new file with mode: 0644]
include/soundtouch_config.h.in [new file with mode: 0644]
make-win.bat [new file with mode: 0644]
readme.md [new file with mode: 0644]
soundtouch.m4 [new file with mode: 0644]
soundtouch.pc.in [new file with mode: 0644]
source/Android-lib/.classpath [new file with mode: 0644]
source/Android-lib/.project [new file with mode: 0644]
source/Android-lib/AndroidManifest.xml [new file with mode: 0644]
source/Android-lib/README-SoundTouch-Android.html [new file with mode: 0644]
source/Android-lib/jni/Android.mk [new file with mode: 0644]
source/Android-lib/jni/Application.mk [new file with mode: 0644]
source/Android-lib/jni/soundtouch-jni.cpp [new file with mode: 0644]
source/Android-lib/lint.xml [new file with mode: 0644]
source/Android-lib/proguard-project.txt [new file with mode: 0644]
source/Android-lib/project.properties [new file with mode: 0644]
source/Android-lib/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
source/Android-lib/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
source/Android-lib/res/drawable-xhdpi/ic_launcher.png [new file with mode: 0644]
source/Android-lib/res/drawable-xxhdpi/ic_launcher.png [new file with mode: 0644]
source/Android-lib/res/layout/activity_example.xml [new file with mode: 0644]
source/Android-lib/res/values/strings.xml [new file with mode: 0644]
source/Android-lib/res/values/styles.xml [new file with mode: 0644]
source/Android-lib/src/net/surina/ExampleActivity.java [new file with mode: 0644]
source/Android-lib/src/net/surina/soundtouch/SoundTouch.java [new file with mode: 0644]
source/Makefile.am [new file with mode: 0644]
source/SoundStretch/Makefile.am [new file with mode: 0644]
source/SoundStretch/RunParameters.cpp [new file with mode: 0644]
source/SoundStretch/RunParameters.h [new file with mode: 0644]
source/SoundStretch/WavFile.cpp [new file with mode: 0644]
source/SoundStretch/WavFile.h [new file with mode: 0644]
source/SoundStretch/main.cpp [new file with mode: 0644]
source/SoundStretch/soundstretch.sln [new file with mode: 0644]
source/SoundStretch/soundstretch.vcxproj [new file with mode: 0644]
source/SoundTouch/AAFilter.cpp [new file with mode: 0644]
source/SoundTouch/AAFilter.h [new file with mode: 0644]
source/SoundTouch/BPMDetect.cpp [new file with mode: 0644]
source/SoundTouch/FIFOSampleBuffer.cpp [new file with mode: 0644]
source/SoundTouch/FIRFilter.cpp [new file with mode: 0644]
source/SoundTouch/FIRFilter.h [new file with mode: 0644]
source/SoundTouch/InterpolateCubic.cpp [new file with mode: 0644]
source/SoundTouch/InterpolateCubic.h [new file with mode: 0644]
source/SoundTouch/InterpolateLinear.cpp [new file with mode: 0644]
source/SoundTouch/InterpolateLinear.h [new file with mode: 0644]
source/SoundTouch/InterpolateShannon.cpp [new file with mode: 0644]
source/SoundTouch/InterpolateShannon.h [new file with mode: 0644]
source/SoundTouch/Makefile.am [new file with mode: 0644]
source/SoundTouch/PeakFinder.cpp [new file with mode: 0644]
source/SoundTouch/PeakFinder.h [new file with mode: 0644]
source/SoundTouch/RateTransposer.cpp [new file with mode: 0644]
source/SoundTouch/RateTransposer.h [new file with mode: 0644]
source/SoundTouch/SoundTouch.cpp [new file with mode: 0644]
source/SoundTouch/SoundTouch.sln [new file with mode: 0644]
source/SoundTouch/SoundTouch.vcxproj [new file with mode: 0644]
source/SoundTouch/TDStretch.cpp [new file with mode: 0644]
source/SoundTouch/TDStretch.h [new file with mode: 0644]
source/SoundTouch/cpu_detect.h [new file with mode: 0644]
source/SoundTouch/cpu_detect_x86.cpp [new file with mode: 0644]
source/SoundTouch/mmx_optimized.cpp [new file with mode: 0644]
source/SoundTouch/sse_optimized.cpp [new file with mode: 0644]
source/SoundTouchDLL/DllTest/DllTest.cpp [new file with mode: 0644]
source/SoundTouchDLL/DllTest/DllTest.vcxproj [new file with mode: 0644]
source/SoundTouchDLL/SoundTouchDLL.cpp [new file with mode: 0644]
source/SoundTouchDLL/SoundTouchDLL.h [new file with mode: 0644]
source/SoundTouchDLL/SoundTouchDLL.pas [new file with mode: 0644]
source/SoundTouchDLL/SoundTouchDLL.rc [new file with mode: 0644]
source/SoundTouchDLL/SoundTouchDLL.sln [new file with mode: 0644]
source/SoundTouchDLL/SoundTouchDLL.vcxproj [new file with mode: 0644]
source/SoundTouchDLL/make-gnu-dll.sh [new file with mode: 0755]
source/SoundTouchDLL/resource.h [new file with mode: 0644]
source/csharp-example/App.config [new file with mode: 0644]
source/csharp-example/App.xaml [new file with mode: 0644]
source/csharp-example/App.xaml.cs [new file with mode: 0644]
source/csharp-example/MainWindow.xaml [new file with mode: 0644]
source/csharp-example/MainWindow.xaml.cs [new file with mode: 0644]
source/csharp-example/NAudio-license.txt [new file with mode: 0644]
source/csharp-example/NAudio-readme.txt [new file with mode: 0644]
source/csharp-example/NAudio.dll [new file with mode: 0644]
source/csharp-example/Properties/AssemblyInfo.cs [new file with mode: 0644]
source/csharp-example/Properties/Resources.Designer.cs [new file with mode: 0644]
source/csharp-example/Properties/Resources.resx [new file with mode: 0644]
source/csharp-example/Properties/Settings.Designer.cs [new file with mode: 0644]
source/csharp-example/Properties/Settings.settings [new file with mode: 0644]
source/csharp-example/README.txt [new file with mode: 0644]
source/csharp-example/SoundProcessor.cs [new file with mode: 0644]
source/csharp-example/SoundTouch.cs [new file with mode: 0644]
source/csharp-example/SoundTouch.dll [new file with mode: 0644]
source/csharp-example/csharp-example.csproj [new file with mode: 0644]
source/csharp-example/csharp-example.sln [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9def793
--- /dev/null
@@ -0,0 +1,40 @@
+bin\r
+lib\r
+\r
+# Win build files\r
+*.dll\r
+*.exe\r
+*.lib\r
+\r
+# GNU build files\r
+*.o\r
+*.so*\r
+*.lo\r
+*.P*\r
+*.la*\r
+*.a\r
+*.pc\r
+*config*\r
+Makefile\r
+Makefile.in\r
+.libs\r
+aclocal.m4\r
+autom4te.cache\r
+stamp-*\r
+libtool\r
+soundstretch\r
+\r
+# Files generated by MSVC\r
+*.bsc\r
+*.suo\r
+*.sdf\r
+*.filters\r
+*.user\r
+source/SoundTouch/Win32/\r
+source/SoundTouch/x64/\r
+source/SoundStretch/Win32/\r
+source/SoundStretch/x64/\r
+source/SoundTouchDll/Win32/\r
+source/SoundTouchDll/x64/\r
+source/SoundTouchDll/DllTest/Win32/\r
+source/SoundTouchDll/DllTest/x64/\r
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644 (file)
index 0000000..66abc34
--- /dev/null
@@ -0,0 +1,32 @@
+{
+    // This is build task definition file for MS VisualStudio Code.
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "echo",
+            "type": "shell",
+            "command": "echo Hello"
+        },
+        {
+            "label": "configure",
+            "type": "shell",
+            "command": "./bootstrap && ./configure"
+        },
+        {
+            "label": "build",
+            "type": "shell",
+            "command": "make -j4",
+            "problemMatcher": [
+                "$gcc"
+            ]
+        },
+        {
+            "label": "clean",
+            "type": "shell",
+            "command": "make clean",
+            "problemMatcher": []
+        }
+    ]
+}
\ No newline at end of file
diff --git a/COPYING.TXT b/COPYING.TXT
new file mode 100644 (file)
index 0000000..bbd24e6
--- /dev/null
@@ -0,0 +1,458 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  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.
+\f
+  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.
+\f
+                 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 authoried 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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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.
+\f
+  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/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..1394ce6
--- /dev/null
@@ -0,0 +1,65 @@
+## 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
+
+## Descend into SUBDIRS and run make. Look at the Makefile.am files in the
+## subdirectories Start at frontend_fox/Makefile.am to see how everything works.
+SUBDIRS=include source
+
+# list files that are documentation to be packaged in a release tarball and installed
+dist_doc_DATA=COPYING.TXT README.html
+
+# extra data files that are to be pacakged in a release tarball and installed into the data directory
+#pkgdata_DATA=
+
+# sets up for soundtouch.m4 to be installed
+m4datadir=$(datadir)/aclocal
+m4data_DATA=soundtouch.m4
+
+## These extra files and directories will be included in the distribution. by
+## using make-dist by default many common filenames are automatically included
+## such as AUTHORS, COPYING, etc the bootstrap script really shouldn't be a part
+## of a final package, but it is useful for developers who might want to make
+## changes to the configure scripts or makefiles.
+# NOTE: wouldn't have to list the .TXT file if it were named without the .TXT
+EXTRA_DIST=                  \
+       soundtouch.m4        \
+       config/m4            \
+       bootstrap            \
+       make-win.bat         \
+       COPYING.TXT          \
+       README.html
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = soundtouch.pc
+
+## This removes stuff from the distribution which may be present
+## from a cvs checkout or other build reasons
+dist-hook:
+       rm -rf `find $(distdir) -type d -name CVS`      # remove all CVS directories
+       echo rm -rf `find $(distdir) -type f -name \.\#\*`      # CVS revision files left around for some reason
+
+## This happens at 'make distclean'
+#distcleancheck:
+#      rm -rf files-that-may-also-need-to-be-deleted-on-'make distclean'
+
+
+# flag to aclocal where to find m4 macros for tests
+ACLOCAL_AMFLAGS = -I config/m4
+AUTOMAKE_OPTIONS = foreign
diff --git a/README.html b/README.html
new file mode 100644 (file)
index 0000000..9373432
--- /dev/null
@@ -0,0 +1,914 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+  <title>SoundTouch library README</title>\r
+  <meta http-equiv="Content-Type"\r
+ content="text/html; charset=windows-1252">\r
+  <meta http-equiv="Content-Language" content="en-us">\r
+  <meta name="author" content="Olli Parviainen">\r
+  <meta name="description"\r
+ content="Readme file for SoundTouch audio processing library">\r
+  <style> <!-- .normal { font-family: Arial }\r
+    --></style>\r
+</head>\r
+<body class="normal">\r
+<hr>\r
+<h1>SoundTouch audio processing library v2.1</h1>\r
+<p class="normal">SoundTouch library Copyright &copy Olli Parviainen 2001-2018</p>\r
+<hr>\r
+<h2>1. Introduction </h2>\r
+<p>SoundTouch is an open-source audio processing library that allows\r
+changing the sound tempo, pitch and playback rate parameters\r
+independently from each other, i.e.:</p>\r
+<ul>\r
+  <li> Sound tempo can be increased or decreased while maintaining the\r
+original pitch</li>\r
+  <li> Sound pitch can be increased or decreased while maintaining the\r
+original tempo</li>\r
+  <li> Change playback rate that affects both tempo and pitch at the\r
+same time</li>\r
+  <li> Choose any combination of tempo/pitch/rate</li>\r
+</ul>\r
+<h3>1.1 Contact information </h3>\r
+<p>Author email: oparviai 'at' iki.fi </p>\r
+<p>SoundTouch WWW page: <a href="http://soundtouch.surina.net">http://soundtouch.surina.net</a></p>\r
+<p>SoundTouch git repository: <a href="https://gitlab.com/soundtouch/soundtouch.git">https://gitlab.com/soundtouch/soundtouch.git</a></p>\r
+<hr>\r
+<h2>2. Compiling SoundTouch</h2>\r
+<p>Before compiling, notice that you can choose the sample data format if it's \r
+desirable to use floating point sample data instead of 16bit integers. See \r
+section &quot;sample data format&quot; for more information.</p>\r
+<p>Also notice that SoundTouch can use OpenMP instructions for parallel \r
+computation to accelerate the runtime processing speed in multi-core systems, \r
+however, these improvements need to be separately enabled before compiling. See \r
+OpenMP notes in Chapter 3 below.</p>\r
+<h3>2.1. Building in Microsoft Windows</h3>\r
+<p>Project files for Microsoft Visual C++ are supplied with the source \r
+code package. Go to Microsoft WWW page to download \r
+<a href="http://www.visualstudio.com/en-US/products/visual-studio-express-vs">\r
+Microsoft Visual Studio Express version for free</a>.\r
+</p>\r
+<p>To build the binaries with Visual C++ compiler, either run\r
+"make-win.bat" script, or open the appropriate project files in source\r
+code directories with Visual Studio. The final executable will appear\r
+under the "SoundTouch\bin" directory. If using the Visual Studio IDE\r
+instead of the make-win.bat script, directories bin and lib may need to\r
+be created manually to the SoundTouch package root for the final\r
+executables. The make-win.bat script creates these directories\r
+automatically. </p>\r
+<p><strong>C# example</strong>: The source code package includes also a C# example \r
+    application for Windows that shows how to invoke SoundTouch.dll \r
+    dynamic-load library for processing mp3 audio.\r
+<p><strong>OpenMP NOTE</strong>: If activating the OpenMP parallel computing in \r
+the compilation, the target program will require additional vcomp dll library to \r
+properly run. In Visual C++ 9.0 these libraries can be found in the following \r
+folders.</p>\r
+<ul>\r
+    <li>x86 32bit: C:\Program Files (x86)\Microsoft Visual Studio \r
+    9.0\VC\redist\x86\Microsoft.VC90.OPENMP\vcomp90.dll</li>\r
+    <li>x64 64bit: C:\Program Files (x86)\Microsoft Visual Studio \r
+    9.0\VC\redist\amd64\Microsoft.VC90.OPENMP\vcomp90.dll</li>\r
+</ul>\r
+<p>In Visual Studio 2008, a SP1 version may be required for these libraries. In \r
+other VC++ versions the required library will be expectedly found in similar \r
+&quot;redist&quot; location.</p>\r
+<p>Notice that as minor demonstration of a &quot;dll hell&quot; phenomenon both the 32-bit \r
+and 64-bit version of vcomp90.dll have the same filename but different contents, \r
+thus choose the proper version to allow the program start.</p>\r
+<h3>2.2. Building in Gnu platforms</h3>\r
+<p>The SoundTouch library compiles in practically any platform\r
+supporting GNU compiler (GCC) tools. SoundTouch requires GCC version 4.3 or later.</p>\r
+<p>To build and install the binaries, run the following commands in \r
+/soundtouch directory:</p>\r
+<table border="0" cellpadding="0" cellspacing="4">\r
+  <tbody>\r
+    <tr>\r
+      <td style="vertical-align: top;">\r
+      <pre>./bootstrap  -</pre>\r
+      </td>\r
+      <td style="vertical-align: top;">Creates "configure" file with\r
+local autoconf/automake toolset.<br>\r
+      </td>\r
+    </tr>\r
+    <tr valign="top">\r
+      <td>\r
+      <pre>./configure  -</pre>\r
+      </td>\r
+      <td>\r
+      <p>Configures the SoundTouch package for the local environment.\r
+Notice that "configure" file is not available before running the\r
+"./bootstrap" command as above.<br>\r
+      </p>\r
+      </td>\r
+    </tr>\r
+    <tr valign="top">\r
+      <td>\r
+      <pre>make         -</pre>\r
+      </td>\r
+      <td>\r
+      <p>Builds the SoundTouch library &amp; SoundStretch utility. You can \r
+      optionally add &quot;-j&quot; switch after &quot;make&quot; to speed up the compilation in \r
+      multi-core systems.</p>\r
+      </td>\r
+    </tr>\r
+    <tr valign="top">\r
+      <td>\r
+      <pre>make install -</pre>\r
+      </td>\r
+      <td>\r
+      <p>Installs the SoundTouch &amp; BPM libraries to <b>/usr/local/lib</b>\r
+and SoundStretch utility to <b>/usr/local/bin</b>. Please notice that\r
+'root' privileges may be required to install the binaries to the\r
+destination locations.</p>\r
+      </td>\r
+    </tr>\r
+  </tbody>\r
+</table>\r
+<h4><b>2.2.1 Required GNU tools</b></h4>\r
+<p> <span style="font-weight: bold;">Bash shell</span>, <span\r
+ style="font-weight: bold;">GNU C++ compiler</span>, <span\r
+ style="font-weight: bold;">libtool</span>, <span\r
+ style="font-weight: bold;">autoconf</span> and <span\r
+ style="font-weight: bold;">automake</span> tools\r
+are required for compiling the SoundTouch library. These are usually\r
+included with the GNU/Linux distribution, but if not, install these\r
+packages first. For example, Ubuntu Linux can acquire and install\r
+these with the following command:</p>\r
+<pre><b>sudo apt-get install automake autoconf libtool build-essential</b></pre>\r
+<h4><b>2.2.2 Problems with GCC compiler compatibility</b></h4>\r
+<p>At the release time the SoundTouch package has been tested to\r
+compile in GNU/Linux platform. However, If you have problems getting the\r
+SoundTouch library compiled, try disabling optimizations that are specific for \r
+x86 processors by running <b>./configure</b> script with switch\r
+<blockquote>\r
+<pre>--enable-x86-optimizations=no</pre>\r
+</blockquote>\r
+\r
+Alternatively, if you don't use GNU Configure system, edit file "include/STTypes.h" \r
+directly and remove the following definition:<blockquote>\r
+  <pre>#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1</pre>\r
+</blockquote>\r
+\r
+<h4><b>2.2.3 Compiling Shared Library / DLL version in Cygwin</b></h4>\r
+    <p>\r
+        The GNU compilation does not automatically create a shared-library version of \r
+        SoundTouch (.so or .dll). If such is desired, then you can create it as follows \r
+        after running the usual compilation:</p>\r
+    <blockquote>\r
+  <pre>g++ -shared -static -DDLL_EXPORTS -I../../include -o SoundTouch.dll \\r
+     SoundTouchDLL.cpp ../SoundTouch/.libs/libSoundTouch.a\r
+sstrip SoundTouch.dll</pre>\r
+</blockquote>\r
+\r
+<h3>2.3. Building in Android</h3>\r
+<p>Android compilation instructions are within the \r
+    source code package, see file &quot;<b>source/Android-lib/README-SoundTouch-Android.html</b>&quot; \r
+    in the source code package. </p>\r
+<p>The Android compilation automatically builds separate .so library binaries \r
+for ARM, X86 and MIPS processor architectures. For optimal device support, \r
+include all these .so library binaries into the Android .apk application \r
+package, so the target Android device can automatically choose the proper \r
+library binary version to use.</p>\r
+<p>The <strong>source/Android-lib</strong> folder includes also an Android \r
+example application that processes WAV audio files using SoundTouch library in \r
+Android devices.</p>\r
+\r
+<hr>\r
+<h2>3. About implementation &amp; Usage tips <h3>3.1. Supported sample data formats</h3>\r
+<p>The sample data format can be chosen between 16bit signed integer\r
+and 32bit floating point values. The default is 32bit floating point format, \r
+which will also provide slightly better sound quality over the integer format. </p>\r
+<p> In Windows environment, the sample data format is chosen in file\r
+"STTypes.h" by choosing one of the following defines:</p>\r
+<ul>\r
+  <li> <span style="font-weight: bold;">#define\r
+SOUNDTOUCH_INTEGER_SAMPLES</span> for 16bit signed integer</li>\r
+  <li> <span style="font-weight: bold;">#define </span><span\r
+ style="font-weight: bold;">SOUNDTOUCH_</span><span\r
+ style="font-weight: bold;">FLOAT_SAMPLES</span> for 32bit floating\r
+point</li>\r
+</ul>\r
+<p> In GNU environment, the floating sample format is used by default,\r
+but integer sample format can be chosen by giving the following switch\r
+to the configure script: </p>\r
+<blockquote>\r
+  <pre>./configure --enable-integer-samples</pre>\r
+</blockquote>\r
+<p>The sample data can have either single (mono) or double (stereo)\r
+audio channel. Stereo data is interleaved so that every other data\r
+value is for left channel and every second for right channel. Notice\r
+that while it'd be possible in theory to process stereo sound as two\r
+separate mono channels, this isn't recommended because processing the\r
+channels separately would result in losing the phase coherency between\r
+the channels, which consequently would ruin the stereo effect.</p>\r
+<p>Sample rates between 8000-48000H are supported.</p>\r
+<h3>3.2. Processing latency</h3>\r
+<p>The processing and latency constraints of the SoundTouch library are:</p>\r
+<ul>\r
+  <li> Input/output processing latency for the SoundTouch processor is\r
+around 100 ms. This is when time-stretching is used. If the rate\r
+transposing effect alone is used, the latency requirement is much\r
+shorter, see section 'About algorithms'.</li>\r
+  <li> Processing CD-quality sound (16bit stereo sound with 44100H\r
+sample rate) in real-time or faster is possible starting from\r
+processors equivalent to Intel Pentium 133Mh or better, if using the\r
+"quick" processing algorithm. If not using the "quick" mode or if\r
+floating point sample data are being used, several times more CPU power\r
+is typically required.</li>\r
+</ul>\r
+<h3>3.3. About algorithms</h3>\r
+<p>SoundTouch provides three seemingly independent effects: tempo,\r
+pitch and playback rate control. These three controls are implemented\r
+as combination of two primary effects, <em>sample rate transposing</em>\r
+and <em>time-stretching</em>.</p>\r
+<p><em>Sample rate transposing</em> affects both the audio stream\r
+duration and pitch. It's implemented simply by converting the original\r
+audio sample stream to the desired duration by interpolating from\r
+the original audio samples. In SoundTouch, linear interpolation with\r
+anti-alias filtering is used. Theoretically a higher-order\r
+interpolation provide better result than 1st order linear\r
+interpolation, but in audio application linear interpolation together\r
+with anti-alias filtering performs subjectively about as well as\r
+higher-order filtering would.</p>\r
+<p><em>Time-stretching </em>means changing the audio stream duration\r
+without affecting it's pitch. SoundTouch uses WSOLA-like\r
+time-stretching routines that operate in the time domain. Compared to\r
+sample rate transposing, time-stretching is a much heavier operation\r
+and also requires a longer processing "window" of sound samples used by\r
+the processing algorithm, thus increasing the algorithm input/output\r
+latency. Typical i/o latency for the SoundTouch time-stretch algorithm\r
+is around 100 ms.</p>\r
+<p>Sample rate transposing and time-stretching are then used together\r
+to produce the tempo, pitch and rate controls:</p>\r
+<ul>\r
+  <li> <strong>'Tempo'</strong> control is implemented purely by\r
+time-stretching.</li>\r
+  <li> <strong>'Rate</strong>' control is implemented purely by sample\r
+rate transposing.</li>\r
+  <li> <strong>'Pitch</strong>' control is implemented as a\r
+combination of time-stretching and sample rate transposing. For\r
+example, to increase pitch the audio stream is first time-stretched to\r
+longer duration (without affecting pitch) and then transposed back to\r
+original duration by sample rate transposing, which simultaneously\r
+reduces duration and increases pitch. The result is original duration\r
+but increased pitch.</li>\r
+</ul>\r
+<h3>3.4 Tuning the algorithm parameters</h3>\r
+<p>The time-stretch algorithm has few parameters that can be tuned to\r
+optimize sound quality for certain application. The current default\r
+parameters have been chosen by iterative if-then analysis (read: "trial\r
+and error") to obtain best subjective sound quality in pop/rock music\r
+processing, but in applications processing different kind of sound the\r
+default parameter set may result into a sub-optimal result.</p>\r
+<p>The time-stretch algorithm default parameter values are set by the\r
+following #defines in file "TDStretch.h":</p>\r
+<blockquote>\r
+  <pre>#define DEFAULT_SEQUENCE_MS     AUTOMATIC<br>#define DEFAULT_SEEKWINDOW_MS   AUTOMATIC<br>#define DEFAULT_OVERLAP_MS      8</pre>\r
+</blockquote>\r
+<p>These parameters affect to the time-stretch algorithm as follows:</p>\r
+<ul>\r
+  <li> <strong>DEFAULT_SEQUENCE_MS</strong>: This is the default\r
+length of a single processing sequence in milliseconds which determines\r
+the how the original sound is chopped in the time-stretch algorithm.\r
+Larger values mean fewer sequences are used in processing. In principle\r
+a larger value sounds better when slowing down the tempo, but worse\r
+when increasing the tempo and vice versa.<br>\r
+    <br>\r
+By default, this setting value is calculated automatically according to\r
+tempo value.<br>\r
+ </li>\r
+  <li> <strong>DEFAULT_SEEKWINDOW_MS</strong>: The seeking window\r
+default length in milliseconds is for the algorithm that seeks the best\r
+possible overlapping location. This determines from how wide a sample\r
+"window" the algorithm can use to find an optimal mixing location when\r
+the sound sequences are to be linked back together.<br>\r
+    <br>\r
+The bigger this window setting is, the higher the possibility to find a\r
+better mixing position becomes, but at the same time large values may\r
+cause a "drifting" sound artifact because neighboring sequences can be\r
+chosen at more uneven intervals. If there's a disturbing artifact that\r
+sounds as if a constant frequency was drifting around, try reducing\r
+this setting.<br>\r
+    <br>\r
+By default, this setting value is calculated automatically according to\r
+tempo value.<br>\r
+ </li>\r
+  <li> <strong>DEFAULT_OVERLAP_MS</strong>: Overlap length in\r
+milliseconds. When the sound sequences are mixed back together to form\r
+again a continuous sound stream, this parameter defines how much the\r
+ends of the consecutive sequences will overlap with each other.<br>\r
+    <br>\r
+This shouldn't be that critical parameter. If you reduce the\r
+DEFAULT_SEQUENCE_MS setting by a large amount, you might wish to try a\r
+smaller value on this.</li>\r
+</ul>\r
+<p>Notice that these parameters can also be set during execution time\r
+with functions "<strong>TDStretch::setParameters()</strong>" and "<strong>SoundTouch::setSetting()</strong>".</p>\r
+<p>The table below summaries how the parameters can be adjusted for\r
+different applications:</p>\r
+<table border="1">\r
+  <tbody>\r
+    <tr>\r
+      <td valign="top"><strong>Parameter name</strong></td>\r
+      <td valign="top"><strong>Default value magnitude</strong></td>\r
+      <td valign="top"><strong>Larger value affects...</strong></td>\r
+      <td valign="top"><strong>Smaller value affects...</strong></td>\r
+      <td valign="top"><strong>Effect to CPU burden</strong></td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>SEQUENCE_MS</pre>\r
+      </td>\r
+      <td valign="top">Default value is relatively large, chosen for\r
+slowing down music tempo</td>\r
+      <td valign="top">Larger value is usually better for slowing down\r
+tempo. Growing the value decelerates the "echoing" artifact when\r
+slowing down the tempo.</td>\r
+      <td valign="top">Smaller value might be better for speeding up\r
+tempo. Reducing the value accelerates the "echoing" artifact when\r
+slowing down the tempo </td>\r
+      <td valign="top">Increasing the parameter value reduces\r
+computation burden</td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>SEEKWINDOW_MS</pre>\r
+      </td>\r
+      <td valign="top">Default value is relatively large, chosen for\r
+slowing down music tempo</td>\r
+      <td valign="top">Larger value eases finding a good mixing\r
+position, but may cause a "drifting" artifact</td>\r
+      <td valign="top">Smaller reduce possibility to find a good mixing\r
+position, but reduce the "drifting" artifact.</td>\r
+      <td valign="top">Increasing the parameter value increases\r
+computation burden</td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>OVERLAP_MS</pre>\r
+      </td>\r
+      <td valign="top">Default value is relatively large, chosen to\r
+suit with above parameters.</td>\r
+      <td valign="top"></td>\r
+      <td valign="top">If you reduce the "sequence ms" setting, you\r
+might wish to try a smaller value.</td>\r
+      <td valign="top">Increasing the parameter value increases\r
+computation burden</td>\r
+    </tr>\r
+  </tbody>\r
+</table>\r
+<h3>3.5 Performance Optimizations </h3>\r
+<p><strong>General optimizations:</strong></p>\r
+<p>The time-stretch routine has a 'quick' mode that substantially\r
+speeds up the algorithm but may slightly compromise the sound quality. \r
+This mode is activated by calling SoundTouch::setSetting()\r
+function with parameter id of SETTING_USE_QUICKSEEK and value\r
+"1", i.e. </p>\r
+<blockquote>\r
+  <p>setSetting(SETTING_USE_QUICKSEEK, 1);</p>\r
+</blockquote>\r
+<p><strong>CPU-specific optimizations:</strong></p>\r
+<p>Intel x86 specific SIMD optimizations are implemented using compiler \r
+intrinsics, providing about a 3x processing speedup for x86 compatible \r
+processors vs. non-SIMD implementation:</p>\r
+<ul>\r
+    <li> Intel MMX optimized routines are used with x86 CPUs when 16bit integer \r
+    sample type is used</li>\r
+  <li> Intel SSE optimized routines are used with x86 CPUs when 32bit floating \r
+  point sample type is used</li>\r
+</ul>\r
+<h3>3.5 OpenMP parallel computation</h3>\r
+<p>SoundTouch 1.9 onwards support running the algorithms parallel in several CPU \r
+cores. Based on benchmark the experienced multi-core processing speed-up gain \r
+ranges between +30% (on a high-spec dual-core x86 Windows PC) to 215% (on a moderately low-spec \r
+quad-core ARM of Raspberry Pi2). </p>\r
+<p>See an external blog article with more detailed discussion about the\r
+<a href="http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices/">\r
+SoundTouch OpenMP optimization</a>.</p>\r
+<p>The parallel computing support is implemented using OpenMP spec 3.0 \r
+instructions. These instructions are supported by Visual C++ 2008 and later, and \r
+GCC v4.2 and later. Compilers that do not supporting OpenMP will ignore these \r
+optimizations and routines will still work properly. Possible warnings about \r
+unknown #pragmas are related to OpenMP support and can be safely ignored.</p>\r
+<p>The OpenMP improvements are disabled by default, and need to be enabled by \r
+developer during compile-time. Reason for this is that parallel processing adds \r
+moderate runtime overhead in managing the multi-threading, so it may not be \r
+necessary nor desirable in all applications. For example real-time processing \r
+that is not constrained by CPU power will not benefit of speed-up provided by \r
+the parallel processing, in the contrary it may increase power consumption due \r
+to the increased overhead.</p>\r
+<p>However, applications that run on low-spec multi-core CPUs and may otherwise \r
+have possibly constrained performance will benefit of the OpenMP improvements. \r
+This include for example multi-core embedded devices.</p>\r
+<p>OpenMP parallel computation can be enabled before compiling SoundTouch \r
+library as follows:</p>\r
+<ul>\r
+    <li><strong>Visual Studio</strong>: Open properties for the <strong>SoundTouch\r
+    </strong>sub-project, browse to <strong>C/C++</strong> and <strong>Language \r
+    </strong>settings. Set \r
+    there &quot;<strong>OpenMP support</strong>&quot; to &quot;<strong>Yes</strong>&quot;. Alternatively add \r
+    <strong>/openmp</strong> switch to command-line \r
+    parameters</li>\r
+    <li><strong>GNU</strong>: Run the configure script with &quot;<strong>./configure \r
+    --enable-openmp</strong>&quot; switch, then run make as usually</li>\r
+    <li><strong>Android</strong>: Add &quot;<strong>-fopenmp</strong>&quot; switches to compiler &amp; linker \r
+    options, see README-SoundTouch-Android.html in the source code package for \r
+    more detailed instructions.</li>\r
+</ul>\r
+<hr>\r
+<h2><a name="SoundStretch"></a>4. SoundStretch audio processing utility\r
+</h2>\r
+<p>SoundStretch audio processing utility<br>\r
+    Copyright (c) Olli Parviainen 2002-2015</p>\r
+<p>SoundStretch is a simple command-line application that can change\r
+tempo, pitch and playback rates of WAV sound files. This program is\r
+intended primarily to demonstrate how the "SoundTouch" library can be\r
+used to process sound in your own program, but it can as well be used\r
+for processing sound files.</p>\r
+<h3>4.1. SoundStretch Usage Instructions</h3>\r
+<p>SoundStretch Usage syntax:</p>\r
+<blockquote>\r
+  <pre>soundstretch infilename outfilename [switches]</pre>\r
+</blockquote>\r
+<p>Where: </p>\r
+<table width="100%" border="0" cellpadding="2">\r
+  <tbody>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>"infilename"</pre>\r
+      </td>\r
+      <td valign="top">Name of the input sound data file (in .WAV audio\r
+file format). Give "stdin" as filename to use standard input pipe. </td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>"outfilename"</pre>\r
+      </td>\r
+      <td valign="top">Name of the output sound file where the\r
+resulting sound is saved (in .WAV audio file format). This parameter\r
+may be omitted if you don't want to save the output (e.g. when\r
+only calculating BPM rate with '-bpm' switch). Give "stdout" as\r
+filename to use standard output pipe.</td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>[switches]</pre>\r
+      </td>\r
+      <td valign="top">Are one or more control switches.</td>\r
+    </tr>\r
+  </tbody>\r
+</table>\r
+<p>Available control switches are:</p>\r
+<table width="100%" border="0" cellpadding="2">\r
+  <tbody>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>-tempo=n </pre>\r
+      </td>\r
+      <td valign="top">Change the sound tempo by n percents (n = -95.0\r
+.. +5000.0 %) </td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>-pitch=n</pre>\r
+      </td>\r
+      <td valign="top">Change the sound pitch by n semitones (n = -60.0\r
+.. + 60.0 semitones) </td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>-rate=n</pre>\r
+      </td>\r
+      <td valign="top">Change the sound playback rate by n percents (n\r
+= -95.0 .. +5000.0 %) </td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>-bpm=n</pre>\r
+      </td>\r
+      <td valign="top">Detect the Beats-Per-Minute (BPM) rate of the\r
+sound and adjust the tempo to meet 'n' BPMs. When this switch is\r
+applied, the "-tempo" switch is ignored. If "=n" is omitted, i.e.\r
+switch "-bpm" is used alone, then the BPM rate is estimated and\r
+displayed, but tempo not adjusted according to the BPM value. </td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>-quick</pre>\r
+      </td>\r
+      <td valign="top">Use quicker tempo change algorithm. Gains speed\r
+but loses sound quality. </td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>-naa</pre>\r
+      </td>\r
+      <td valign="top">Don't use anti-alias filtering in sample rate\r
+transposing. Gains speed but loses sound quality. </td>\r
+    </tr>\r
+    <tr>\r
+      <td valign="top">\r
+      <pre>-license</pre>\r
+      </td>\r
+      <td valign="top">Displays the program license text (LGPL)</td>\r
+    </tr>\r
+  </tbody>\r
+</table>\r
+<p>Notes:</p>\r
+<ul>\r
+  <li> To use standard input/output pipes for processing, give "stdin"\r
+and "stdout" as input/output filenames correspondingly. The standard\r
+input/output pipes will still carry the audio data in .wav audio file\r
+format.</li>\r
+  <li> The numerical switches allow both integer (e.g. "-tempo=123")\r
+and decimal (e.g. "-tempo=123.45") numbers.</li>\r
+  <li> The "-naa" and/or "-quick" switches can be used to reduce CPU\r
+usage while compromising some sound quality</li>\r
+  <li> The BPM detection algorithm works by detecting repeating bass or\r
+drum patterns at low frequencies of &lt;250Hz. A lower-than-expected\r
+BPM figure may be reported for music with uneven or complex bass\r
+patterns.</li>\r
+</ul>\r
+<h3>4.2. SoundStretch usage examples </h3>\r
+<p><strong>Example 1</strong></p>\r
+<p>The following command increases tempo of the sound file\r
+"originalfile.wav" by 12.5% and stores result to file\r
+"destinationfile.wav":</p>\r
+<blockquote>\r
+  <pre>soundstretch originalfile.wav destinationfile.wav -tempo=12.5</pre>\r
+</blockquote>\r
+<p><strong>Example 2</strong></p>\r
+<p>The following command decreases the sound pitch (key) of the sound\r
+file "orig.wav" by two semitones and stores the result to file\r
+"dest.wav":</p>\r
+<blockquote>\r
+  <pre>soundstretch orig.wav dest.wav -pitch=-2</pre>\r
+</blockquote>\r
+<p><strong>Example 3</strong></p>\r
+<p>The following command processes the file "orig.wav" by decreasing\r
+the sound tempo by 25.3% and increasing the sound pitch (key) by 1.5\r
+semitones. Resulting .wav audio data is directed to standard output\r
+pipe:</p>\r
+<blockquote>\r
+  <pre>soundstretch orig.wav stdout -tempo=-25.3 -pitch=1.5</pre>\r
+</blockquote>\r
+<p><strong>Example 4</strong></p>\r
+<p>The following command detects the BPM rate of the file "orig.wav"\r
+and adjusts the tempo to match 100 beats per minute. Result is stored\r
+to file "dest.wav":</p>\r
+<blockquote>\r
+  <pre>soundstretch orig.wav dest.wav -bpm=100</pre>\r
+</blockquote>\r
+<p><strong>Example 5</strong></p>\r
+<p>The following command reads .wav sound data from standard input pipe\r
+and estimates the BPM rate:</p>\r
+<blockquote>\r
+  <pre>soundstretch stdin -bpm</pre>\r
+</blockquote>\r
+<p><strong>Example 6</strong></p>\r
+<p>The following command tunes song from original 440Hz tuning to 432Hz tuning: \r
+this corresponds to lowering the pitch by -0.318 semitones:</p>\r
+<blockquote>\r
+  <pre>soundstretch original.wav output.wav -pitch=-0.318</pre>\r
+</blockquote>\r
+<hr>\r
+<h2>5. Change History</h2>\r
+<h3>5.1. SoundTouch library Change History </h3>\r
+    <p><b>2.1:</b></p>\r
+    <ul>\r
+      <li>Refactored C# interface example</li>\r
+      <li>Disable anti-alias filter when switch \r
+      SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER defined because anti-alias \r
+      filter cause slight click if the rate change crosses zero during \r
+      processing</li>\r
+      <li>Added script for building SoundTouchDll dynamic-link-library for GNU platforms</li>\r
+      <li>Rewrote Beats-per-Minute analysis algorithm for more reliable BPM detection</li>\r
+      <li>Added BPM functions to SoundTouchDll API</li>\r
+      <li>Migrated Visual Studio project files to MSVC 201x format</li>\r
+      <li>Replaced function parameter value asserts with runtime exceptions</li>\r
+      <li>Code maintenance & style cleanup</li>\r
+    </ul>\r
+    <p><b>2.0:</b></p>\r
+    <ul>\r
+        <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>\r
+        <li>Fixed issue that added brief sequence of silence to beginning of output audio</li>\r
+        <li>Adjusted algorithm parameters to reduce reverberating effect at tempo slowdown</li>\r
+        <li>Bugfix: Fixed a glitch that could cause negative array indexing in quick seek algorithm</li>\r
+        <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>\r
+        <li>Bugfix: Pi value had incorrect 9th/10th decimals</li>\r
+        <li>Added C# example application that uses SoundTouch dll library for processing MP3 files</li>\r
+    </ul>\r
+    <p><b>1.9.2:</b></p>\r
+    <ul>\r
+        <li>Fix in GNU package configuration</li>\r
+    </ul>\r
+    <p><b>1.9.1:</b></p>\r
+    <ul>\r
+        <li>Improved SoundTouch::flush() function so that it returns precisely the desired amount of samples for exact output duration control</li>\r
+        <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 \r
+        default full-scan mode, while the quickseek algorithm is remarkable less \r
+        CPU intensive.</li>\r
+        <li>Added adaptive integer divider scaling for improved sound quality when using integer processing algorithm\r
+        </li>\r
+    </ul>\r
+<p><b>1.9:</b></p>\r
+<ul>\r
+    <li>Added support for parallel computation support via OpenMP primitives for better performance in multicore systems. \r
+        Benchmarks show that achieved parallel processing speedup improvement \r
+    typically range from +30% (x86 dual-core) to +180% (ARM quad-core). The \r
+    OpenMP optimizations are disabled by default, see OpenMP notes above in this \r
+    readme file how to enabled these optimizations.</li>\r
+    <li>Android: Added support for Android devices featuring X86 and MIPS CPUs, \r
+    in addition to ARM CPUs.</li>\r
+    <li>Android: More versatile Android example application that processes WAV \r
+    audio files with SoundTouch library</li>\r
+    <li>Replaced Windows-like 'BOOL' types with native 'bool'</li>\r
+    <li>Changed documentation token to "dist_doc_DATA" in Makefile.am file</li>\r
+    <li>Miscellaneous small fixes and improvements</li>\r
+</ul>\r
+<p><b>1.8.0:</b></p>\r
+<ul>\r
+    <li>Added support for multi-channel audio processing</li>\r
+    <li>Added support for <b>cubic</b> and <b>shannon</b> interpolation for rate and pitch shift effects besides \r
+        the original <b>linear</b> interpolation, to reduce aliasing at high frequencies due to interpolation.\r
+        Cubic interpolation is used as default for floating point processing, and linear interpolation for integer \r
+        processing.</li>\r
+    <li>Fixed bug in anti-alias filtering that limited stop-band attenuation to -10 dB instead of <-50dB, and\r
+        increased filter length from 32 to 64 taps to further reduce aliasing due to frequency folding.</li>\r
+    <li>Performance improvements in cross-correlation algorithm</li>\r
+    <li>Other bug and compatibility fixes</li>\r
+</ul>\r
+<p><b>1.7.1:</b></p>\r
+<ul>\r
+    <li>Added files for Android compilation\r
+</ul>\r
+<p><b>1.7.0:</b></p>\r
+<ul>\r
+    <li>Sound quality improvements/li>\r
+    <li>Improved flush() to adjust output sound stream duration to match better with \r
+        ideal duration</li>\r
+    <li>Rewrote x86 cpu feature check to resolve compatibility problems</li>\r
+    <li>Configure script automatically checks if CPU supports mmx & sse compatibility for GNU platform, and\r
+    the script support now "--enable-x86-optimizations" switch to allow disabling x86-specific optimizations.</li>\r
+    <li>Revised #define conditions for 32bit/64bit compatibility</li>\r
+    <li>gnu autoconf/automake script compatibility fixes</li>\r
+    <li>Tuned beat-per-minute detection algorithm</li>\r
+</ul>\r
+<p><b>1.6.0:</b></p>\r
+<ul>\r
+  <li> Added automatic cutoff threshold adaptation to beat detection\r
+routine to better adapt BPM calculation to different types of music</li>\r
+  <li> Retired 3DNow! optimization support as 3DNow! is nowadays\r
+obsoleted and assembler code is nuisance to maintain</li>\r
+  <li>Retired "configure" file from source code package due to\r
+autoconf/automake versio conflicts, so that it is from now on to be\r
+generated by invoking "boostrap" script that uses locally available\r
+toolchain version for generating the "configure" file</li>\r
+  <li>Resolved namespace/label naming conflicts with other libraries by\r
+replacing global labels such as INTEGER_SAMPLES with more specific\r
+SOUNDTOUCH_INTEGER_SAMPLES etc.<br>\r
+ </li>\r
+  <li>Updated windows build scripts &amp; project files for Visual\r
+Studio 2008 support</li>\r
+  <li> Updated SoundTouch.dll API for .NET compatibility</li>\r
+  <li> Added API for querying nominal processing input &amp; output\r
+sample batch sizes</li>\r
+</ul>\r
+<p><strong>1.5.0:</strong></p>\r
+<ul>\r
+  <li> Added normalization to correlation calculation and improvement\r
+automatic seek/sequence parameter calculation to improve sound quality</li>\r
+  <li> Bugfixes:\r
+    <ul>\r
+      <li> Fixed negative array indexing in quick seek algorithm</li>\r
+      <li> FIR autoalias filter running too far in processing buffer</li>\r
+      <li> Check against zero sample count in rate transposing</li>\r
+      <li> Fix for x86-64 support: Removed pop/push instructions from\r
+the cpu detection algorithm.</li>\r
+      <li> Check against empty buffers in FIFOSampleBuffer</li>\r
+      <li> Other minor fixes &amp; code cleanup</li>\r
+    </ul>\r
+ </li>\r
+  <li> Fixes in compilation scripts for non-Intel platforms</li>\r
+  <li> Added Dynamic-Link-Library (DLL) version of SoundTouch library\r
+build, provided with Delphi/Pascal wrapper for calling the dll routines\r
+ </li>\r
+  <li> Added #define PREVENT_CLICK_AT_RATE_CROSSOVER that prevents a\r
+click artifact when crossing the nominal pitch from either positive to\r
+negative side or vice versa</li>\r
+</ul>\r
+<p><strong>1.4.1:</strong></p>\r
+<ul>\r
+  <li> Fixed a buffer overflow bug in BPM detect algorithm routines if\r
+processing more than 2048 samples at one call</li>\r
+</ul>\r
+<p><strong>1.4.0:</strong></p>\r
+<ul>\r
+  <li> Improved sound quality by automatic calculation of time stretch\r
+algorithm processing parameters according to tempo setting</li>\r
+  <li> Moved BPM detection routines from SoundStretch application into\r
+SoundTouch library</li>\r
+  <li> Bugfixes: Usage of uninitialied variables, GNU build scripts,\r
+compiler errors due to 'const' keyword mismatch.</li>\r
+  <li> Source code cleanup</li>\r
+</ul>\r
+<p><strong>1.3.1: </strong> </p>\r
+<ul>\r
+  <li> Changed static class declaration to GCC 4.x compiler compatible\r
+syntax.</li>\r
+  <li> Enabled MMX/SSE-optimized routines also for GCC compilers.\r
+Earlier the MMX/SSE-optimized routines were written in\r
+compiler-specific inline assembler, now these routines are migrated to\r
+use compiler intrinsic syntax which allows compiling the same\r
+MMX/SSE-optimized source code with both Visual C++ and GCC compilers.</li>\r
+  <li> Set floating point as the default sample format and added switch\r
+to the GNU configure script for selecting the other sample format.</li>\r
+</ul>\r
+<p><strong>1.3.0: </strong> </p>\r
+<ul>\r
+  <li> Fixed tempo routine output duration inaccuracy due to rounding\r
+error</li>\r
+  <li> Implemented separate processing routines for integer and\r
+floating arithmetic to allow improvements to floating point routines\r
+(earlier used algorithms mostly optimized for integer arithmetic also\r
+for floating point samples)</li>\r
+  <li> Fixed a bug that distorts sound if sample rate changes during\r
+the sound stream</li>\r
+  <li> Fixed a memory leak that appeared in MMX/SSE/3DNow! optimized\r
+routines</li>\r
+  <li> Reduced redundant code pieces in MMX/SSE/3DNow! optimized\r
+routines vs. the standard C routines.</li>\r
+  <li> MMX routine incompatibility with new gcc compiler versions</li>\r
+  <li> Other miscellaneous bug fixes</li>\r
+</ul>\r
+<p><strong>1.2.1: </strong> </p>\r
+<ul>\r
+  <li> Added automake/autoconf scripts for GNU platforms (in courtesy\r
+of David Durham)</li>\r
+  <li> Fixed SCALE overflow bug in rate transposer routine.</li>\r
+  <li> Fixed 64bit address space bugs.</li>\r
+  <li> Created a 'soundtouch' namespace for SAMPLETYPE definitions.</li>\r
+</ul>\r
+<p><strong>1.2.0: </strong> </p>\r
+<ul>\r
+  <li> Added support for 32bit floating point sample data type with\r
+SSE/3DNow! optimizations for Win32 platform (SSE/3DNow! optimizations\r
+currently not supported in GCC environment)</li>\r
+  <li> Replaced 'make-gcc' script for GNU environment by master\r
+Makefile</li>\r
+  <li> Added time-stretch routine configurability to SoundTouch main\r
+class</li>\r
+  <li> Bugfixes</li>\r
+</ul>\r
+<p><strong>1.1.1: </strong> </p>\r
+<ul>\r
+  <li> Moved SoundTouch under lesser GPL license (LGPL). This allows\r
+using SoundTouch library in programs that aren't released under GPL\r
+license.</li>\r
+  <li> Changed MMX routine organiation so that MMX optimized routines\r
+are now implemented in classes that are derived from the basic classes\r
+having the standard non-mmx routines.</li>\r
+  <li> MMX routines to support gcc version 3.</li>\r
+  <li> Replaced windows makefiles by script using the .dsw files</li>\r
+</ul>\r
+<p><strong>1.0.1: </strong> </p>\r
+<ul>\r
+  <li> "mmx_gcc.cpp": Added "using namespace std" and removed "return\r
+0" from a function with void return value to fix compiler errors when\r
+compiling the library in Solaris environment.</li>\r
+  <li> Moved file "FIFOSampleBuffer.h" to "include" directory to allow\r
+accessing the FIFOSampleBuffer class from external files.</li>\r
+</ul>\r
+<p><strong>1.0: </strong> </p>\r
+<ul>\r
+  <li> Initial release</li>\r
+</ul>\r
+<h3>5.2. SoundStretch application Change History </h3>\r
+<p><b>1.9:</b></p>\r
+<ul>\r
+    <li>Added support for WAV file 'fact' information chunk.</li>\r
+</ul>\r
+\r
+<p><b>1.7.0:</b></p>\r
+<ul>\r
+    <li>Bugfixes in Wavfile: exception string formatting, avoid getLengthMs() integer \r
+        precision overflow, support WAV files using 24/32bit sample format.</li>\r
+</ul>\r
+    <p><b>1.5.0:</b></p>\r
+<ul>\r
+  <li> Added "-speech" switch to activate algorithm parameters more\r
+suitable for speech processing than the default parameters tuned for\r
+music processing.</li>\r
+</ul>\r
+<p><strong>1.4.0:</strong></p>\r
+<ul>\r
+  <li> Moved BPM detection routines from SoundStretch application into\r
+SoundTouch library</li>\r
+  <li> Allow using standard input/output pipes as audio processing\r
+input/output streams</li>\r
+</ul>\r
+<p><strong>1.3.0:</strong></p>\r
+<ul>\r
+  <li> Simplified accessing WAV files with floating point sample\r
+format.</li>\r
+</ul>\r
+<p><strong>1.2.1: </strong> </p>\r
+<ul>\r
+  <li> Fixed 64bit address space bugs.</li>\r
+</ul>\r
+<p><strong>1.2.0: </strong> </p>\r
+<ul>\r
+  <li> Added support for 32bit floating point sample data type</li>\r
+  <li> Restructured the BPM routines into separate library</li>\r
+  <li> Fixed big-endian conversion bugs in WAV file routines (hopefully\r
+:)</li>\r
+</ul>\r
+<p><strong>1.1.1: </strong> </p>\r
+<ul>\r
+  <li> Fixed bugs in WAV file reading &amp; added byte-order conversion\r
+for big-endian processors.</li>\r
+  <li> Moved SoundStretch source code under 'example' directory to\r
+highlight difference from SoundTouch stuff.</li>\r
+  <li> Replaced windows makefiles by script using the .dsw files</li>\r
+  <li> Output file name isn't required if output isn't desired (e.g. if\r
+using the switch '-bpm' in plain format only)</li>\r
+</ul>\r
+<p><strong>1.1:</strong></p>\r
+<ul>\r
+  <li> Fixed "Release" settings in Microsoft Visual C++ project file\r
+(.dsp)</li>\r
+  <li> Added beats-per-minute (BPM) detection routine and command-line\r
+switch "-bpm"</li>\r
+</ul>\r
+<p><strong>1.01: </strong> </p>\r
+<ul>\r
+  <li> Initial release</li>\r
+</ul>\r
+<hr>\r
+<h2>6. Acknowledgements </h2>\r
+<p>Kudos for these people who have contributed to development or\r
+submitted bugfixes:</p>\r
+<ul>\r
+  <li> Arthur A</li>\r
+  <li> Paul Adenot</li>\r
+  <li> Richard Ash</li>\r
+  <li> Stanislav Brabec</li>\r
+  <li> Christian Budde</li>\r
+  <li> Jamie Bullock</li>\r
+  <li> Chris Bryan</li>  \r
+  <li> Jacek Caban</li>\r
+  <li> Brian Cameron</li>\r
+  <li> Jason Champion</li>\r
+  <li> David Clark</li>\r
+  <li> Patrick Colis</li>\r
+  <li> Miquel Colon</li>\r
+  <li> Jim Credland</li>\r
+  <li> Sandro Cumerlato</li>\r
+  <li> Justin Frankel</li>\r
+  <li> Masa H.</li>\r
+  <li> Jason Garland</li>\r
+  <li> Takashi Iwai</li>\r
+  <li> Thomas Klausner</li>\r
+  <li> Lu Zhihe</li>\r
+       <li> Luzpaz</li>\r
+  <li> Tony Mechelynck </li>\r
+  <li> Mathias M&ouml;hl</li>\r
+  <li> Yuval Naveh</li>\r
+  <li> Mats Palmgren </li>\r
+  <li> Chandni Patel</li>\r
+  <li> Paulo Pizarro</li>\r
+  <li> Andrey Ponomarenko</li>\r
+  <li> Blaise Potard</li>\r
+  <li> Michael Pruett</li>\r
+  <li> Rajeev Puran</li>\r
+  <li> RJ Ryan</li>\r
+  <li> John Sheehy</li>\r
+  <li> Tim Shuttleworth</li>\r
+  <li> Albert Sirvent</li>\r
+  <li> Tyson Smith</li>\r
+  <li> John Stumpo</li>\r
+  <li> Mario di Vece</li>\r
+  <li> Katja Vetter</li>\r
+  <li> Wu Q.</li>\r
+</ul>\r
+<p>Moral greetings to all other contributors and users also!</p>\r
+<hr>\r
+<h2>7. LICENSE </h2>\r
+<p>SoundTouch audio processing library<br>\r
+Copyright (c) Olli Parviainen</p>\r
+<p>This library is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU Lesser General Public License version 2.1\r
+as published by the Free Software Foundation.</p>\r
+<p>This library is distributed in the hope that it will be useful, but\r
+WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser\r
+General Public License for more details.</p>\r
+<p>You should have received a copy of the GNU Lesser General Public\r
+License along with this library; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA</p>\r
+<p>---</p>\r
+<p>commercial license alternative also available, contact author for details.</p>\r
+<hr>\r
+<p><i>README.html file updated in May-2018</i></p>\r
+</body>\r
+</html>\r
diff --git a/bin/run_test b/bin/run_test
new file mode 100755 (executable)
index 0000000..f7d0cf1
--- /dev/null
@@ -0,0 +1,21 @@
+SOUND_DIR=~/dev/test_sounds
+OUT_DIR=./test_out
+TEST_NAME=semmari
+OUT_NAME=out
+SS=./soundstretch
+TEST_PARAM="-pitch=-3 -bpm"
+
+mkdir $OUT_DIR
+
+$SS $SOUND_DIR/$TEST_NAME-8b1.wav $OUT_DIR/$OUT_NAME-8b1.wav $TEST_PARAM
+$SS $SOUND_DIR/$TEST_NAME-8b2.wav $OUT_DIR/$OUT_NAME-8b2.wav $TEST_PARAM
+
+$SS $SOUND_DIR/$TEST_NAME-16b1.wav $OUT_DIR/$OUT_NAME-16b1.wav $TEST_PARAM
+$SS $SOUND_DIR/$TEST_NAME-16b2.wav $OUT_DIR/$OUT_NAME-16b2.wav $TEST_PARAM
+
+$SS $SOUND_DIR/$TEST_NAME-24b1.wav $OUT_DIR/$OUT_NAME-24b1.wav $TEST_PARAM
+$SS $SOUND_DIR/$TEST_NAME-24b2.wav $OUT_DIR/$OUT_NAME-24b2.wav $TEST_PARAM
+
+$SS $SOUND_DIR/$TEST_NAME-32b1.wav $OUT_DIR/$OUT_NAME-32b1.wav $TEST_PARAM
+$SS $SOUND_DIR/$TEST_NAME-32b2.wav $OUT_DIR/$OUT_NAME-32b2.wav $TEST_PARAM
+
diff --git a/bin/run_test.cmd b/bin/run_test.cmd
new file mode 100644 (file)
index 0000000..0af8672
--- /dev/null
@@ -0,0 +1,19 @@
+set SOUND_DIR=d:\dev\test_sounds\r
+set OUT_DIR=.\r
+set TEST_NAME=semmari\r
+set OUT_NAME=out\r
+set SS=soundstretch\r
+set TEST_PARAM=-pitch=-3 -bpm\r
+\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-8b1.wav %OUT_DIR%\%OUT_NAME%-8b1.wav %TEST_PARAM%\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-8b2.wav %OUT_DIR%\%OUT_NAME%-8b2.wav %TEST_PARAM%\r
+\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-16b1.wav %OUT_DIR%\%OUT_NAME%-16b1.wav %TEST_PARAM%\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-16b2.wav %OUT_DIR%\%OUT_NAME%-16b2.wav %TEST_PARAM%\r
+\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-24b1.wav %OUT_DIR%\%OUT_NAME%-24b1.wav %TEST_PARAM%\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-24b2.wav %OUT_DIR%\%OUT_NAME%-24b2.wav %TEST_PARAM%\r
+\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-32b1.wav %OUT_DIR%\%OUT_NAME%-32b1.wav %TEST_PARAM%\r
+call %SS% %SOUND_DIR%\%TEST_NAME%-32b2.wav %OUT_DIR%\%OUT_NAME%-32b2.wav %TEST_PARAM%\r
+\r
diff --git a/bootstrap b/bootstrap
new file mode 100755 (executable)
index 0000000..67bcbea
--- /dev/null
+++ b/bootstrap
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+if [ "$1" = "--clean" ]
+then
+       if [ -a Makefile ]
+       then
+               make maintainer-clean
+       elif [ -a configure ]
+       then
+               configure && $0 --clean
+       else 
+               bootstrap && configure && $0 --clean
+       fi
+
+       rm -rf configure libtool aclocal.m4 `find . -name Makefile.in` autom4te*.cache config/config.guess config/config.h.in config/config.sub config/depcomp config/install-sh config/ltmain.sh config/missing config/mkinstalldirs config/stamp-h config/stamp-h.in
+
+       #gettextie files
+       #rm -f ABOUT-NLS config/config.rpath config/m4/codeset.m4 config/m4/gettext.m4 config/m4/glibc21.m4 config/m4/iconv.m4 config/m4/intdiv0.m4 config/m4/inttypes-pri.m4 config/m4/inttypes.m4 config/m4/inttypes_h.m4 config/m4/isc-posix.m4 config/m4/lcmessage.m4 config/m4/lib-ld.m4 config/m4/lib-link.m4 config/m4/lib-prefix.m4 config/m4/progtest.m4 config/m4/stdint_h.m4 config/m4/uintmax_t.m4 config/m4/ulonglong.m4 po/Makefile.in.in po/Rules-quot po/boldquot.sed po/en@boldquot.header po/en@quot.header po/insert-header.sin po/quot.sed po/remove-potcdate.sin 
+
+else
+       export AUTOMAKE="automake --add-missing --foreign --copy"
+       autoreconf -fisv && rm -f `find . -name "*~"` && rm -f ChangeLog
+       exit $?
+fi
diff --git a/config/README.TXT b/config/README.TXT
new file mode 100644 (file)
index 0000000..7c4f6e4
--- /dev/null
@@ -0,0 +1,3 @@
+Files in this directory are used by GNU autoconf/automake system.\r
+These files aren't used/needed in the Windows environment.\r
+\r
diff --git a/config/am_include.mk b/config/am_include.mk
new file mode 100644 (file)
index 0000000..5d6bdfb
--- /dev/null
@@ -0,0 +1,26 @@
+## vim:tw=78\r
+## Process this file with automake to create Makefile.in\r
+##\r
+## This file is part of SoundTouch, an audio processing library for pitch/time adjustments\r
+## \r
+## SoundTouch is free software; you can redistribute it and/or modify it under the\r
+## terms of the GNU General Public License as published by the Free Software\r
+## Foundation; either version 2 of the License, or (at your option) any later\r
+## version.\r
+## \r
+## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY\r
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+## A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r
+## \r
+## You should have received a copy of the GNU General Public License along with\r
+## this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
+## Place - Suite 330, Boston, MA  02111-1307, USA\r
+\r
+## These are common definitions used in all Makefiles\r
+## It is actually included when a makefile.am is converted to Makefile.in\r
+## by automake, so it's ok to have @MACROS@ that will be set by configure\r
+\r
+AM_CPPFLAGS=-I$(top_srcdir)/include\r
+\r
+# doc directory\r
+pkgdocdir=$(prefix)/doc/@PACKAGE@\r
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..bd8023c
--- /dev/null
@@ -0,0 +1,261 @@
+dnl This file is part of SoundTouch, an audio processing library for pitch/time adjustments
+dnl 
+dnl SoundTouch is free software; you can redistribute it and/or modify it under the
+dnl terms of the GNU General Public License as published by the Free Software
+dnl Foundation; either version 2 of the License, or (at your option) any later
+dnl version.
+dnl 
+dnl SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
+dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+dnl FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+dnl details.
+dnl 
+dnl You should have received a copy of the GNU General Public License along with
+dnl this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+dnl Place - Suite 330, Boston, MA  02111-1307, USA
+# Process this file with autoconf to produce a configure script.
+
+AC_INIT([SoundTouch], [2.0.0], [http://www.surina.net/soundtouch])
+dnl Default to libSoundTouch.so.$LIB_SONAME.0.0
+LIB_SONAME=1
+AC_SUBST(LIB_SONAME)
+
+AC_CONFIG_AUX_DIR(config)
+AC_CONFIG_MACRO_DIR([config/m4])
+AM_CONFIG_HEADER([config.h include/soundtouch_config.h])
+AM_INIT_AUTOMAKE
+AM_SILENT_RULES([yes])
+#AC_DISABLE_SHARED     dnl This makes libtool only build static libs 
+AC_DISABLE_STATIC      dnl This makes libtool only build shared libs
+#AC_GNU_SOURCE                 dnl enable posix extensions in glibc
+
+AC_LANG(C++)
+
+# Set AR_FLAGS to avoid build warning "ar: `u' modifier ignored since `D' is the default (see `U')"
+AR_FLAGS='cr'
+
+
+dnl ############################################################################
+dnl # Checks for programs                                                      #
+dnl ############################################################################
+AC_PROG_CXX
+#AC_PROG_AWK
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXXCPP
+AC_PROG_INSTALL
+#AC_PROG_LN_S
+AC_PROG_MAKE_SET
+
+AM_PROG_LIBTOOL dnl turn on using libtool
+
+
+
+
+dnl ############################################################################
+dnl # Checks for header files                                                  #
+dnl ############################################################################
+AC_HEADER_STDC
+#AC_HEADER_SYS_WAIT
+#      add any others you want to check for here
+AC_CHECK_HEADERS([cpuid.h])
+
+if test "x$ac_cv_header_cpuid_h" = "xno"; then
+       AC_MSG_WARN([The cpuid.h file was not found therefore the x86 optimizations will be disabled.])
+       AC_MSG_WARN([If using a x86 architecture and optimizations are desired then please install gcc (>= 4.3).])
+       AC_MSG_WARN([If using a non-x86 architecture then this is expected and can be ignored.])
+fi
+
+dnl ############################################################################
+dnl # Checks for typedefs, structures, and compiler characteristics            $
+dnl ############################################################################
+AC_C_CONST
+AC_C_INLINE
+#AC_TYPE_OFF_T
+#AC_TYPE_SIZE_T
+
+
+AC_ARG_ENABLE(integer-samples,
+              [AC_HELP_STRING([--enable-integer-samples],
+                              [use integer samples instead of floats
+[default=no]])],,
+              [enable_integer_samples=no])
+
+
+AC_ARG_ENABLE(openmp,
+              [AC_HELP_STRING([--enable-openmp],
+                              [use parallel multicore calculation through OpenMP [default=no]])],,
+              [enable_openmp=no])
+
+# Let the user enable/disable the x86 optimizations.
+# Useful when compiling on non-x86 architectures.
+AC_ARG_ENABLE([x86-optimizations],
+              [AS_HELP_STRING([--enable-x86-optimizations],
+                              [use MMX or SSE optimization
+[default=yes]])],[enable_x86_optimizations="${enableval}"],
+              [enable_x86_optimizations=yes])
+
+# Tell the Makefile.am if the user wants to disable optimizations.
+# Makefile.am will enable them by default if support is available.
+# Note: We check if optimizations are supported a few lines down.
+AM_CONDITIONAL([X86_OPTIMIZATIONS], [test "x$enable_x86_optimizations" = "xyes"])
+
+
+if test "x$enable_integer_samples" = "xyes"; then
+        echo "****** Integer sample type enabled ******"
+        AC_DEFINE(SOUNDTOUCH_INTEGER_SAMPLES,1,[Use Integer as Sample type])
+else
+        echo "****** Float sample type enabled ******"
+        AC_DEFINE(SOUNDTOUCH_FLOAT_SAMPLES,1,[Use Float as Sample type])
+fi
+
+
+if test "x$enable_openmp" = "xyes"; then
+        echo "****** openmp optimizations enabled ******"
+        AM_CXXFLAGS="-fopenmp $AM_CXXFLAGS"
+else
+        echo "****** openmp optimizations disabled ******"
+fi
+
+
+# Check if optimizations are supported in the system at build time.
+if test "x$enable_x86_optimizations" = "xyes" -a "x$ac_cv_header_cpuid_h" = "xyes"; then
+        echo "****** x86 optimizations enabled ******"
+
+       original_saved_CXXFLAGS=$CXXFLAGS
+       have_mmx_intrinsics=no
+       CXXFLAGS="-mmmx -Winline $CXXFLAGS"
+
+       # Check if the user can compile MMX code using intrinsics.
+       # GCC supports MMX intrinsics since version 3.3
+       # A more recent GCC (>= 4.3) is recommended.
+       AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+       #if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3))
+       #error "Need GCC >= 3.3 for MMX intrinsics"
+       #endif
+       #include <mmintrin.h>
+       int main () {
+           __m64 loop = _mm_cvtsi32_si64 (1);
+           return _mm_cvtsi64_si32 (loop);
+       }]])],[have_mmx_intrinsics=yes])
+       CXXFLAGS=$original_saved_CXXFLAGS
+
+       # Inform the user if we did or did not find MMX support.
+       #
+       # If we enable optimization and integer samples we only require MMX.
+       # Disable optimizations in the SSTypes.h file if this is not the case.
+       if test "x$have_mmx_intrinsics" = "xyes" ; then
+               echo "****** MMX support found ******"
+       else
+               echo "****** No MMX support found ******"
+               if test "x$enable_integer_samples" = "xyes"; then
+                       echo "****** Disabling optimizations. Using integer samples with no MMX support ******"
+                       CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
+               fi
+       fi
+
+
+       # SSE support
+       original_saved_CXXFLAGS=$CXXFLAGS
+       have_sse_intrinsics=no
+       CXXFLAGS="-msse -Winline $CXXFLAGS"
+
+       # Check if the user can compile SSE code using intrinsics.
+       # GCC supports SSE intrinsics since version 3.3
+       # A more recent GCC (>= 4.3) is recommended.
+       AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+       #if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 3))
+       #error "Need GCC >= 3.3 for SSE intrinsics"
+       #endif
+       #include <xmmintrin.h>
+       int main () {
+           _mm_setzero_ps();
+           return 0;
+       }]])],[have_sse_intrinsics=yes])
+       CXXFLAGS=$original_saved_CXXFLAGS
+
+       # Inform the user if we did or did not find SSE support.
+       #
+       # If we enable optimization and float samples we only require SSE.
+       # Disable optimizations in the SSTypes.h file if this is not the case.
+       if test "x$have_sse_intrinsics" = "xyes" ; then
+               echo "****** SSE support found ******"
+       else
+               echo "****** No SSE support found ******"
+               if test "x$enable_integer_samples" != "xyes"; then
+                       echo "****** Disabling optimizations. Using float samples with no SSE support ******"
+                       CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
+               fi
+       fi
+
+else
+       # Disable optimizations in SSTypes.h since the user requested it.
+        echo "****** x86 optimizations disabled ******"
+        CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
+fi
+
+# Set AM_CXXFLAGS
+AC_SUBST([AM_CXXFLAGS], [$AM_CXXFLAGS])
+
+# Empty default CXXFLAGS so user can set them if desirable
+#AC_SUBST([CXXFLAGS], [ ])
+
+
+# SSTypes.h by default enables optimizations. Those already got disabled if
+# the user requested for it or if the system does not support them.
+#
+# Now tell the Makefile.am the optimizations that are supported.
+# Note:
+# Makefile.am already knows if the user asked for optimizations. We apply
+# optimizations by default (if support is available) and then disable all of
+# them if the user requested it.
+AM_CONDITIONAL([HAVE_MMX], [test "x$have_mmx_intrinsics" = "xyes"])
+AM_CONDITIONAL([HAVE_SSE], [test "x$have_sse_intrinsics" = "xyes"])
+
+
+dnl ############################################################################
+dnl # Checks for library functions/classes                                     #
+dnl ############################################################################
+AC_FUNC_MALLOC
+AC_TYPE_SIGNAL
+
+dnl make -lm get added to the LIBS
+AC_CHECK_LIB(m, sqrt,,AC_MSG_ERROR([compatible libc math library not found])) 
+
+dnl add whatever functions you might want to check for here
+#AC_CHECK_FUNCS([floor ftruncate memmove memset mkdir modf pow realpath sqrt strchr strdup strerror strrchr strstr strtol])
+
+
+
+
+
+
+
+dnl ############################################################################
+dnl # Internationaliation and Localiation                                    #
+dnl ############################################################################
+#AM_GNU_GETTEXT_VERSION([0.11.5])
+#AM_GNU_GETTEXT([external])
+
+
+
+
+
+dnl ############################################################################
+dnl # Final                                                                    #
+dnl ############################################################################
+
+AC_CONFIG_FILES([
+       Makefile
+       source/Makefile
+               source/SoundTouch/Makefile
+               source/SoundStretch/Makefile
+       include/Makefile
+])
+
+AC_OUTPUT(
+       soundtouch.pc
+)
+
+dnl use 'echo' to put stuff here if you want a message to the builder
diff --git a/createsrcpack b/createsrcpack
new file mode 100755 (executable)
index 0000000..2f4b69a
--- /dev/null
@@ -0,0 +1,16 @@
+# Helper script for building a source code release package
+
+rm -Rf soundtouch
+rm soundtouch.zip
+rm soundtouch.tar.gz
+mkdir soundtouch
+cp -R * soundtouch
+cd soundtouch
+rm -Rf soundtouch
+rm -rf `find . -type d -name .svn`
+rm createsrcpack
+chmod u+x bootstrap
+cd ..
+zip -r9 soundtouch.zip soundtouch
+tar -chf soundtouch.tar soundtouch
+gzip soundtouch.tar
diff --git a/include/BPMDetect.h b/include/BPMDetect.h
new file mode 100644 (file)
index 0000000..8ece784
--- /dev/null
@@ -0,0 +1,205 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Beats-per-minute (BPM) detection routine.\r
+///\r
+/// The beat detection algorithm works as follows:\r
+/// - Use function 'inputSamples' to input a chunks of samples to the class for\r
+///   analysis. It's a good idea to enter a large sound file or stream in smallish\r
+///   chunks of around few kilosamples in order not to extinguish too much RAM memory.\r
+/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden,\r
+///   which is basically ok as low (bass) frequencies mostly determine the beat rate.\r
+///   Simple averaging is used for anti-alias filtering because the resulting signal\r
+///   quality isn't of that high importance.\r
+/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by\r
+///   taking absolute value that's smoothed by sliding average. Signal levels that\r
+///   are below a couple of times the general RMS amplitude level are cut away to\r
+///   leave only notable peaks there.\r
+/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term \r
+///   autocorrelation function of the enveloped signal.\r
+/// - After whole sound data file has been analyzed as above, the bpm level is \r
+///   detected by function 'getBpm' that finds the highest peak of the autocorrelation \r
+///   function, calculates it's precise location and converts this reading to bpm's.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _BPMDetect_H_\r
+#define _BPMDetect_H_\r
+\r
+#include <vector>\r
+#include "STTypes.h"\r
+#include "FIFOSampleBuffer.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+    /// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.\r
+    #define MIN_BPM 45\r
+\r
+    /// Maximum allowed BPM rate range. Used for calculating algorithm parametrs\r
+    #define MAX_BPM_RANGE 200\r
+\r
+    /// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit.\r
+    #define MAX_BPM_VALID 190\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+    typedef struct\r
+    {\r
+        float pos;\r
+        float strength;\r
+    } BEAT;\r
+\r
+\r
+    class IIR2_filter\r
+    {\r
+        double coeffs[5];\r
+        double prev[5];\r
+\r
+    public:\r
+        IIR2_filter(const double *lpf_coeffs);\r
+        float update(float x);\r
+    };\r
+\r
+\r
+    /// Class for calculating BPM rate for audio data.\r
+    class BPMDetect\r
+    {\r
+    protected:\r
+        /// Auto-correlation accumulator bins.\r
+        float *xcorr;\r
+\r
+        /// Sample average counter.\r
+        int decimateCount;\r
+\r
+        /// Sample average accumulator for FIFO-like decimation.\r
+        soundtouch::LONG_SAMPLETYPE decimateSum;\r
+\r
+        /// Decimate sound by this coefficient to reach approx. 500 Hz.\r
+        int decimateBy;\r
+\r
+        /// Auto-correlation window length\r
+        int windowLen;\r
+\r
+        /// Number of channels (1 = mono, 2 = stereo)\r
+        int channels;\r
+\r
+        /// sample rate\r
+        int sampleRate;\r
+\r
+        /// Beginning of auto-correlation window: Autocorrelation isn't being updated for\r
+        /// the first these many correlation bins.\r
+        int windowStart;\r
+\r
+        /// window functions for data preconditioning\r
+        float *hamw;\r
+        float *hamw2;\r
+\r
+        // beat detection variables\r
+        int pos;\r
+        int peakPos;\r
+        int beatcorr_ringbuffpos;\r
+        int init_scaler;\r
+        float peakVal;\r
+        float *beatcorr_ringbuff;\r
+\r
+        /// FIFO-buffer for decimated processing samples.\r
+        soundtouch::FIFOSampleBuffer *buffer;\r
+\r
+        /// Collection of detected beat positions\r
+        //BeatCollection beats;\r
+        std::vector<BEAT> beats;\r
+\r
+        // 2nd order low-pass-filter\r
+        IIR2_filter beat_lpf;\r
+\r
+        /// Updates auto-correlation function for given number of decimated samples that \r
+        /// are read from the internal 'buffer' pipe (samples aren't removed from the pipe \r
+        /// though).\r
+        void updateXCorr(int process_samples      /// How many samples are processed.\r
+        );\r
+\r
+        /// Decimates samples to approx. 500 Hz.\r
+        ///\r
+        /// \return Number of output samples.\r
+        int decimate(soundtouch::SAMPLETYPE *dest,      ///< Destination buffer\r
+            const soundtouch::SAMPLETYPE *src, ///< Source sample buffer\r
+            int numsamples                     ///< Number of source samples.\r
+        );\r
+\r
+        /// Calculates amplitude envelope for the buffer of samples.\r
+        /// Result is output to 'samples'.\r
+        void calcEnvelope(soundtouch::SAMPLETYPE *samples,  ///< Pointer to input/output data buffer\r
+            int numsamples                    ///< Number of samples in buffer\r
+        );\r
+\r
+        /// remove constant bias from xcorr data\r
+        void removeBias();\r
+\r
+        // Detect individual beat positions\r
+        void updateBeatPos(int process_samples);\r
+\r
+\r
+    public:\r
+        /// Constructor.\r
+        BPMDetect(int numChannels,  ///< Number of channels in sample data.\r
+            int sampleRate    ///< Sample rate in Hz.\r
+        );\r
+\r
+        /// Destructor.\r
+        virtual ~BPMDetect();\r
+\r
+        /// Inputs a block of samples for analyzing: Envelopes the samples and then\r
+        /// updates the autocorrelation estimation. When whole song data has been input\r
+        /// in smaller blocks using this function, read the resulting bpm with 'getBpm' \r
+        /// function. \r
+        /// \r
+        /// Notice that data in 'samples' array can be disrupted in processing.\r
+        void inputSamples(const soundtouch::SAMPLETYPE *samples,    ///< Pointer to input/working data buffer\r
+            int numSamples                            ///< Number of samples in buffer\r
+        );\r
+\r
+        /// Analyzes the results and returns the BPM rate. Use this function to read result\r
+        /// after whole song data has been input to the class by consecutive calls of\r
+        /// 'inputSamples' function.\r
+        ///\r
+        /// \return Beats-per-minute rate, or zero if detection failed.\r
+        float getBpm();\r
+\r
+        /// Get beat position arrays. Note: The array includes also really low beat detection values \r
+        /// in absence of clear strong beats. Consumer may wish to filter low values away.\r
+        /// - "pos" receive array of beat positions\r
+        /// - "values" receive array of beat detection strengths\r
+        /// - max_num indicates max.size of "pos" and "values" array.  \r
+        ///\r
+        /// You can query a suitable array sized by calling this with NULL in "pos" & "values".\r
+        ///\r
+        /// \return number of beats in the arrays.\r
+        int getBeats(float *pos, float *strength, int max_num);\r
+    };\r
+}\r
+#endif // _BPMDetect_H_\r
diff --git a/include/FIFOSampleBuffer.h b/include/FIFOSampleBuffer.h
new file mode 100644 (file)
index 0000000..de298dd
--- /dev/null
@@ -0,0 +1,177 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// A buffer class for temporarily storaging sound samples, operates as a \r
+/// first-in-first-out pipe.\r
+///\r
+/// Samples are added to the end of the sample buffer with the 'putSamples' \r
+/// function, and are received from the beginning of the buffer by calling\r
+/// the 'receiveSamples' function. The class automatically removes the \r
+/// output samples from the buffer as well as grows the storage size \r
+/// whenever necessary.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef FIFOSampleBuffer_H\r
+#define FIFOSampleBuffer_H\r
+\r
+#include "FIFOSamplePipe.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes\r
+/// care of storage size adjustment and data moving during input/output operations.\r
+///\r
+/// Notice that in case of stereo audio, one sample is considered to consist of \r
+/// both channel data.\r
+class FIFOSampleBuffer : public FIFOSamplePipe\r
+{\r
+private:\r
+    /// Sample buffer.\r
+    SAMPLETYPE *buffer;\r
+\r
+    // Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first\r
+    // 16-byte aligned location of this buffer\r
+    SAMPLETYPE *bufferUnaligned;\r
+\r
+    /// Sample buffer size in bytes\r
+    uint sizeInBytes;\r
+\r
+    /// How many samples are currently in buffer.\r
+    uint samplesInBuffer;\r
+\r
+    /// Channels, 1=mono, 2=stereo.\r
+    uint channels;\r
+\r
+    /// Current position pointer to the buffer. This pointer is increased when samples are \r
+    /// removed from the pipe so that it's necessary to actually rewind buffer (move data)\r
+    /// only new data when is put to the pipe.\r
+    uint bufferPos;\r
+\r
+    /// Rewind the buffer by moving data from position pointed by 'bufferPos' to real \r
+    /// beginning of the buffer.\r
+    void rewind();\r
+\r
+    /// Ensures that the buffer has capacity for at least this many samples.\r
+    void ensureCapacity(uint capacityRequirement);\r
+\r
+    /// Returns current capacity.\r
+    uint getCapacity() const;\r
+\r
+public:\r
+\r
+    /// Constructor\r
+    FIFOSampleBuffer(int numChannels = 2     ///< Number of channels, 1=mono, 2=stereo.\r
+                                              ///< Default is stereo.\r
+                     );\r
+\r
+    /// destructor\r
+    ~FIFOSampleBuffer();\r
+\r
+    /// Returns a pointer to the beginning of the output samples. \r
+    /// This function is provided for accessing the output samples directly. \r
+    /// Please be careful for not to corrupt the book-keeping!\r
+    ///\r
+    /// When using this function to output samples, also remember to 'remove' the\r
+    /// output samples from the buffer by calling the \r
+    /// 'receiveSamples(numSamples)' function\r
+    virtual SAMPLETYPE *ptrBegin();\r
+\r
+    /// Returns a pointer to the end of the used part of the sample buffer (i.e. \r
+    /// where the new samples are to be inserted). This function may be used for \r
+    /// inserting new samples into the sample buffer directly. Please be careful\r
+    /// not corrupt the book-keeping!\r
+    ///\r
+    /// When using this function as means for inserting new samples, also remember \r
+    /// to increase the sample count afterwards, by calling  the \r
+    /// 'putSamples(numSamples)' function.\r
+    SAMPLETYPE *ptrEnd(\r
+                uint slackCapacity   ///< How much free capacity (in samples) there _at least_ \r
+                                     ///< should be so that the caller can successfully insert the \r
+                                     ///< desired samples to the buffer. If necessary, the function \r
+                                     ///< grows the buffer size to comply with this requirement.\r
+                );\r
+\r
+    /// Adds 'numSamples' pcs of samples from the 'samples' memory position to\r
+    /// the sample buffer.\r
+    virtual void putSamples(const SAMPLETYPE *samples,  ///< Pointer to samples.\r
+                            uint numSamples                         ///< Number of samples to insert.\r
+                            );\r
+\r
+    /// Adjusts the book-keeping to increase number of samples in the buffer without \r
+    /// copying any actual samples.\r
+    ///\r
+    /// This function is used to update the number of samples in the sample buffer\r
+    /// when accessing the buffer directly with 'ptrEnd' function. Please be \r
+    /// careful though!\r
+    virtual void putSamples(uint numSamples   ///< Number of samples been inserted.\r
+                            );\r
+\r
+    /// Output samples from beginning of the sample buffer. Copies requested samples to \r
+    /// output buffer and removes them from the sample buffer. If there are less than \r
+    /// 'numsample' samples in the buffer, returns all that available.\r
+    ///\r
+    /// \return Number of samples returned.\r
+    virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.\r
+                                uint maxSamples                 ///< How many samples to receive at max.\r
+                                );\r
+\r
+    /// Adjusts book-keeping so that given number of samples are removed from beginning of the \r
+    /// sample buffer without copying them anywhere. \r
+    ///\r
+    /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+    /// with 'ptrBegin' function.\r
+    virtual uint receiveSamples(uint maxSamples   ///< Remove this many samples from the beginning of pipe.\r
+                                );\r
+\r
+    /// Returns number of samples currently available.\r
+    virtual uint numSamples() const;\r
+\r
+    /// Sets number of channels, 1 = mono, 2 = stereo.\r
+    void setChannels(int numChannels);\r
+\r
+    /// Get number of channels\r
+    int getChannels() \r
+    {\r
+        return channels;\r
+    }\r
+\r
+    /// Returns nonzero if there aren't any samples available for outputting.\r
+    virtual int isEmpty() const;\r
+\r
+    /// Clears all the samples.\r
+    virtual void clear();\r
+\r
+    /// allow trimming (downwards) amount of samples in pipeline.\r
+    /// Returns adjusted amount of samples\r
+    uint adjustAmountOfSamples(uint numSamples);\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/include/FIFOSamplePipe.h b/include/FIFOSamplePipe.h
new file mode 100644 (file)
index 0000000..38ef31a
--- /dev/null
@@ -0,0 +1,230 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound\r
+/// samples by operating like a first-in-first-out pipe: New samples are fed\r
+/// into one end of the pipe with the 'putSamples' function, and the processed\r
+/// samples are received from the other end with the 'receiveSamples' function.\r
+///\r
+/// 'FIFOProcessor' : A base class for classes the do signal processing with \r
+/// the samples while operating like a first-in-first-out pipe. When samples\r
+/// are input with the 'putSamples' function, the class processes them\r
+/// and moves the processed samples to the given 'output' pipe object, which\r
+/// may be either another processing stage, or a fifo sample buffer object.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef FIFOSamplePipe_H\r
+#define FIFOSamplePipe_H\r
+\r
+#include <assert.h>\r
+#include <stdlib.h>\r
+#include "STTypes.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+/// Abstract base class for FIFO (first-in-first-out) sample processing classes.\r
+class FIFOSamplePipe\r
+{\r
+protected:\r
+\r
+    bool verifyNumberOfChannels(int nChannels) const\r
+    {\r
+        if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS))\r
+        {\r
+            return true;\r
+        }\r
+        ST_THROW_RT_ERROR("Error: Illegal number of channels");\r
+        return false;\r
+    }\r
+\r
+public:\r
+    // virtual default destructor\r
+    virtual ~FIFOSamplePipe() {}\r
+\r
+\r
+    /// Returns a pointer to the beginning of the output samples. \r
+    /// This function is provided for accessing the output samples directly. \r
+    /// Please be careful for not to corrupt the book-keeping!\r
+    ///\r
+    /// When using this function to output samples, also remember to 'remove' the\r
+    /// output samples from the buffer by calling the \r
+    /// 'receiveSamples(numSamples)' function\r
+    virtual SAMPLETYPE *ptrBegin() = 0;\r
+\r
+    /// Adds 'numSamples' pcs of samples from the 'samples' memory position to\r
+    /// the sample buffer.\r
+    virtual void putSamples(const SAMPLETYPE *samples,  ///< Pointer to samples.\r
+                            uint numSamples             ///< Number of samples to insert.\r
+                            ) = 0;\r
+\r
+\r
+    // Moves samples from the 'other' pipe instance to this instance.\r
+    void moveSamples(FIFOSamplePipe &other  ///< Other pipe instance where from the receive the data.\r
+         )\r
+    {\r
+        int oNumSamples = other.numSamples();\r
+\r
+        putSamples(other.ptrBegin(), oNumSamples);\r
+        other.receiveSamples(oNumSamples);\r
+    };\r
+\r
+    /// Output samples from beginning of the sample buffer. Copies requested samples to \r
+    /// output buffer and removes them from the sample buffer. If there are less than \r
+    /// 'numsample' samples in the buffer, returns all that available.\r
+    ///\r
+    /// \return Number of samples returned.\r
+    virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.\r
+                                uint maxSamples                 ///< How many samples to receive at max.\r
+                                ) = 0;\r
+\r
+    /// Adjusts book-keeping so that given number of samples are removed from beginning of the \r
+    /// sample buffer without copying them anywhere. \r
+    ///\r
+    /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+    /// with 'ptrBegin' function.\r
+    virtual uint receiveSamples(uint maxSamples   ///< Remove this many samples from the beginning of pipe.\r
+                                ) = 0;\r
+\r
+    /// Returns number of samples currently available.\r
+    virtual uint numSamples() const = 0;\r
+\r
+    // Returns nonzero if there aren't any samples available for outputting.\r
+    virtual int isEmpty() const = 0;\r
+\r
+    /// Clears all the samples.\r
+    virtual void clear() = 0;\r
+\r
+    /// allow trimming (downwards) amount of samples in pipeline.\r
+    /// Returns adjusted amount of samples\r
+    virtual uint adjustAmountOfSamples(uint numSamples) = 0;\r
+\r
+};\r
+\r
+\r
+/// Base-class for sound processing routines working in FIFO principle. With this base \r
+/// class it's easy to implement sound processing stages that can be chained together,\r
+/// so that samples that are fed into beginning of the pipe automatically go through \r
+/// all the processing stages.\r
+///\r
+/// When samples are input to this class, they're first processed and then put to \r
+/// the FIFO pipe that's defined as output of this class. This output pipe can be\r
+/// either other processing stage or a FIFO sample buffer.\r
+class FIFOProcessor :public FIFOSamplePipe\r
+{\r
+protected:\r
+    /// Internal pipe where processed samples are put.\r
+    FIFOSamplePipe *output;\r
+\r
+    /// Sets output pipe.\r
+    void setOutPipe(FIFOSamplePipe *pOutput)\r
+    {\r
+        assert(output == NULL);\r
+        assert(pOutput != NULL);\r
+        output = pOutput;\r
+    }\r
+\r
+    /// Constructor. Doesn't define output pipe; it has to be set be \r
+    /// 'setOutPipe' function.\r
+    FIFOProcessor()\r
+    {\r
+        output = NULL;\r
+    }\r
+\r
+    /// Constructor. Configures output pipe.\r
+    FIFOProcessor(FIFOSamplePipe *pOutput   ///< Output pipe.\r
+                 )\r
+    {\r
+        output = pOutput;\r
+    }\r
+\r
+    /// Destructor.\r
+    virtual ~FIFOProcessor()\r
+    {\r
+    }\r
+\r
+    /// Returns a pointer to the beginning of the output samples. \r
+    /// This function is provided for accessing the output samples directly. \r
+    /// Please be careful for not to corrupt the book-keeping!\r
+    ///\r
+    /// When using this function to output samples, also remember to 'remove' the\r
+    /// output samples from the buffer by calling the \r
+    /// 'receiveSamples(numSamples)' function\r
+    virtual SAMPLETYPE *ptrBegin()\r
+    {\r
+        return output->ptrBegin();\r
+    }\r
+\r
+public:\r
+\r
+    /// Output samples from beginning of the sample buffer. Copies requested samples to \r
+    /// output buffer and removes them from the sample buffer. If there are less than \r
+    /// 'numsample' samples in the buffer, returns all that available.\r
+    ///\r
+    /// \return Number of samples returned.\r
+    virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.\r
+                                uint maxSamples                    ///< How many samples to receive at max.\r
+                                )\r
+    {\r
+        return output->receiveSamples(outBuffer, maxSamples);\r
+    }\r
+\r
+    /// Adjusts book-keeping so that given number of samples are removed from beginning of the \r
+    /// sample buffer without copying them anywhere. \r
+    ///\r
+    /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+    /// with 'ptrBegin' function.\r
+    virtual uint receiveSamples(uint maxSamples   ///< Remove this many samples from the beginning of pipe.\r
+                                )\r
+    {\r
+        return output->receiveSamples(maxSamples);\r
+    }\r
+\r
+    /// Returns number of samples currently available.\r
+    virtual uint numSamples() const\r
+    {\r
+        return output->numSamples();\r
+    }\r
+\r
+    /// Returns nonzero if there aren't any samples available for outputting.\r
+    virtual int isEmpty() const\r
+    {\r
+        return output->isEmpty();\r
+    }\r
+\r
+    /// allow trimming (downwards) amount of samples in pipeline.\r
+    /// Returns adjusted amount of samples\r
+    virtual uint adjustAmountOfSamples(uint numSamples)\r
+    {\r
+        return output->adjustAmountOfSamples(numSamples);\r
+    }\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644 (file)
index 0000000..d1b8238
--- /dev/null
@@ -0,0 +1,22 @@
+## Process this file with automake to create Makefile.in\r
+##\r
+## This file is part of SoundTouch, an audio processing library for pitch/time adjustments\r
+## \r
+## SoundTouch is free software; you can redistribute it and/or modify it under the\r
+## terms of the GNU General Public License as published by the Free Software\r
+## Foundation; either version 2 of the License, or (at your option) any later\r
+## version.\r
+## \r
+## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY\r
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+## A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r
+## \r
+## You should have received a copy of the GNU General Public License along with\r
+## this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
+## Place - Suite 330, Boston, MA  02111-1307, USA\r
+\r
+## I used config/am_include.mk for common definitions\r
+include $(top_srcdir)/config/am_include.mk\r
+\r
+pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h\r
+\r
diff --git a/include/STTypes.h b/include/STTypes.h
new file mode 100644 (file)
index 0000000..862505e
--- /dev/null
@@ -0,0 +1,183 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Common type definitions for SoundTouch audio processing library.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef STTypes_H\r
+#define STTypes_H\r
+\r
+typedef unsigned int    uint;\r
+typedef unsigned long   ulong;\r
+\r
+// Patch for MinGW: on Win64 long is 32-bit\r
+#ifdef _WIN64\r
+    typedef unsigned long long ulongptr;\r
+#else\r
+    typedef ulong ulongptr;\r
+#endif\r
+\r
+\r
+// Helper macro for aligning pointer up to next 16-byte boundary\r
+#define SOUNDTOUCH_ALIGN_POINTER_16(x)      ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 )\r
+\r
+\r
+#if (defined(__GNUC__) && !defined(ANDROID))\r
+    // In GCC, include soundtouch_config.h made by config scritps.\r
+    // Skip this in Android compilation that uses GCC but without configure scripts.\r
+    #include "soundtouch_config.h"\r
+#endif\r
+\r
+\r
+namespace soundtouch\r
+{\r
+    /// Max allowed number of channels\r
+    #define SOUNDTOUCH_MAX_CHANNELS     16\r
+\r
+    /// Activate these undef's to overrule the possible sampletype \r
+    /// setting inherited from some other header file:\r
+    //#undef SOUNDTOUCH_INTEGER_SAMPLES\r
+    //#undef SOUNDTOUCH_FLOAT_SAMPLES\r
+\r
+    /// If following flag is defined, always uses multichannel processing \r
+    /// routines also for mono and stero sound. This is for routine testing \r
+    /// purposes; output should be same with either routines, yet disabling \r
+    /// the dedicated mono/stereo processing routines will result in slower \r
+    /// runtime performance so recommendation is to keep this off.\r
+    // #define USE_MULTICH_ALWAYS\r
+\r
+    #if (defined(__SOFTFP__) && defined(ANDROID))\r
+        // For Android compilation: Force use of Integer samples in case that\r
+        // compilation uses soft-floating point emulation - soft-fp is way too slow\r
+        #undef  SOUNDTOUCH_FLOAT_SAMPLES\r
+        #define SOUNDTOUCH_INTEGER_SAMPLES      1\r
+    #endif\r
+\r
+    #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)\r
+       \r
+        /// Choose either 32bit floating point or 16bit integer sampletype\r
+        /// by choosing one of the following defines, unless this selection \r
+        /// has already been done in some other file.\r
+        ////\r
+        /// Notes:\r
+        /// - In Windows environment, choose the sample format with the\r
+        ///   following defines.\r
+        /// - In GNU environment, the floating point samples are used by \r
+        ///   default, but integer samples can be chosen by giving the \r
+        ///   following switch to the configure script:\r
+        ///       ./configure --enable-integer-samples\r
+        ///   However, if you still prefer to select the sample format here \r
+        ///   also in GNU environment, then please #undef the INTEGER_SAMPLE\r
+        ///   and FLOAT_SAMPLE defines first as in comments above.\r
+        //#define SOUNDTOUCH_INTEGER_SAMPLES     1    //< 16bit integer samples\r
+        #define SOUNDTOUCH_FLOAT_SAMPLES       1    //< 32bit float samples\r
+     \r
+    #endif\r
+\r
+    #if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)\r
+        /// Define this to allow X86-specific assembler/intrinsic optimizations. \r
+        /// Notice that library contains also usual C++ versions of each of these\r
+        /// these routines, so if you're having difficulties getting the optimized \r
+        /// routines compiled for whatever reason, you may disable these optimizations \r
+        /// to make the library compile.\r
+\r
+        #define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS     1\r
+\r
+        /// In GNU environment, allow the user to override this setting by\r
+        /// giving the following switch to the configure script:\r
+        /// ./configure --disable-x86-optimizations\r
+        /// ./configure --enable-x86-optimizations=no\r
+        #ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS\r
+            #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS\r
+        #endif\r
+    #else\r
+        /// Always disable optimizations when not using a x86 systems.\r
+        #undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS\r
+\r
+    #endif\r
+\r
+    // If defined, allows the SIMD-optimized routines to take minor shortcuts \r
+    // for improved performance. Undefine to require faithfully similar SIMD \r
+    // calculations as in normal C implementation.\r
+    #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION    1\r
+\r
+\r
+    #ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+        // 16bit integer sample type\r
+        typedef short SAMPLETYPE;\r
+        // data type for sample accumulation: Use 32bit integer to prevent overflows\r
+        typedef long  LONG_SAMPLETYPE;\r
+\r
+        #ifdef SOUNDTOUCH_FLOAT_SAMPLES\r
+            // check that only one sample type is defined\r
+            #error "conflicting sample types defined"\r
+        #endif // SOUNDTOUCH_FLOAT_SAMPLES\r
+\r
+        #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS\r
+            // Allow MMX optimizations (not available in X64 mode)\r
+            #if (!_M_X64)\r
+                #define SOUNDTOUCH_ALLOW_MMX   1\r
+            #endif\r
+        #endif\r
+\r
+    #else\r
+\r
+        // floating point samples\r
+        typedef float  SAMPLETYPE;\r
+        // data type for sample accumulation: Use double to utilize full precision.\r
+        typedef double LONG_SAMPLETYPE;\r
+\r
+        #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS\r
+            // Allow SSE optimizations\r
+            #define SOUNDTOUCH_ALLOW_SSE       1\r
+        #endif\r
+\r
+    #endif  // SOUNDTOUCH_INTEGER_SAMPLES\r
+\r
+};\r
+\r
+// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions:\r
+// #define ST_NO_EXCEPTION_HANDLING    1\r
+#ifdef ST_NO_EXCEPTION_HANDLING\r
+    // Exceptions disabled. Throw asserts instead if enabled.\r
+    #include <assert.h>\r
+    #define ST_THROW_RT_ERROR(x)    {assert((const char *)x);}\r
+#else\r
+    // use c++ standard exceptions\r
+    #include <stdexcept>\r
+    #include <string>\r
+    #define ST_THROW_RT_ERROR(x)    {throw std::runtime_error(x);}\r
+#endif\r
+\r
+// When this #define is active, eliminates a clicking sound when the "rate" or "pitch" \r
+// parameter setting crosses from value <1 to >=1 or vice versa during processing. \r
+// Default is off as such crossover is untypical case and involves a slight sound \r
+// quality compromise.\r
+//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER   1\r
+\r
+#endif\r
diff --git a/include/SoundTouch.h b/include/SoundTouch.h
new file mode 100644 (file)
index 0000000..f2addc1
--- /dev/null
@@ -0,0 +1,348 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// SoundTouch - main class for tempo/pitch/rate adjusting routines. \r
+///\r
+/// Notes:\r
+/// - Initialize the SoundTouch object instance by setting up the sound stream \r
+///   parameters with functions 'setSampleRate' and 'setChannels', then set \r
+///   desired tempo/pitch/rate settings with the corresponding functions.\r
+///\r
+/// - The SoundTouch class behaves like a first-in-first-out pipeline: The \r
+///   samples that are to be processed are fed into one of the pipe by calling\r
+///   function 'putSamples', while the ready processed samples can be read \r
+///   from the other end of the pipeline with function 'receiveSamples'.\r
+/// \r
+/// - The SoundTouch processing classes require certain sized 'batches' of \r
+///   samples in order to process the sound. For this reason the classes buffer \r
+///   incoming samples until there are enough of samples available for \r
+///   processing, then they carry out the processing step and consequently\r
+///   make the processed samples available for outputting.\r
+/// \r
+/// - For the above reason, the processing routines introduce a certain \r
+///   'latency' between the input and output, so that the samples input to\r
+///   SoundTouch may not be immediately available in the output, and neither \r
+///   the amount of outputtable samples may not immediately be in direct \r
+///   relationship with the amount of previously input samples.\r
+///\r
+/// - The tempo/pitch/rate control parameters can be altered during processing.\r
+///   Please notice though that they aren't currently protected by semaphores,\r
+///   so in multi-thread application external semaphore protection may be\r
+///   required.\r
+///\r
+/// - This class utilizes classes 'TDStretch' for tempo change (without modifying\r
+///   pitch) and 'RateTransposer' for changing the playback rate (that is, both \r
+///   tempo and pitch in the same ratio) of the sound. The third available control \r
+///   'pitch' (change pitch but maintain tempo) is produced by a combination of\r
+///   combining the two other controls.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef SoundTouch_H\r
+#define SoundTouch_H\r
+\r
+#include "FIFOSamplePipe.h"\r
+#include "STTypes.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+/// Soundtouch library version string\r
+#define SOUNDTOUCH_VERSION          "2.1"\r
+\r
+/// SoundTouch library version id\r
+#define SOUNDTOUCH_VERSION_ID       (20100)\r
+\r
+//\r
+// Available setting IDs for the 'setSetting' & 'get_setting' functions:\r
+\r
+/// Enable/disable anti-alias filter in pitch transposer (0 = disable)\r
+#define SETTING_USE_AA_FILTER       0\r
+\r
+/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)\r
+#define SETTING_AA_FILTER_LENGTH    1\r
+\r
+/// Enable/disable quick seeking algorithm in tempo changer routine\r
+/// (enabling quick seeking lowers CPU utilization but causes a minor sound\r
+///  quality compromising)\r
+#define SETTING_USE_QUICKSEEK       2\r
+\r
+/// Time-stretch algorithm single processing sequence length in milliseconds. This determines \r
+/// to how long sequences the original sound is chopped in the time-stretch algorithm. \r
+/// See "STTypes.h" or README for more information.\r
+#define SETTING_SEQUENCE_MS         3\r
+\r
+/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the \r
+/// best possible overlapping location. This determines from how wide window the algorithm \r
+/// may look for an optimal joining location when mixing the sound sequences back together. \r
+/// See "STTypes.h" or README for more information.\r
+#define SETTING_SEEKWINDOW_MS       4\r
+\r
+/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences \r
+/// are mixed back together, to form a continuous sound stream, this parameter defines over \r
+/// how long period the two consecutive sequences are let to overlap each other. \r
+/// See "STTypes.h" or README for more information.\r
+#define SETTING_OVERLAP_MS          5\r
+\r
+\r
+/// Call "getSetting" with this ID to query processing sequence size in samples. \r
+/// This value gives approximate value of how many input samples you'll need to \r
+/// feed into SoundTouch after initial buffering to get out a new batch of\r
+/// output samples. \r
+///\r
+/// This value does not include initial buffering at beginning of a new processing \r
+/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size.\r
+///\r
+/// Notices: \r
+/// - This is read-only parameter, i.e. setSetting ignores this parameter\r
+/// - This parameter value is not constant but change depending on \r
+///   tempo/pitch/rate/samplerate settings.\r
+#define SETTING_NOMINAL_INPUT_SEQUENCE      6\r
+\r
+\r
+/// Call "getSetting" with this ID to query nominal average processing output \r
+/// size in samples. This value tells approcimate value how many output samples \r
+/// SoundTouch outputs once it does DSP processing run for a batch of input samples.\r
+///\r
+/// Notices: \r
+/// - This is read-only parameter, i.e. setSetting ignores this parameter\r
+/// - This parameter value is not constant but change depending on \r
+///   tempo/pitch/rate/samplerate settings.\r
+#define SETTING_NOMINAL_OUTPUT_SEQUENCE     7\r
+\r
+\r
+/// Call "getSetting" with this ID to query initial processing latency, i.e.\r
+/// approx. how many samples you'll need to enter to SoundTouch pipeline before \r
+/// you can expect to get first batch of ready output samples out. \r
+///\r
+/// After the first output batch, you can then expect to get approx. \r
+/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every\r
+/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch.\r
+///\r
+/// Example:\r
+///     processing with parameter -tempo=5\r
+///     => initial latency = 5509 samples\r
+///        input sequence  = 4167 samples\r
+///        output sequence = 3969 samples\r
+///\r
+/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of \r
+/// the stream, and then you'll get out the first 3969 samples. After that, for \r
+/// every approx. 4167 samples that you'll put in, you'll receive again approx. \r
+/// 3969 samples out.\r
+///\r
+/// This also means that average latency during stream processing is \r
+/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2 \r
+/// = 3524 samples\r
+/// \r
+/// Notices: \r
+/// - This is read-only parameter, i.e. setSetting ignores this parameter\r
+/// - This parameter value is not constant but change depending on \r
+///   tempo/pitch/rate/samplerate settings.\r
+#define SETTING_INITIAL_LATENCY             8\r
+\r
+\r
+class SoundTouch : public FIFOProcessor\r
+{\r
+private:\r
+    /// Rate transposer class instance\r
+    class RateTransposer *pRateTransposer;\r
+\r
+    /// Time-stretch class instance\r
+    class TDStretch *pTDStretch;\r
+\r
+    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.\r
+    double virtualRate;\r
+\r
+    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.\r
+    double virtualTempo;\r
+\r
+    /// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.\r
+    double virtualPitch;\r
+\r
+    /// Flag: Has sample rate been set?\r
+    bool  bSrateSet;\r
+\r
+    /// Accumulator for how many samples in total will be expected as output vs. samples put in,\r
+    /// considering current processing settings.\r
+    double samplesExpectedOut;\r
+\r
+    /// Accumulator for how many samples in total have been read out from the processing so far\r
+    long   samplesOutput;\r
+\r
+    /// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and \r
+    /// 'virtualPitch' parameters.\r
+    void calcEffectiveRateAndTempo();\r
+\r
+protected :\r
+    /// Number of channels\r
+    uint  channels;\r
+\r
+    /// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'\r
+    double rate;\r
+\r
+    /// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'\r
+    double tempo;\r
+\r
+public:\r
+    SoundTouch();\r
+    virtual ~SoundTouch();\r
+\r
+    /// Get SoundTouch library version string\r
+    static const char *getVersionString();\r
+\r
+    /// Get SoundTouch library version Id\r
+    static uint getVersionId();\r
+\r
+    /// Sets new rate control value. Normal rate = 1.0, smaller values\r
+    /// represent slower rate, larger faster rates.\r
+    void setRate(double newRate);\r
+\r
+    /// Sets new tempo control value. Normal tempo = 1.0, smaller values\r
+    /// represent slower tempo, larger faster tempo.\r
+    void setTempo(double newTempo);\r
+\r
+    /// Sets new rate control value as a difference in percents compared\r
+    /// to the original rate (-50 .. +100 %)\r
+    void setRateChange(double newRate);\r
+\r
+    /// Sets new tempo control value as a difference in percents compared\r
+    /// to the original tempo (-50 .. +100 %)\r
+    void setTempoChange(double newTempo);\r
+\r
+    /// Sets new pitch control value. Original pitch = 1.0, smaller values\r
+    /// represent lower pitches, larger values higher pitch.\r
+    void setPitch(double newPitch);\r
+\r
+    /// Sets pitch change in octaves compared to the original pitch  \r
+    /// (-1.00 .. +1.00)\r
+    void setPitchOctaves(double newPitch);\r
+\r
+    /// Sets pitch change in semi-tones compared to the original pitch\r
+    /// (-12 .. +12)\r
+    void setPitchSemiTones(int newPitch);\r
+    void setPitchSemiTones(double newPitch);\r
+\r
+    /// Sets the number of channels, 1 = mono, 2 = stereo\r
+    void setChannels(uint numChannels);\r
+\r
+    /// Sets sample rate.\r
+    void setSampleRate(uint srate);\r
+\r
+    /// Get ratio between input and output audio durations, useful for calculating\r
+    /// processed output duration: if you'll process a stream of N samples, then \r
+    /// you can expect to get out N * getInputOutputSampleRatio() samples.\r
+    ///\r
+    /// This ratio will give accurate target duration ratio for a full audio track, \r
+    /// given that the the whole track is processed with same processing parameters.\r
+    /// \r
+    /// If this ratio is applied to calculate intermediate offsets inside a processing\r
+    /// stream, then this ratio is approximate and can deviate +- some tens of milliseconds \r
+    /// from ideal offset, yet by end of the audio stream the duration ratio will become\r
+    /// exact.\r
+    ///\r
+    /// Example: if processing with parameters "-tempo=15 -pitch=-3", the function\r
+    /// will return value 0.8695652... Now, if processing an audio stream whose duration\r
+    /// is exactly one million audio samples, then you can expect the processed \r
+    /// output duration  be 0.869565 * 1000000 = 869565 samples.\r
+    double getInputOutputSampleRatio();\r
+\r
+    /// Flushes the last samples from the processing pipeline to the output.\r
+    /// Clears also the internal processing buffers.\r
+    //\r
+    /// Note: This function is meant for extracting the last samples of a sound\r
+    /// stream. This function may introduce additional blank samples in the end\r
+    /// of the sound stream, and thus it's not recommended to call this function\r
+    /// in the middle of a sound stream.\r
+    void flush();\r
+\r
+    /// Adds 'numSamples' pcs of samples from the 'samples' memory position into\r
+    /// the input of the object. Notice that sample rate _has_to_ be set before\r
+    /// calling this function, otherwise throws a runtime_error exception.\r
+    virtual void putSamples(\r
+            const SAMPLETYPE *samples,  ///< Pointer to sample buffer.\r
+            uint numSamples                         ///< Number of samples in buffer. Notice\r
+                                                    ///< that in case of stereo-sound a single sample\r
+                                                    ///< contains data for both channels.\r
+            );\r
+\r
+    /// Output samples from beginning of the sample buffer. Copies requested samples to \r
+    /// output buffer and removes them from the sample buffer. If there are less than \r
+    /// 'numsample' samples in the buffer, returns all that available.\r
+    ///\r
+    /// \return Number of samples returned.\r
+    virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.\r
+        uint maxSamples                 ///< How many samples to receive at max.\r
+        );\r
+\r
+    /// Adjusts book-keeping so that given number of samples are removed from beginning of the \r
+    /// sample buffer without copying them anywhere. \r
+    ///\r
+    /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+    /// with 'ptrBegin' function.\r
+    virtual uint receiveSamples(uint maxSamples   ///< Remove this many samples from the beginning of pipe.\r
+        );\r
+\r
+    /// Clears all the samples in the object's output and internal processing\r
+    /// buffers.\r
+    virtual void clear();\r
+\r
+    /// Changes a setting controlling the processing system behaviour. See the\r
+    /// 'SETTING_...' defines for available setting ID's.\r
+    /// \r
+    /// \return 'true' if the setting was successfully changed\r
+    bool setSetting(int settingId,   ///< Setting ID number. see SETTING_... defines.\r
+                    int value        ///< New setting value.\r
+                    );\r
+\r
+    /// Reads a setting controlling the processing system behaviour. See the\r
+    /// 'SETTING_...' defines for available setting ID's.\r
+    ///\r
+    /// \return the setting value.\r
+    int getSetting(int settingId    ///< Setting ID number, see SETTING_... defines.\r
+                   ) const;\r
+\r
+    /// Returns number of samples currently unprocessed.\r
+    virtual uint numUnprocessedSamples() const;\r
+\r
+    /// Return number of channels\r
+    uint numChannels() const\r
+    {\r
+        return channels;\r
+    }\r
+\r
+    /// Other handy functions that are implemented in the ancestor classes (see\r
+    /// classes 'FIFOProcessor' and 'FIFOSamplePipe')\r
+    ///\r
+    /// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.\r
+    /// - numSamples()     : Get number of 'ready' samples that can be received with \r
+    ///                      function 'receiveSamples()'\r
+    /// - isEmpty()        : Returns nonzero if there aren't any 'ready' samples.\r
+    /// - clear()          : Clears all samples from ready/processing buffers.\r
+};\r
+\r
+}\r
+#endif\r
diff --git a/include/soundtouch_config.h.in b/include/soundtouch_config.h.in
new file mode 100644 (file)
index 0000000..74a9ccb
--- /dev/null
@@ -0,0 +1,5 @@
+/* Use Float as Sample type */
+#undef SOUNDTOUCH_FLOAT_SAMPLES
+
+/* Use Integer as Sample type */
+#undef SOUNDTOUCH_INTEGER_SAMPLES
diff --git a/make-win.bat b/make-win.bat
new file mode 100644 (file)
index 0000000..fbc1812
--- /dev/null
@@ -0,0 +1,40 @@
+@REM 
+@REM SoundTouch & SoundStretch Build script for Win32 platform
+@REM 
+@REM You'll need Visual C++ 6.0 installed to compile - also execute the 
+@REM "vcvars32.bat" in VC install directotry before running this one.
+@REM 
+@REM Copyright (c) Olli Parviainen
+@REM
+
+@if "%DevEnvDir%"=="" goto nodevdir
+
+@rem devenv source\SoundStretch\SoundStretch.sln /upgrade
+devenv source\SoundStretch\SoundStretch.sln /build "Debug|Win32"
+devenv source\SoundStretch\SoundStretch.sln /build "Release|Win32"
+devenv source\SoundStretch\SoundStretch.sln /build "Debug|x64"
+devenv source\SoundStretch\SoundStretch.sln /build "Release|x64"
+
+@rem devenv source\SoundTouchDll\SoundTouchDll.sln /upgrade
+devenv source\SoundTouchDll\SoundTouchDll.sln /build "Debug|Win32"
+devenv source\SoundTouchDll\SoundTouchDll.sln /build "Release|Win32"
+devenv source\SoundTouchDll\SoundTouchDll.sln /build "Debug|x64"
+devenv source\SoundTouchDll\SoundTouchDll.sln /build "Release|x64"
+
+@goto end
+
+
+:nodevdir
+
+@echo off
+echo ****************************************************************************
+echo **
+echo ** ERROR: Visual Studio path not set.
+echo **
+echo ** Run "vsvars32.bat" or "vcvars32.bat" from Visual Studio installation dir,
+echo ** e.g. "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin",
+echo ** then try again.
+echo **
+echo ****************************************************************************
+
+:end
diff --git a/readme.md b/readme.md
new file mode 100644 (file)
index 0000000..d6f8ef0
--- /dev/null
+++ b/readme.md
@@ -0,0 +1,50 @@
+# SoundTouch library
+
+SoundTouch is an open-source audio processing library that allows changing the sound tempo, pitch and playback rate parameters independently from each other:
+* Change **tempo** while maintaining the original pitch
+* Change **pitch** while maintaining the original tempo
+* Change **playback rate** that affects both tempo and pitch at the
+same time
+* Change any combination of tempo/pitch/rate
+
+Visit [SoundTouch website](https://www.surina.net/soundtouch) and see the [README file](README.html) for more information and audio examples.
+
+## Example
+
+Use SoundStretch example app for modifying wav audio files, for example as follows:
+
+```
+soundstretch my_original_file.wav output_file.wav -tempo=+15 -pitch=-3
+```
+
+See the [README file](README.html) for more usage examples and instructions how to build SoundTouch + SoundStretch.
+
+Ready [SoundStretch application executables](https://www.surina.net/soundtouch/download.html) are available for download for Windows and Mac OS.
+
+## Language & Platforms
+
+SoundTouch is written in C++ and compiles in virtually any platform:
+* Windows
+* Mac OS
+* Linux & Unices (including also Raspberry, Beaglebone, Yocto etc embedded Linux flavors)
+* Android
+* iOS
+* embedded systems
+
+The source code package includes dynamic library import modules for C#, Java and Pascal/Delphi languages.
+
+## License
+
+SoundTouch is released under LGPL v2.1:
+
+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.
+
+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
+
+See [LGPL v2.1 full license text ](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) for details.
+
+--
+
+Also commercial license free of GPL limitations available upon request
diff --git a/soundtouch.m4 b/soundtouch.m4
new file mode 100644 (file)
index 0000000..7e7589b
--- /dev/null
@@ -0,0 +1,67 @@
+# m4 configure test script for the SoundTouch library
+#
+# This file can be included with other packages that need to test
+# for libSoundTouch.
+#
+# It will #define HAVE_LIBSOUNDTOUCH iff the library is found
+# It will AC_SUBST SOUNDTOUCH_LIBS and SOUNDTOUCH_CXXFLAGS as well
+# It also defines some flags to the configure script for specifying
+# the location to search for libSoundTouch
+#
+# A user of libSoundTouch should add @SOUNDTOUCH_LIBS@ and 
+# @SOUNDTOUCH_CXXFLAGS@ to the appropriate variables in his
+# Makefile.am files
+#
+# This script works with autoconf-2.5x and automake-1.6 but I have
+# not tested it with older versions.
+
+
+dnl        min version not supported yet
+dnl AM_PATH_SOUNDTOUCH([MINMUM-VERSION, [(additional) ACTION-IF-FOUND] [, ACTION-IF-NOT-FOUND]]])
+
+AH_TEMPLATE([HAVE_LIBSOUNDTOUCH], [defined by $0])
+SOUNDTOUCH_CXXFLAGS=""
+SOUNDTOUCH_LIBS=""
+
+AC_DEFUN([AM_PATH_SOUNDTOUCH],[
+       AC_ARG_WITH(soundtouch-prefix,[  --with-soundtouch-prefix=DIR   Prefix where SoundTouch was installed (optional)], [soundtouch_prefix="$withval"],[soundtouch_prefix=""])
+
+       AC_ARG_ENABLE(soundtouch-check,[  --disable-soundtouch-check   Do not look for the SoundTouch Library],[enable_soundtouch_check="$enableval"],[enable_soundtouch_check="yes"])
+
+       if test "$enable_soundtouch_check" = "yes"
+       then
+               saved_CPPFLAGS="$CPPFLAGS"
+               saved_LDFLAGS="$LDFLAGS"
+          
+               CPPFLAGS="$CPPFLAGS -I$soundtouch_prefix/include"
+               LDFLAGS="$LDFLAGS -L$soundtouch_prefix/lib"
+   
+               dnl make sure SoundTouch.h header file exists
+                       dnl could use AC_CHECK_HEADERS to check for all of them, but the supporting .h file names may change later
+               AC_CHECK_HEADER([soundtouch/SoundTouch.h],[
+                               dnl SoundTouch.h found
+                               dnl make sure libSoundTouch is linkable
+                               AC_CHECK_LIB([SoundTouch],[soundtouch_ac_test],[
+                                       dnl libSoundTouch found
+                                       SOUNDTOUCH_CXXFLAGS="-I$soundtouch_prefix/include"
+                                       SOUNDTOUCH_LIBS="-L$soundtouch_prefix/lib -lSoundTouch"
+                                       AC_DEFINE([HAVE_LIBSOUNDTOUCH])
+
+                                       dnl run action-if-found
+                                       ifelse([$2], , :, [$2])
+                               ],[ 
+                                       dnl run action-if-not-found
+                                       ifelse([$3], , :, [$3])
+                               ])
+                       ],[
+                               dnl run action-if-not-found
+                               ifelse([$3], , :, [$3])
+                       ])
+
+               CPPFLAGS="$saved_CPPFLAGS"
+               LDFLAGS="$saved_LDFLAGS"
+       fi
+
+       AC_SUBST(SOUNDTOUCH_CXXFLAGS)
+       AC_SUBST(SOUNDTOUCH_LIBS)
+])
diff --git a/soundtouch.pc.in b/soundtouch.pc.in
new file mode 100644 (file)
index 0000000..03d0360
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: SoundTouch
+Description: SoundTouch is an open-source audio processing library for changing the Tempo, Pitch and Playback Rates of audio streams or files
+Version: @VERSION@
+Libs: -L${libdir} -lSoundTouch
+Cflags: -I${includedir}/soundtouch  
+
diff --git a/source/Android-lib/.classpath b/source/Android-lib/.classpath
new file mode 100644 (file)
index 0000000..5176974
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+       <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+       <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="gen"/>
+       <classpathentry kind="output" path="bin/classes"/>
+</classpath>
diff --git a/source/Android-lib/.project b/source/Android-lib/.project
new file mode 100644 (file)
index 0000000..1f328a8
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>ExampleActivity</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/source/Android-lib/AndroidManifest.xml b/source/Android-lib/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..b77e35e
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="net.surina.soundtouchexample"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk
+        android:minSdkVersion="11"
+        android:targetSdkVersion="21" />
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    
+    <application
+        android:allowBackup="true"
+        android:icon="@drawable/ic_launcher"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme" >
+        <activity
+            android:name="net.surina.ExampleActivity"
+            android:label="@string/app_name" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
diff --git a/source/Android-lib/README-SoundTouch-Android.html b/source/Android-lib/README-SoundTouch-Android.html
new file mode 100644 (file)
index 0000000..4a2c809
--- /dev/null
@@ -0,0 +1,127 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\r
+<html>\r
+<head>\r
+  <title>SoundTouch in Android</title>\r
+  <meta http-equiv="Content-Type"\r
+ content="text/html; charset=windows-1252">\r
+  <meta http-equiv="Content-Language" content="en-us">\r
+  <meta name="author" content="Olli Parviainen">\r
+  <meta name="description"\r
+ content="Readme file for SoundTouch library Android compilation">\r
+  <style> <!-- .normal { font-family: Arial }\r
+  --></style>\r
+</head>\r
+<body class="normal">\r
+<hr>\r
+<h1>SoundTouch in Android</h1>\r
+<hr>\r
+<h2>Compiling SoundTouch for Android</h2>\r
+<p>SoundTouch source code package contains &quot;Android-lib&quot; example project that compiles SoundTouch \r
+    source codes into Android native library, and gives an example of JNI interface \r
+    for invoking \r
+    the native SoundTouch routines from an Android application written in Java.</p>\r
+<p style="font-weight: 700">Software prerequisites:</p>\r
+<ul>\r
+    <li>Android SDK environment for developing your own Android application. Visit the <a href="http://developer.android.com/index.html">Android developers' site</a> \r
+        for more information about the Android SDK and developing Android applications.</li>\r
+    <li>Android NDK compiler kit for compiling native library binaries. The Android NDK \r
+        is <a href="http://developer.android.com/tools/sdk/ndk/index.html">\r
+        available for download</a> at the Android developer tools site.</li>\r
+    <li>In case you're working in Windows environment, install\r
+        <a href="http://cygwin.com/install.html">\r
+        Cygwin</a> to run the Android NDK/SDK compiler scripts</li>\r
+    <li>Latest SoundTouch source code package available at <a href="http://soundtouch.surina.net/sourcecode.html">\r
+        soundtouch.surina.net</a>.</li>\r
+</ul>\r
+<p><b>Hint: </b>As installing and configuring all the components for an Android SDK/NDK \r
+    environment requires fair effort, it&#39;s good idea to create a dedicated Virtual \r
+    Machine environment for the Android development environment installation. \r
+    Having the Android developer environment setup in dedicated Virtual Machine \r
+    allows keeping all these settings isolated from your other PC operations, and \r
+    eases taking backup snapshots of your full development environment.</p>\r
+<p><b>Compiling</b></p>\r
+<p>\r
+    To compile the SoundTouch library source codes into an Android native library, \r
+    open Cygwin/bash shell, go to directory <b>&quot;soundtouch/source/Android-lib/jni&quot;</b> and invoke the NDK \r
+    compiler with following command:</p>\r
+<pre>    $NDK/ndk-build</pre>\r
+<p>This will build binaries for all the supported Android platforms (arm-v5, arm-v7, X86, MIPS etc) of SoundTouch library, plus the JNI wrapper interface as discussed below. The target binaries will be built into the &quot;libs&quot; subdirectory. As long as all these .so binary library versions are included in the APK Application delivery package, the target Android device can choose the correct library version to use. </p>\r
+<p>Notice that to allow Cygwin/bash to locate the NDK compile scripts, you \r
+    need to define the location of the NDK installation defined in environment \r
+    variable &quot;NDK&quot;. That's easiest done by adding the NDK path definition at end of \r
+    your <b>~/.bash_profile</b> file, for instance as follows:</p>\r
+<pre>    NDK=/cygdrive/d/Android/android-ndk-r6</pre>\r
+<p><b>Enabling OpenMP parallel computing mode</b></p>\r
+<p>\r
+    SoundTouch supports OpenMP for parallel computing in multi-core \r
+       environments, and these improvements can be enabled also in the Android \r
+       build. See the SoundTouch main README.html file for generic notes about the \r
+       OpenMP implementation.</p>\r
+<p>\r
+    To enable OpenMP mode in Android compilation, edit file <strong>Android.mk</strong> \r
+       and enable the &quot;-fopenmp&quot; flag in LOCAL_CFLAGS and LOCAL_LDFLAGS variables. \r
+       This is done by removing hash # from before the following lines in the \r
+       Android.mk file, before compiling the library:</p>\r
+<pre>    LOCAL_CFLAGS += -fopenmp\r
+   LOCAL_LDFLAGS += -fopenmp</pre>\r
+<p><strong>OpenMP COMPATIBILITY NOTE: </strong>Android NDK has a threading issue \r
+(at least until NDK v10) that causes the native library crash with fatal signal \r
+11 if calling OpenMP-improved routines from a background thread. SoundTouch has \r
+a workaround for this issue in soundtouch-jni.cpp, and this workaround requires \r
+calling function <strong>SoundTouch.getVersionString() </strong>from the Android \r
+application's main thread at least once before calling other SoundTouch \r
+processing routines. See the SoundTouch Android example application and comments \r
+in the <strong>soundtouch-jni.cpp </strong>source code file for more details.</p>\r
+<p>\r
+    <strong>SoundTouch performance in Android</strong></p>\r
+<p>\r
+    See external blog articles for more discussion about the\r
+       <a href="http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices/">\r
+       SoundTouch OpenMP implementation</a> and the\r
+       <a href="http://www.softwarecoven.com/parallel-computing-with-openmp-in-android/">\r
+       SoundTouch performance benchmark tests in Android environment</a>.</p>\r
+<hr />\r
+<h2>\r
+    Calling SoundTouch native routines from Android application</h2>\r
+    <p>The NDK tools build the SoundTouch c++ routines into a native binary library, while \r
+    Android applications are written in Java language. To call the SoundTouch and other c/c++ \r
+    routines from an Android java application code, you'll need to use Java Native \r
+    Interface (JNI).</p>\r
+    <p>\r
+        The SoundTouch source code package provides source code example how to \r
+        use JNI to call native c++ routines from a Java class, and provides source codes also for\r
+       a simple example Android application:<ul>\r
+       <li><b>ExampleActivity</b>: This is simple Android example application that\r
+       utilizes SoundTouch native routines for processing WAV audio files. To build the example\r
+       application, use Eclipse Android SDK environment to import the "ExampleActivity" project in the         "Android-lib" folder into the Eclipse workspace. \r
+        <li><b>Android-lib/jni/soundtouch-jni.cpp</b>: This file contains c/c++ wrapper routines\r
+       for performing elementary audio file processing with adjusted tempo/pitch/speed parameters\r
+       from the Android application. The wrapper interface is not complete, but provides example\r
+       that is easy to extend when necessary. The NDK compiles this file along with the SoundTouch \r
+            routines into the native binary library.</li>\r
+        <li><b>Android-lib/src/net/surina/soundtouch/SoundTouch.java</b>: This file implements\r
+       the Java interface class that loasd & accesses the JNI routines in the natively compiled library.\r
+       The example Android application uses this class as interface for processing audio files \r
+       with SoundTouch.</li>\r
+    </ul>\r
+<p>\r
+        Feel free to examine and extend the provided cpp/java source code example file pair to \r
+        implement and integrate the desired SoundTouch library capabilities into your own Android application.</p>\r
+<hr />\r
+<h2>\r
+    Android floating-point performance considerations</h2>\r
+<p>\r
+        The make process will build dedicated binaries for each supported Android CPU hardware platform type.\r
+</p><p>SoundTouch uses floating-point algorithms for ideal sound quality on all other platform than in the lowest-end ARMv5. That is because lowest-end Android devices are not guaranteed to \r
+        have floating-point hardware in their CPUs, so that the ARMv5 compilation uses by default software-emulation for floating-point calculations to allow running the binary executables also in low-end devices without floating-point hardware.<p>\r
+        As floating point software-emulation is however several tens of times slower \r
+        than real hardware-level floating-point calculations, that would make running\r
+        floating-point-intensive applications such as SoundTouch infeasible in these low-end \r
+        devices. As workaround, the SoundTouch Android compilation builds the ARMv5 version using integer algorithm versions. The integer \r
+            algorithm version compromises the sound quality but provides good performance also \r
+            with low-end devices without hardware floating-point support in the CPU level.</p>\r
+        <p>When Android devices with more capable device is used, the device will automatically choose a proper library version for ideal sound quality.</p>\r
+<hr />\r
+    <p style="text-align: center"><i>Copyright &copy; Olli Parviainen</i></p>\r
+</body>\r
+</html>\r
diff --git a/source/Android-lib/jni/Android.mk b/source/Android-lib/jni/Android.mk
new file mode 100644 (file)
index 0000000..778ed89
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# *** Remember: Change -O0 into -O2 in add-applications.mk ***
+
+LOCAL_MODULE    := soundtouch
+LOCAL_SRC_FILES := soundtouch-jni.cpp ../../SoundTouch/AAFilter.cpp  ../../SoundTouch/FIFOSampleBuffer.cpp \
+                ../../SoundTouch/FIRFilter.cpp ../../SoundTouch/cpu_detect_x86.cpp \
+                ../../SoundTouch/sse_optimized.cpp ../../SoundStretch/WavFile.cpp \
+                ../../SoundTouch/RateTransposer.cpp ../../SoundTouch/SoundTouch.cpp \
+                ../../SoundTouch/InterpolateCubic.cpp ../../SoundTouch/InterpolateLinear.cpp \
+                ../../SoundTouch/InterpolateShannon.cpp ../../SoundTouch/TDStretch.cpp \
+                ../../SoundTouch/BPMDetect.cpp ../../SoundTouch/PeakFinder.cpp 
+
+# for native audio
+LOCAL_SHARED_LIBRARIES += -lgcc 
+# --whole-archive -lgcc 
+# for logging
+LOCAL_LDLIBS    += -llog
+# for native asset manager
+#LOCAL_LDLIBS    += -landroid
+
+# Custom Flags: 
+# -fvisibility=hidden : don't export all symbols
+LOCAL_CFLAGS += -fvisibility=hidden -I ../../../include -fdata-sections -ffunction-sections
+
+# OpenMP mode : enable these flags to enable using OpenMP for parallel computation 
+#LOCAL_CFLAGS += -fopenmp
+#LOCAL_LDFLAGS += -fopenmp
+
+
+# Use ARM instruction set instead of Thumb for improved calculation performance in ARM CPUs    
+LOCAL_ARM_MODE := arm
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/source/Android-lib/jni/Application.mk b/source/Android-lib/jni/Application.mk
new file mode 100644 (file)
index 0000000..122fb12
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Build library bilaries for all supported architectures
+#
+
+APP_ABI := all #armeabi-v7a armeabi
+APP_OPTIM := release
+APP_STL := stlport_static
+APP_CPPFLAGS := -fexceptions # -D SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
+
diff --git a/source/Android-lib/jni/soundtouch-jni.cpp b/source/Android-lib/jni/soundtouch-jni.cpp
new file mode 100644 (file)
index 0000000..6383fe4
--- /dev/null
@@ -0,0 +1,255 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Example Interface class for SoundTouch native compilation\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// WWW           : http://www.surina.net\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <jni.h>\r
+#include <android/log.h>\r
+#include <stdexcept>\r
+#include <string>\r
+\r
+using namespace std;\r
+\r
+#include "../../../include/SoundTouch.h"\r
+#include "../source/SoundStretch/WavFile.h"\r
+\r
+#define LOGV(...)   __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)\r
+//#define LOGV(...)\r
+\r
+\r
+// String for keeping possible c++ exception error messages. Notice that this isn't\r
+// thread-safe but it's expected that exceptions are special situations that won't\r
+// occur in several threads in parallel.\r
+static string _errMsg = "";\r
+\r
+\r
+#define DLL_PUBLIC __attribute__ ((visibility ("default")))\r
+#define BUFF_SIZE 4096\r
+\r
+\r
+using namespace soundtouch;\r
+\r
+\r
+// Set error message to return\r
+static void _setErrmsg(const char *msg)\r
+{\r
+       _errMsg = msg;\r
+}\r
+\r
+\r
+#ifdef _OPENMP\r
+\r
+#include <pthread.h>\r
+extern pthread_key_t gomp_tls_key;\r
+static void * _p_gomp_tls = NULL;\r
+\r
+/// Function to initialize threading for OpenMP.\r
+///\r
+/// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if\r
+/// called from the Android App main thread because in the main thread the gomp_tls storage is\r
+/// properly set, however, Android does not properly initialize gomp_tls storage for other threads.\r
+/// Thus if OpenMP routines are invoked from some other thread than the main thread,\r
+/// the OpenMP routine will crash the application due to NULL pointer access on uninitialized storage.\r
+///\r
+/// This workaround stores the gomp_tls storage from main thread, and copies to other threads.\r
+/// In order this to work, the Application main thread needws to call at least "getVersionString"\r
+/// routine.\r
+static int _init_threading(bool warn)\r
+{\r
+       void *ptr = pthread_getspecific(gomp_tls_key);\r
+       LOGV("JNI thread-specific TLS storage %ld", (long)ptr);\r
+       if (ptr == NULL)\r
+       {\r
+               LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);\r
+               pthread_setspecific(gomp_tls_key, _p_gomp_tls);\r
+       }\r
+       else\r
+       {\r
+               LOGV("JNI store this TLS storage");\r
+               _p_gomp_tls = ptr;\r
+       }\r
+       // Where critical, show warning if storage still not properly initialized\r
+       if ((warn) && (_p_gomp_tls == NULL))\r
+       {\r
+               _setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");\r
+               return -1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+#else\r
+static int _init_threading(bool warn)\r
+{\r
+       // do nothing if not OpenMP build\r
+       return 0;\r
+}\r
+#endif\r
+\r
+\r
+// Processes the sound file\r
+static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)\r
+{\r
+    int nSamples;\r
+    int nChannels;\r
+    int buffSizeSamples;\r
+    SAMPLETYPE sampleBuffer[BUFF_SIZE];\r
+\r
+    // open input file\r
+    WavInFile inFile(inFileName);\r
+    int sampleRate = inFile.getSampleRate();\r
+    int bits = inFile.getNumBits();\r
+    nChannels = inFile.getNumChannels();\r
+\r
+    // create output file\r
+    WavOutFile outFile(outFileName, sampleRate, bits, nChannels);\r
+\r
+    pSoundTouch->setSampleRate(sampleRate);\r
+    pSoundTouch->setChannels(nChannels);\r
+\r
+    assert(nChannels > 0);\r
+    buffSizeSamples = BUFF_SIZE / nChannels;\r
+\r
+    // Process samples read from the input file\r
+    while (inFile.eof() == 0)\r
+    {\r
+        int num;\r
+\r
+        // Read a chunk of samples from the input file\r
+        num = inFile.read(sampleBuffer, BUFF_SIZE);\r
+        nSamples = num / nChannels;\r
+\r
+        // Feed the samples into SoundTouch processor\r
+        pSoundTouch->putSamples(sampleBuffer, nSamples);\r
+\r
+        // Read ready samples from SoundTouch processor & write them output file.\r
+        // NOTES:\r
+        // - 'receiveSamples' doesn't necessarily return any samples at all\r
+        //   during some rounds!\r
+        // - On the other hand, during some round 'receiveSamples' may have more\r
+        //   ready samples than would fit into 'sampleBuffer', and for this reason\r
+        //   the 'receiveSamples' call is iterated for as many times as it\r
+        //   outputs samples.\r
+        do\r
+        {\r
+            nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);\r
+            outFile.write(sampleBuffer, nSamples * nChannels);\r
+        } while (nSamples != 0);\r
+    }\r
+\r
+    // Now the input file is processed, yet 'flush' few last samples that are\r
+    // hiding in the SoundTouch's internal processing pipeline.\r
+    pSoundTouch->flush();\r
+    do\r
+    {\r
+        nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);\r
+        outFile.write(sampleBuffer, nSamples * nChannels);\r
+    } while (nSamples != 0);\r
+}\r
+\r
+\r
+\r
+extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)\r
+{\r
+    const char *verStr;\r
+\r
+    LOGV("JNI call SoundTouch.getVersionString");\r
+\r
+    // Call example SoundTouch routine\r
+    verStr = SoundTouch::getVersionString();\r
+\r
+    /// gomp_tls storage bug workaround - see comments in _init_threading() function!\r
+    _init_threading(false);\r
+\r
+    int threads = 0;\r
+       #pragma omp parallel\r
+    {\r
+               #pragma omp atomic\r
+       threads ++;\r
+    }\r
+    LOGV("JNI thread count %d", threads);\r
+\r
+    // return version as string\r
+    return env->NewStringUTF(verStr);\r
+}\r
+\r
+\r
+\r
+extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)\r
+{\r
+       return (jlong)(new SoundTouch());\r
+}\r
+\r
+\r
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)\r
+{\r
+       SoundTouch *ptr = (SoundTouch*)handle;\r
+       delete ptr;\r
+}\r
+\r
+\r
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)\r
+{\r
+       SoundTouch *ptr = (SoundTouch*)handle;\r
+       ptr->setTempo(tempo);\r
+}\r
+\r
+\r
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)\r
+{\r
+       SoundTouch *ptr = (SoundTouch*)handle;\r
+       ptr->setPitchSemiTones(pitch);\r
+}\r
+\r
+\r
+extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)\r
+{\r
+       SoundTouch *ptr = (SoundTouch*)handle;\r
+       ptr->setRate(speed);\r
+}\r
+\r
+\r
+extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)\r
+{\r
+       jstring result = env->NewStringUTF(_errMsg.c_str());\r
+       _errMsg.clear();\r
+\r
+       return result;\r
+}\r
+\r
+\r
+extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)\r
+{\r
+       SoundTouch *ptr = (SoundTouch*)handle;\r
+\r
+       const char *inputFile = env->GetStringUTFChars(jinputFile, 0);\r
+       const char *outputFile = env->GetStringUTFChars(joutputFile, 0);\r
+\r
+       LOGV("JNI process file %s", inputFile);\r
+\r
+    /// gomp_tls storage bug workaround - see comments in _init_threading() function!\r
+    if (_init_threading(true)) return -1;\r
+\r
+       try\r
+       {\r
+               _processFile(ptr, inputFile, outputFile);\r
+       }\r
+       catch (const runtime_error &e)\r
+    {\r
+               const char *err = e.what();\r
+        // An exception occurred during processing, return the error message\r
+       LOGV("JNI exception in SoundTouch::processFile: %s", err);\r
+        _setErrmsg(err);\r
+        return -1;\r
+    }\r
+\r
+\r
+       env->ReleaseStringUTFChars(jinputFile, inputFile);\r
+       env->ReleaseStringUTFChars(joutputFile, outputFile);\r
+\r
+       return 0;\r
+}\r
diff --git a/source/Android-lib/lint.xml b/source/Android-lib/lint.xml
new file mode 100644 (file)
index 0000000..ee0eead
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<lint>
+</lint>
\ No newline at end of file
diff --git a/source/Android-lib/proguard-project.txt b/source/Android-lib/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/source/Android-lib/project.properties b/source/Android-lib/project.properties
new file mode 100644 (file)
index 0000000..4ab1256
--- /dev/null
@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-19
diff --git a/source/Android-lib/res/drawable-hdpi/ic_launcher.png b/source/Android-lib/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..288b665
Binary files /dev/null and b/source/Android-lib/res/drawable-hdpi/ic_launcher.png differ
diff --git a/source/Android-lib/res/drawable-mdpi/ic_launcher.png b/source/Android-lib/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..6ae570b
Binary files /dev/null and b/source/Android-lib/res/drawable-mdpi/ic_launcher.png differ
diff --git a/source/Android-lib/res/drawable-xhdpi/ic_launcher.png b/source/Android-lib/res/drawable-xhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..d4fb7cd
Binary files /dev/null and b/source/Android-lib/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/source/Android-lib/res/drawable-xxhdpi/ic_launcher.png b/source/Android-lib/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..85a6081
Binary files /dev/null and b/source/Android-lib/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/source/Android-lib/res/layout/activity_example.xml b/source/Android-lib/res/layout/activity_example.xml
new file mode 100644 (file)
index 0000000..c71c77d
--- /dev/null
@@ -0,0 +1,140 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/linearLayout1"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <TableLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <TableRow
+            android:id="@+id/tableRow1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" >
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Tempo %:"
+                android:textAppearance="?android:attr/textAppearanceMedium" />
+
+            <EditText
+                android:id="@+id/editTextTempo"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ems="5"
+                android:inputType="text"
+                android:text="100" >
+            </EditText>
+        </TableRow>
+
+        <TableRow
+            android:id="@+id/tableRow2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" >
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="Pitch half-steps:"
+                android:textAppearance="?android:attr/textAppearanceMedium" />
+
+            <EditText
+                android:id="@+id/editTextPitch"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ems="5"
+                android:inputType="text"
+                android:text="-0.318" >
+            </EditText>
+        </TableRow>
+    </TableLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp" >
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Source file:"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <EditText
+            android:id="@+id/editTextSrcFileName"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="/sdcard/Download/test.wav"
+            android:layout_weight="1" />
+               
+
+        <Button
+            android:id="@+id/buttonSelectSrcFile"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Select" />
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" >
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Output file:"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <EditText
+            android:id="@+id/editTextOutFileName"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:text="/sdcard/Download/soundtouch-output.wav"
+            android:layout_weight="1" />
+
+        <Button
+            android:id="@+id/buttonSelectOutFile"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Select" />
+    </LinearLayout>
+
+    <CheckBox
+        android:id="@+id/checkBoxPlay"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:text="Play the output file after processing!" />
+
+    <Button
+        android:id="@+id/buttonProcess"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:text="Process file!" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dp"
+        android:text="Status console:"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    <ScrollView
+        android:id="@+id/scrollView1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" >
+
+        <TextView
+        android:id="@+id/textViewResult"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:text="@string/hello_world" />
+
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/source/Android-lib/res/values/strings.xml b/source/Android-lib/res/values/strings.xml
new file mode 100644 (file)
index 0000000..7403f9f
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">SoundTouch Example</string>
+    <string name="hello_world">Hello world!</string>
+
+</resources>
diff --git a/source/Android-lib/res/values/styles.xml b/source/Android-lib/res/values/styles.xml
new file mode 100644 (file)
index 0000000..13a7798
--- /dev/null
@@ -0,0 +1,20 @@
+<resources>
+
+    <!--
+        Base application theme, dependent on API level. This theme is replaced
+        by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+    -->
+    <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+        <!--
+            Theme customizations available in newer API levels can go in
+            res/values-vXX/styles.xml, while customizations related to
+            backward-compatibility can go here.
+        -->
+    </style>
+
+    <!-- Application theme. -->
+    <style name="AppTheme" parent="AppBaseTheme">
+        <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+    </style>
+
+</resources>
diff --git a/source/Android-lib/src/net/surina/ExampleActivity.java b/source/Android-lib/src/net/surina/ExampleActivity.java
new file mode 100644 (file)
index 0000000..53a3345
--- /dev/null
@@ -0,0 +1,219 @@
+/////////////////////////////////////////////////////////////////////////////
+///
+/// Example Android Application/Activity that allows processing WAV 
+/// audio files with SoundTouch library
+///
+/// Copyright (c) Olli Parviainen
+///
+////////////////////////////////////////////////////////////////////////////////
+
+package net.surina;
+
+import java.io.File;
+
+import net.surina.soundtouch.SoundTouch;
+import net.surina.soundtouchexample.R;
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class ExampleActivity extends Activity implements OnClickListener 
+{
+       TextView textViewConsole = null;
+       EditText editSourceFile = null;
+       EditText editOutputFile = null;
+       EditText editTempo = null;
+       EditText editPitch = null;
+       CheckBox checkBoxPlay = null;
+       
+       StringBuilder consoleText = new StringBuilder();
+
+       
+       /// Called when the activity is created
+       @Override
+       protected void onCreate(Bundle savedInstanceState) 
+       {
+               super.onCreate(savedInstanceState);
+               setContentView(R.layout.activity_example);
+               
+               textViewConsole = (TextView)findViewById(R.id.textViewResult);
+               editSourceFile = (EditText)findViewById(R.id.editTextSrcFileName);
+               editOutputFile = (EditText)findViewById(R.id.editTextOutFileName);
+
+               editTempo = (EditText)findViewById(R.id.editTextTempo);
+               editPitch = (EditText)findViewById(R.id.editTextPitch);
+               
+               Button buttonFileSrc = (Button)findViewById(R.id.buttonSelectSrcFile);
+               Button buttonFileOutput = (Button)findViewById(R.id.buttonSelectOutFile);
+               Button buttonProcess = (Button)findViewById(R.id.buttonProcess);
+               buttonFileSrc.setOnClickListener(this);
+               buttonFileOutput.setOnClickListener(this);
+               buttonProcess.setOnClickListener(this);
+
+               checkBoxPlay = (CheckBox)findViewById(R.id.checkBoxPlay);
+
+               // Check soundtouch library presence & version
+               checkLibVersion();
+       }
+       
+       
+               
+       /// Function to append status text onto "console box" on the Activity
+       public void appendToConsole(final String text)
+       {
+               // run on UI thread to avoid conflicts
+               runOnUiThread(new Runnable() 
+               {
+                   public void run() 
+                   {
+                               consoleText.append(text);
+                               consoleText.append("\n");
+                               textViewConsole.setText(consoleText);
+                   }
+               });
+       }
+       
+
+       
+       /// print SoundTouch native library version onto console
+       protected void checkLibVersion()
+       {
+               String ver = SoundTouch.getVersionString();
+               appendToConsole("SoundTouch native library version = " + ver);
+       }
+
+
+
+       /// Button click handler
+       @Override
+       public void onClick(View arg0) 
+       {
+               switch (arg0.getId())
+               {
+                       case R.id.buttonSelectSrcFile:
+                       case R.id.buttonSelectOutFile:
+                               // one of the file select buttons clicked ... we've not just implemented them ;-)
+                               Toast.makeText(this, "File selector not implemented, sorry! Enter the file path manually ;-)", Toast.LENGTH_LONG).show();
+                               break;
+                               
+                       case R.id.buttonProcess:
+                               // button "process" pushed
+                               process();
+                               break;                                          
+               }
+               
+       }
+       
+       
+       /// Play audio file
+       protected void playWavFile(String fileName)
+       {
+               File file2play = new File(fileName);
+               Intent i = new Intent();
+               i.setAction(android.content.Intent.ACTION_VIEW);
+               i.setDataAndType(Uri.fromFile(file2play), "audio/wav");
+               startActivity(i);               
+       }
+       
+                               
+
+       /// Helper class that will execute the SoundTouch processing. As the processing may take
+       /// some time, run it in background thread to avoid hanging of the UI.
+       protected class ProcessTask extends AsyncTask<ProcessTask.Parameters, Integer, Long>
+       {
+               /// Helper class to store the SoundTouch file processing parameters
+               public final class Parameters
+               {
+                       String inFileName;
+                       String outFileName;
+                       float tempo;
+                       float pitch;
+               }
+
+               
+               
+               /// Function that does the SoundTouch processing
+               public final long doSoundTouchProcessing(Parameters params) 
+               {
+                       
+                       SoundTouch st = new SoundTouch();
+                       st.setTempo(params.tempo);
+                       st.setPitchSemiTones(params.pitch);
+                       Log.i("SoundTouch", "process file " + params.inFileName);
+                       long startTime = System.currentTimeMillis();
+                       int res = st.processFile(params.inFileName, params.outFileName);
+                       long endTime = System.currentTimeMillis();
+                       float duration = (endTime - startTime) * 0.001f;
+                       
+                       Log.i("SoundTouch", "process file done, duration = " + duration);
+                       appendToConsole("Processing done, duration " + duration + " sec.");
+                       if (res != 0)
+                       {
+                               String err = SoundTouch.getErrorString();
+                               appendToConsole("Failure: " + err);
+                               return -1L;
+                       }
+                       
+                       // Play file if so is desirable
+                       if (checkBoxPlay.isChecked())
+                       {
+                               playWavFile(params.outFileName);
+                       }
+                       return 0L;
+               }
+
+
+               
+               /// Overloaded function that get called by the system to perform the background processing
+               @Override       
+               protected Long doInBackground(Parameters... aparams) 
+               {
+                       return doSoundTouchProcessing(aparams[0]);
+               }
+               
+       }
+
+
+       /// process a file with SoundTouch. Do the processing using a background processing
+       /// task to avoid hanging of the UI
+       protected void process()
+       {
+               try 
+               {
+                       ProcessTask task = new ProcessTask();
+                       ProcessTask.Parameters params = task.new Parameters();
+                       // parse processing parameters
+                       params.inFileName = editSourceFile.getText().toString();
+                       params.outFileName = editOutputFile.getText().toString();
+                       params.tempo = 0.01f * Float.parseFloat(editTempo.getText().toString());
+                       params.pitch = Float.parseFloat(editPitch.getText().toString());
+
+                       // update UI about status
+                       appendToConsole("Process audio file :" + params.inFileName +" => " + params.outFileName);
+                       appendToConsole("Tempo = " + params.tempo);
+                       appendToConsole("Pitch adjust = " + params.pitch);
+                       
+                       Toast.makeText(this, "Starting to process file " + params.inFileName + "...", Toast.LENGTH_SHORT).show();
+
+                       // start SoundTouch processing in a background thread
+                       task.execute(params);
+//                     task.doSoundTouchProcessing(params);    // this would run processing in main thread
+                       
+               }
+               catch (Exception exp)
+               {
+                       exp.printStackTrace();
+               }
+       
+       }
+}
\ No newline at end of file
diff --git a/source/Android-lib/src/net/surina/soundtouch/SoundTouch.java b/source/Android-lib/src/net/surina/soundtouch/SoundTouch.java
new file mode 100644 (file)
index 0000000..38ea4d9
--- /dev/null
@@ -0,0 +1,79 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Example class that invokes native SoundTouch routines through the JNI\r
+/// interface.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// WWW           : http://www.surina.net\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+package net.surina.soundtouch;\r
+\r
+public final class SoundTouch\r
+{\r
+    // Native interface function that returns SoundTouch version string.\r
+    // This invokes the native c++ routine defined in "soundtouch-jni.cpp".\r
+    public native final static String getVersionString();\r
+    \r
+    private native final void setTempo(long handle, float tempo);\r
+\r
+    private native final void setPitchSemiTones(long handle, float pitch);\r
+    \r
+    private native final void setSpeed(long handle, float speed);\r
+\r
+    private native final int processFile(long handle, String inputFile, String outputFile);\r
+\r
+    public native final static String getErrorString();\r
+\r
+    private native final static long newInstance();\r
+    \r
+    private native final void deleteInstance(long handle);\r
+    \r
+    long handle = 0;\r
+    \r
+    \r
+    public SoundTouch()\r
+    {\r
+       handle = newInstance();         \r
+    }\r
+    \r
+    \r
+    public void close()\r
+    {\r
+       deleteInstance(handle);\r
+       handle = 0;\r
+    }\r
+\r
+\r
+    public void setTempo(float tempo)\r
+    {\r
+       setTempo(handle, tempo);\r
+    }\r
+\r
+\r
+    public void setPitchSemiTones(float pitch)\r
+    {\r
+       setPitchSemiTones(handle, pitch);\r
+    }\r
+\r
+    \r
+    public void setSpeed(float speed)\r
+    {\r
+       setSpeed(handle, speed);\r
+    }\r
+\r
+\r
+    public int processFile(String inputFile, String outputFile)\r
+    {\r
+       return processFile(handle, inputFile, outputFile);\r
+    }\r
+\r
+    \r
+    // Load the native library upon startup\r
+    static\r
+    {\r
+        System.loadLibrary("soundtouch");\r
+    }\r
+}\r
diff --git a/source/Makefile.am b/source/Makefile.am
new file mode 100644 (file)
index 0000000..f5c3edb
--- /dev/null
@@ -0,0 +1,24 @@
+## Process this file with automake to create Makefile.in\r
+##\r
+## This file is part of SoundTouch, an audio processing library for pitch/time adjustments\r
+## \r
+## SoundTouch is free software; you can redistribute it and/or modify it under the\r
+## terms of the GNU General Public License as published by the Free Software\r
+## Foundation; either version 2 of the License, or (at your option) any later\r
+## version.\r
+## \r
+## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY\r
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+## A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r
+## \r
+## You should have received a copy of the GNU General Public License along with\r
+## this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
+## Place - Suite 330, Boston, MA  02111-1307, USA\r
+\r
+include $(top_srcdir)/config/am_include.mk\r
+\r
+SUBDIRS=SoundTouch SoundStretch\r
+\r
+# set to something if you want other stuff to be included in the distribution tarball\r
+#EXTRA_DIST=\r
+\r
diff --git a/source/SoundStretch/Makefile.am b/source/SoundStretch/Makefile.am
new file mode 100644 (file)
index 0000000..ac5292c
--- /dev/null
@@ -0,0 +1,50 @@
+## Process this file with automake to create Makefile.in\r
+## \r
+## This file is part of SoundTouch, an audio processing library for pitch/time adjustments\r
+## \r
+## SoundTouch is free software; you can redistribute it and/or modify it under the\r
+## terms of the GNU General Public License as published by the Free Software\r
+## Foundation; either version 2 of the License, or (at your option) any later\r
+## version.\r
+## \r
+## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY\r
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+## A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r
+## \r
+## You should have received a copy of the GNU General Public License along with\r
+## this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
+## Place - Suite 330, Boston, MA  02111-1307, USA\r
+\r
+include $(top_srcdir)/config/am_include.mk\r
+\r
+\r
+## bin_PROGRAMS is the macro that tells automake the name of the programs to\r
+## install in the bin directory (/usr/local/bin) by default. By setting\r
+## --prefix= at configure time the user can change this (eg: ./configure\r
+## --prefix=/usr will install soundstretch under /usr/bin/soundstretch )\r
+bin_PROGRAMS=soundstretch\r
+\r
+noinst_HEADERS=RunParameters.h WavFile.h\r
+\r
+# extra files to include in distribution tarball\r
+EXTRA_DIST=soundstretch.sln soundstretch.vcxproj\r
+\r
+## for every name listed under bin_PROGRAMS, you have a <prog>_SOURCES. This lists\r
+## all the sources in the current directory that are used to build soundstretch.\r
+soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp \r
+\r
+## soundstretch_LDADD is a list of extras to pass at link time. All the objects\r
+## created by the above soundstretch_SOURCES are automatically linked in, so here I\r
+## list object files from other directories as well as flags passed to the\r
+## linker. \r
+soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm\r
+\r
+## linker flags. \r
+# OP 2011-7-17 Linker flag -s disabled to prevent stripping symbols by default\r
+#soundstretch_LDFLAGS=-s\r
+\r
+## additional compiler flags\r
+soundstretch_CXXFLAGS=-O3 $(AM_CXXFLAGS)\r
+\r
+#clean-local: \r
+#      -rm -f additional-files-to-remove-on-make-clean\r
diff --git a/source/SoundStretch/RunParameters.cpp b/source/SoundStretch/RunParameters.cpp
new file mode 100644 (file)
index 0000000..1960a35
--- /dev/null
@@ -0,0 +1,291 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// A class for parsing the 'soundstretch' application command line parameters\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <string>\r
+#include <stdlib.h>\r
+\r
+#include "RunParameters.h"\r
+\r
+using namespace std;\r
+\r
+// Program usage instructions \r
+\r
+static const char licenseText[] = \r
+    "    LICENSE:\n"\r
+    "    ========\n"\r
+    "    \n"\r
+    "    SoundTouch sound processing library\n"\r
+    "    Copyright (c) Olli Parviainen\n"\r
+    "    \n"\r
+    "    This library is free software; you can redistribute it and/or\n"\r
+    "    modify it under the terms of the GNU Lesser General Public\n"\r
+    "    License version 2.1 as published by the Free Software Foundation.\n"\r
+    "    \n"\r
+    "    This library is distributed in the hope that it will be useful,\n"\r
+    "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"\r
+    "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"\r
+    "    Lesser General Public License for more details.\n"\r
+    "    \n"\r
+    "    You should have received a copy of the GNU Lesser General Public\n"\r
+    "    License along with this library; if not, write to the Free Software\n"\r
+    "    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"\r
+    "    \n"\r
+    "This application is distributed with full source codes; however, if you\n"\r
+    "didn't receive them, please visit the author's homepage (see the link above).";\r
+\r
+static const char whatText[] = \r
+    "This application processes WAV audio files by modifying the sound tempo,\n"\r
+    "pitch and playback rate properties independently from each other.\n"\r
+    "\n";\r
+\r
+static const char usage[] = \r
+    "Usage :\n"\r
+    "    soundstretch infilename outfilename [switches]\n"\r
+    "\n"\r
+    "To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"\r
+    "\n"\r
+    "Available switches are:\n"\r
+    "  -tempo=n : Change sound tempo by n percents  (n=-95..+5000 %)\n"\r
+    "  -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"\r
+    "  -rate=n  : Change sound rate by n percents   (n=-95..+5000 %)\n"\r
+    "  -bpm=n   : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n"\r
+    "             If '=n' is omitted, just detects the BPM rate.\n"\r
+    "  -quick   : Use quicker tempo change algorithm (gain speed, lose quality)\n"\r
+    "  -naa     : Don't use anti-alias filtering (gain speed, lose quality)\n"\r
+    "  -speech  : Tune algorithm for speech processing (default is for music)\n"\r
+    "  -license : Display the program license text (LGPL)\n";\r
+\r
+\r
+// Converts a char into lower case\r
+static int _toLowerCase(int c)\r
+{\r
+    if (c >= 'A' && c <= 'Z') \r
+    {\r
+        c += 'a' - 'A';\r
+    }\r
+    return c;\r
+}\r
+\r
+\r
+// Constructor\r
+RunParameters::RunParameters(const int nParams, const char * const paramStr[])\r
+{\r
+    int i;\r
+    int nFirstParam;\r
+\r
+    if (nParams < 3) \r
+    {\r
+        // Too few parameters\r
+        if (nParams > 1 && paramStr[1][0] == '-' && \r
+            _toLowerCase(paramStr[1][1]) == 'l') \r
+        {\r
+            // '-license' switch\r
+            throwLicense();\r
+        }\r
+        string msg = whatText;\r
+        msg += usage;\r
+        ST_THROW_RT_ERROR(msg.c_str());\r
+    }\r
+\r
+    inFileName = NULL;\r
+    outFileName = NULL;\r
+    tempoDelta = 0;\r
+    pitchDelta = 0;\r
+    rateDelta = 0;\r
+    quick = 0;\r
+    noAntiAlias = 0;\r
+    goalBPM = 0;\r
+    speech = false;\r
+    detectBPM = false;\r
+\r
+    // Get input & output file names\r
+    inFileName = (char*)paramStr[1];\r
+    outFileName = (char*)paramStr[2];\r
+\r
+    if (outFileName[0] == '-')\r
+    {\r
+        // no outputfile name was given but parameters\r
+        outFileName = NULL;\r
+        nFirstParam = 2;\r
+    }\r
+    else\r
+    {\r
+        nFirstParam = 3;\r
+    }\r
+\r
+    // parse switch parameters\r
+    for (i = nFirstParam; i < nParams; i ++) \r
+    {\r
+        parseSwitchParam(paramStr[i]);\r
+    }\r
+\r
+    checkLimits();\r
+}\r
+\r
+\r
+// Checks parameter limits\r
+void RunParameters::checkLimits()\r
+{\r
+    if (tempoDelta < -95.0f) \r
+    {\r
+        tempoDelta = -95.0f;\r
+    } \r
+    else if (tempoDelta > 5000.0f) \r
+    {\r
+        tempoDelta = 5000.0f;\r
+    }\r
+\r
+    if (pitchDelta < -60.0f) \r
+    {\r
+        pitchDelta = -60.0f;\r
+    } \r
+    else if (pitchDelta > 60.0f) \r
+    {\r
+        pitchDelta = 60.0f;\r
+    }\r
+\r
+    if (rateDelta < -95.0f) \r
+    {\r
+        rateDelta = -95.0f;\r
+    } \r
+    else if (rateDelta > 5000.0f) \r
+    {\r
+        rateDelta = 5000.0f;\r
+    }\r
+}\r
+\r
+\r
+// Unknown switch parameter -- throws an exception with an error message\r
+void RunParameters::throwIllegalParamExp(const string &str) const\r
+{\r
+    string msg = "ERROR : Illegal parameter \"";\r
+    msg += str;\r
+    msg += "\".\n\n";\r
+    msg += usage;\r
+    ST_THROW_RT_ERROR(msg.c_str());\r
+}\r
+\r
+\r
+void RunParameters::throwLicense() const\r
+{\r
+    ST_THROW_RT_ERROR(licenseText);\r
+}\r
+\r
+\r
+float RunParameters::parseSwitchValue(const string &str) const\r
+{\r
+    int pos;\r
+\r
+    pos = (int)str.find_first_of('=');\r
+    if (pos < 0) \r
+    {\r
+        // '=' missing\r
+        throwIllegalParamExp(str);\r
+    }\r
+\r
+    // Read numerical parameter value after '='\r
+    return (float)atof(str.substr(pos + 1).c_str());\r
+}\r
+\r
+\r
+// Interprets a single switch parameter string of format "-switch=xx"\r
+// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores\r
+// switch values into 'params' structure.\r
+void RunParameters::parseSwitchParam(const string &str)\r
+{\r
+    int upS;\r
+\r
+    if (str[0] != '-') \r
+    {\r
+        // leading hyphen missing => not a valid parameter\r
+        throwIllegalParamExp(str);\r
+    }\r
+\r
+    // Take the first character of switch name & change to lower case\r
+    upS = _toLowerCase(str[1]);\r
+\r
+    // interpret the switch name & operate accordingly\r
+    switch (upS) \r
+    {\r
+        case 't' :\r
+            // switch '-tempo=xx'\r
+            tempoDelta = parseSwitchValue(str);\r
+            break;\r
+\r
+        case 'p' :\r
+            // switch '-pitch=xx'\r
+            pitchDelta = parseSwitchValue(str);\r
+            break;\r
+\r
+        case 'r' :\r
+            // switch '-rate=xx'\r
+            rateDelta = parseSwitchValue(str);\r
+            break;\r
+\r
+        case 'b' :\r
+            // switch '-bpm=xx'\r
+            detectBPM = true;\r
+            try\r
+            {\r
+                goalBPM = parseSwitchValue(str);\r
+            } \r
+            catch (const runtime_error &)\r
+            {\r
+                // illegal or missing bpm value => just calculate bpm\r
+                goalBPM = 0;\r
+            }\r
+            break;\r
+\r
+        case 'q' :\r
+            // switch '-quick'\r
+            quick = 1;\r
+            break;\r
+\r
+        case 'n' :\r
+            // switch '-naa'\r
+            noAntiAlias = 1;\r
+            break;\r
+\r
+        case 'l' :\r
+            // switch '-license'\r
+            throwLicense();\r
+            break;\r
+\r
+        case 's' :\r
+            // switch '-speech'\r
+            speech = true;\r
+            break;\r
+\r
+        default:\r
+            // unknown switch\r
+            throwIllegalParamExp(str);\r
+    }\r
+}\r
diff --git a/source/SoundStretch/RunParameters.h b/source/SoundStretch/RunParameters.h
new file mode 100644 (file)
index 0000000..6c0142b
--- /dev/null
@@ -0,0 +1,65 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// A class for parsing the 'soundstretch' application command line parameters\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef RUNPARAMETERS_H\r
+#define RUNPARAMETERS_H\r
+\r
+#include "STTypes.h"\r
+#include <string>\r
+\r
+using namespace std;\r
+\r
+/// Parses command line parameters into program parameters\r
+class RunParameters\r
+{\r
+private:\r
+    void throwIllegalParamExp(const string &str) const;\r
+    void throwLicense() const;\r
+    void parseSwitchParam(const string &str);\r
+    void checkLimits();\r
+    float parseSwitchValue(const string &str) const;\r
+\r
+public:\r
+    char  *inFileName;\r
+    char  *outFileName;\r
+    float tempoDelta;\r
+    float pitchDelta;\r
+    float rateDelta;\r
+    int   quick;\r
+    int   noAntiAlias;\r
+    float goalBPM;\r
+    bool  detectBPM;\r
+    bool  speech;\r
+\r
+    RunParameters(const int nParams, const char * const paramStr[]);\r
+};\r
+\r
+#endif\r
diff --git a/source/SoundStretch/WavFile.cpp b/source/SoundStretch/WavFile.cpp
new file mode 100644 (file)
index 0000000..9d90b8a
--- /dev/null
@@ -0,0 +1,986 @@
+ ////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Classes for easy reading & writing of WAV sound files. \r
+///\r
+/// For big-endian CPU, define _BIG_ENDIAN_ during compile-time to correctly\r
+/// parse the WAV files with such processors.\r
+/// \r
+/// Admittingly, more complete WAV reader routines may exist in public domain,\r
+/// but the reason for 'yet another' one is that those generic WAV reader \r
+/// libraries are exhaustingly large and cumbersome! Wanted to have something\r
+/// simpler here, i.e. something that's not already larger than rest of the\r
+/// SoundTouch/SoundStretch program...\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <stdio.h>\r
+#include <string>\r
+#include <sstream>\r
+#include <cstring>\r
+#include <assert.h>\r
+#include <limits.h>\r
+\r
+#include "WavFile.h"\r
+#include "STTypes.h"\r
+\r
+using namespace std;\r
+\r
+static const char riffStr[] = "RIFF";\r
+static const char waveStr[] = "WAVE";\r
+static const char fmtStr[]  = "fmt ";\r
+static const char factStr[] = "fact";\r
+static const char dataStr[] = "data";\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Helper functions for swapping byte order to correctly read/write WAV files \r
+// with big-endian CPU's: Define compile-time definition _BIG_ENDIAN_ to\r
+// turn-on the conversion if it appears necessary. \r
+//\r
+// For example, Intel x86 is little-endian and doesn't require conversion,\r
+// while PowerPC of Mac's and many other RISC cpu's are big-endian.\r
+\r
+#ifdef BYTE_ORDER\r
+    // In gcc compiler detect the byte order automatically\r
+    #if BYTE_ORDER == BIG_ENDIAN\r
+        // big-endian platform.\r
+        #define _BIG_ENDIAN_\r
+    #endif\r
+#endif\r
+    \r
+#ifdef _BIG_ENDIAN_\r
+    // big-endian CPU, swap bytes in 16 & 32 bit words\r
+\r
+    // helper-function to swap byte-order of 32bit integer\r
+    static inline int _swap32(int &dwData)\r
+    {\r
+        dwData = ((dwData >> 24) & 0x000000FF) | \r
+               ((dwData >> 8)  & 0x0000FF00) | \r
+               ((dwData << 8)  & 0x00FF0000) | \r
+               ((dwData << 24) & 0xFF000000);\r
+        return dwData;\r
+    }   \r
+\r
+    // helper-function to swap byte-order of 16bit integer\r
+    static inline short _swap16(short &wData)\r
+    {\r
+        wData = ((wData >> 8) & 0x00FF) | \r
+                ((wData << 8) & 0xFF00);\r
+        return wData;\r
+    }\r
+\r
+    // helper-function to swap byte-order of buffer of 16bit integers\r
+    static inline void _swap16Buffer(short *pData, int numWords)\r
+    {\r
+        int i;\r
+\r
+        for (i = 0; i < numWords; i ++)\r
+        {\r
+            pData[i] = _swap16(pData[i]);\r
+        }\r
+    }\r
+\r
+#else   // BIG_ENDIAN\r
+    // little-endian CPU, WAV file is ok as such\r
+\r
+    // dummy helper-function\r
+    static inline int _swap32(int &dwData)\r
+    {\r
+        // do nothing\r
+        return dwData;\r
+    }   \r
+\r
+    // dummy helper-function\r
+    static inline short _swap16(short &wData)\r
+    {\r
+        // do nothing\r
+        return wData;\r
+    }\r
+\r
+    // dummy helper-function\r
+    static inline void _swap16Buffer(short *pData, int numBytes)\r
+    {\r
+        // do nothing\r
+    }\r
+\r
+#endif  // BIG_ENDIAN\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Class WavFileBase\r
+//\r
+\r
+WavFileBase::WavFileBase()\r
+{\r
+    convBuff = NULL;\r
+    convBuffSize = 0;\r
+}\r
+\r
+\r
+WavFileBase::~WavFileBase()\r
+{\r
+    delete[] convBuff;\r
+    convBuffSize = 0;\r
+}\r
+\r
+\r
+/// Get pointer to conversion buffer of at min. given size\r
+void *WavFileBase::getConvBuffer(int sizeBytes)\r
+{\r
+    if (convBuffSize < sizeBytes)\r
+    {\r
+        delete[] convBuff;\r
+\r
+        convBuffSize = (sizeBytes + 15) & -8;   // round up to following 8-byte bounday\r
+        convBuff = new char[convBuffSize];\r
+    }\r
+    return convBuff;\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Class WavInFile\r
+//\r
+\r
+WavInFile::WavInFile(const char *fileName)\r
+{\r
+    // Try to open the file for reading\r
+    fptr = fopen(fileName, "rb");\r
+    if (fptr == NULL) \r
+    {\r
+        // didn't succeed\r
+        string msg = "Error : Unable to open file \"";\r
+        msg += fileName;\r
+        msg += "\" for reading.";\r
+        ST_THROW_RT_ERROR(msg.c_str());\r
+    }\r
+\r
+    init();\r
+}\r
+\r
+\r
+WavInFile::WavInFile(FILE *file)\r
+{\r
+    // Try to open the file for reading\r
+    fptr = file;\r
+    if (!file) \r
+    {\r
+        // didn't succeed\r
+        string msg = "Error : Unable to access input stream for reading";\r
+        ST_THROW_RT_ERROR(msg.c_str());\r
+    }\r
+\r
+    init();\r
+}\r
+\r
+\r
+/// Init the WAV file stream\r
+void WavInFile::init()\r
+{\r
+    int hdrsOk;\r
+\r
+    // assume file stream is already open\r
+    assert(fptr);\r
+\r
+    // Read the file headers\r
+    hdrsOk = readWavHeaders();\r
+    if (hdrsOk != 0) \r
+    {\r
+        // Something didn't match in the wav file headers \r
+        ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file");\r
+    }\r
+\r
+    // sanity check for format parameters\r
+    if ((header.format.channel_number < 1)  || (header.format.channel_number > 9) ||\r
+        (header.format.sample_rate < 4000)  || (header.format.sample_rate > 192000) ||\r
+        (header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) ||\r
+        (header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32))\r
+    {\r
+        // Something didn't match in the wav file headers \r
+        ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters.");\r
+    }\r
+\r
+    dataRead = 0;\r
+}\r
+\r
+\r
+WavInFile::~WavInFile()\r
+{\r
+    if (fptr) fclose(fptr);\r
+    fptr = NULL;\r
+}\r
+\r
+\r
+void WavInFile::rewind()\r
+{\r
+    int hdrsOk;\r
+\r
+    fseek(fptr, 0, SEEK_SET);\r
+    hdrsOk = readWavHeaders();\r
+    assert(hdrsOk == 0);\r
+    dataRead = 0;\r
+}\r
+\r
+\r
+int WavInFile::checkCharTags() const\r
+{\r
+    // header.format.fmt should equal to 'fmt '\r
+    if (memcmp(fmtStr, header.format.fmt, 4) != 0) return -1;\r
+    // header.data.data_field should equal to 'data'\r
+    if (memcmp(dataStr, header.data.data_field, 4) != 0) return -1;\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+int WavInFile::read(unsigned char *buffer, int maxElems)\r
+{\r
+    int numBytes;\r
+    uint afterDataRead;\r
+\r
+    // ensure it's 8 bit format\r
+    if (header.format.bits_per_sample != 8)\r
+    {\r
+        ST_THROW_RT_ERROR("Error: WavInFile::read(char*, int) works only with 8bit samples.");\r
+    }\r
+    assert(sizeof(char) == 1);\r
+\r
+    numBytes = maxElems;\r
+    afterDataRead = dataRead + numBytes;\r
+    if (afterDataRead > header.data.data_len) \r
+    {\r
+        // Don't read more samples than are marked available in header\r
+        numBytes = (int)header.data.data_len - (int)dataRead;\r
+        assert(numBytes >= 0);\r
+    }\r
+\r
+    assert(buffer);\r
+    numBytes = (int)fread(buffer, 1, numBytes, fptr);\r
+    dataRead += numBytes;\r
+\r
+    return numBytes;\r
+}\r
+\r
+\r
+int WavInFile::read(short *buffer, int maxElems)\r
+{\r
+    unsigned int afterDataRead;\r
+    int numBytes;\r
+    int numElems;\r
+\r
+    assert(buffer);\r
+    switch (header.format.bits_per_sample)\r
+    {\r
+        case 8:\r
+        {\r
+            // 8 bit format\r
+            unsigned char *temp = (unsigned char*)getConvBuffer(maxElems);\r
+            int i;\r
+\r
+            numElems = read(temp, maxElems);\r
+            // convert from 8 to 16 bit\r
+            for (i = 0; i < numElems; i ++)\r
+            {\r
+                buffer[i] = (short)(((short)temp[i] - 128) * 256);\r
+            }\r
+            break;\r
+        }\r
+\r
+        case 16:\r
+        {\r
+            // 16 bit format\r
+\r
+            assert(sizeof(short) == 2);\r
+\r
+            numBytes = maxElems * 2;\r
+            afterDataRead = dataRead + numBytes;\r
+            if (afterDataRead > header.data.data_len) \r
+            {\r
+                // Don't read more samples than are marked available in header\r
+                numBytes = (int)header.data.data_len - (int)dataRead;\r
+                assert(numBytes >= 0);\r
+            }\r
+\r
+            numBytes = (int)fread(buffer, 1, numBytes, fptr);\r
+            dataRead += numBytes;\r
+            numElems = numBytes / 2;\r
+\r
+            // 16bit samples, swap byte order if necessary\r
+            _swap16Buffer((short *)buffer, numElems);\r
+            break;\r
+        }\r
+\r
+        default:\r
+        {\r
+            stringstream ss;\r
+            ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";\r
+            ss << (int)header.format.bits_per_sample;\r
+            ss << " bit sample format. ";\r
+            ST_THROW_RT_ERROR(ss.str().c_str());\r
+        }\r
+    };\r
+\r
+    return numElems;\r
+}\r
+\r
+\r
+/// Read data in float format. Notice that when reading in float format \r
+/// 8/16/24/32 bit sample formats are supported\r
+int WavInFile::read(float *buffer, int maxElems)\r
+{\r
+    unsigned int afterDataRead;\r
+    int numBytes;\r
+    int numElems;\r
+    int bytesPerSample;\r
+\r
+    assert(buffer);\r
+\r
+    bytesPerSample = header.format.bits_per_sample / 8;\r
+    if ((bytesPerSample < 1) || (bytesPerSample > 4))\r
+    {\r
+        stringstream ss;\r
+        ss << "\nOnly 8/16/24/32 bit sample WAV files supported. Can't open WAV file with ";\r
+        ss << (int)header.format.bits_per_sample;\r
+        ss << " bit sample format. ";\r
+        ST_THROW_RT_ERROR(ss.str().c_str());\r
+    }\r
+\r
+    numBytes = maxElems * bytesPerSample;\r
+    afterDataRead = dataRead + numBytes;\r
+    if (afterDataRead > header.data.data_len) \r
+    {\r
+        // Don't read more samples than are marked available in header\r
+        numBytes = (int)header.data.data_len - (int)dataRead;\r
+        assert(numBytes >= 0);\r
+    }\r
+\r
+    // read raw data into temporary buffer\r
+    char *temp = (char*)getConvBuffer(numBytes);\r
+    numBytes = (int)fread(temp, 1, numBytes, fptr);\r
+    dataRead += numBytes;\r
+\r
+    numElems = numBytes / bytesPerSample;\r
+\r
+    // swap byte ordert & convert to float, depending on sample format\r
+    switch (bytesPerSample)\r
+    {\r
+        case 1:\r
+        {\r
+            unsigned char *temp2 = (unsigned char*)temp;\r
+            double conv = 1.0 / 128.0;\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                buffer[i] = (float)(temp2[i] * conv - 1.0);\r
+            }\r
+            break;\r
+        }\r
+\r
+        case 2:\r
+        {\r
+            short *temp2 = (short*)temp;\r
+            double conv = 1.0 / 32768.0;\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                short value = temp2[i];\r
+                buffer[i] = (float)(_swap16(value) * conv);\r
+            }\r
+            break;\r
+        }\r
+\r
+        case 3:\r
+        {\r
+            char *temp2 = (char *)temp;\r
+            double conv = 1.0 / 8388608.0;\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                int value = *((int*)temp2);\r
+                value = _swap32(value) & 0x00ffffff;             // take 24 bits\r
+                value |= (value & 0x00800000) ? 0xff000000 : 0;  // extend minus sign bits\r
+                buffer[i] = (float)(value * conv);\r
+                temp2 += 3;\r
+            }\r
+            break;\r
+        }\r
+\r
+        case 4:\r
+        {\r
+            int *temp2 = (int *)temp;\r
+            double conv = 1.0 / 2147483648.0;\r
+            assert(sizeof(int) == 4);\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                int value = temp2[i];\r
+                buffer[i] = (float)(_swap32(value) * conv);\r
+            }\r
+            break;\r
+        }\r
+    }\r
+\r
+    return numElems;\r
+}\r
+\r
+\r
+int WavInFile::eof() const\r
+{\r
+    // return true if all data has been read or file eof has reached\r
+    return (dataRead == header.data.data_len || feof(fptr));\r
+}\r
+\r
+\r
+// test if character code is between a white space ' ' and little 'z'\r
+static int isAlpha(char c)\r
+{\r
+    return (c >= ' ' && c <= 'z') ? 1 : 0;\r
+}\r
+\r
+\r
+// test if all characters are between a white space ' ' and little 'z'\r
+static int isAlphaStr(const char *str)\r
+{\r
+    char c;\r
+\r
+    c = str[0];\r
+    while (c) \r
+    {\r
+        if (isAlpha(c) == 0) return 0;\r
+        str ++;\r
+        c = str[0];\r
+    }\r
+\r
+    return 1;\r
+}\r
+\r
+\r
+int WavInFile::readRIFFBlock()\r
+{\r
+    if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1;\r
+\r
+    // swap 32bit data byte order if necessary\r
+    _swap32((int &)header.riff.package_len);\r
+\r
+    // header.riff.riff_char should equal to 'RIFF');\r
+    if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1;\r
+    // header.riff.wave should equal to 'WAVE'\r
+    if (memcmp(waveStr, header.riff.wave, 4) != 0) return -1;\r
+\r
+    return 0;\r
+}\r
+\r
+\r
+int WavInFile::readHeaderBlock()\r
+{\r
+    char label[5];\r
+    string sLabel;\r
+\r
+    // lead label string\r
+    if (fread(label, 1, 4, fptr) !=4) return -1;\r
+    label[4] = 0;\r
+\r
+    if (isAlphaStr(label) == 0) return -1;    // not a valid label\r
+\r
+    // Decode blocks according to their label\r
+    if (strcmp(label, fmtStr) == 0)\r
+    {\r
+        int nLen, nDump;\r
+\r
+        // 'fmt ' block \r
+        memcpy(header.format.fmt, fmtStr, 4);\r
+\r
+        // read length of the format field\r
+        if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;\r
+        // swap byte order if necessary\r
+        _swap32(nLen);\r
+\r
+        // calculate how much length differs from expected \r
+        nDump = nLen - ((int)sizeof(header.format) - 8);\r
+\r
+        // verify that header length isn't smaller than expected structure\r
+        if ((nLen < 0) || (nDump < 0)) return -1;\r
+\r
+        header.format.format_len = nLen;\r
+\r
+        // if format_len is larger than expected, read only as much data as we've space for\r
+        if (nDump > 0)\r
+        {\r
+            nLen = sizeof(header.format) - 8;\r
+        }\r
+\r
+        // read data\r
+        if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;\r
+\r
+        // swap byte order if necessary\r
+        _swap16((short &)header.format.fixed);            // short int fixed;\r
+        _swap16((short &)header.format.channel_number);   // short int channel_number;\r
+        _swap32((int &)header.format.sample_rate);        // int sample_rate;\r
+        _swap32((int &)header.format.byte_rate);          // int byte_rate;\r
+        _swap16((short &)header.format.byte_per_sample);  // short int byte_per_sample;\r
+        _swap16((short &)header.format.bits_per_sample);  // short int bits_per_sample;\r
+\r
+        // if format_len is larger than expected, skip the extra data\r
+        if (nDump > 0)\r
+        {\r
+            fseek(fptr, nDump, SEEK_CUR);\r
+        }\r
+\r
+        return 0;\r
+    }\r
+    else if (strcmp(label, factStr) == 0)\r
+    {\r
+        int nLen, nDump;\r
+\r
+        // 'fact' block \r
+        memcpy(header.fact.fact_field, factStr, 4);\r
+\r
+        // read length of the fact field\r
+        if (fread(&nLen, sizeof(int), 1, fptr) != 1) return -1;\r
+        // swap byte order if necessary\r
+        _swap32(nLen);\r
+\r
+        // calculate how much length differs from expected\r
+        nDump = nLen - ((int)sizeof(header.fact) - 8);\r
+\r
+        // verify that fact length isn't smaller than expected structure\r
+        if ((nLen < 0) || (nDump < 0)) return -1;\r
+\r
+        header.fact.fact_len = nLen;\r
+\r
+        // if format_len is larger than expected, read only as much data as we've space for\r
+        if (nDump > 0)\r
+        {\r
+            nLen = sizeof(header.fact) - 8;\r
+        }\r
+\r
+        // read data\r
+        if (fread(&(header.fact.fact_sample_len), nLen, 1, fptr) != 1) return -1;\r
+\r
+        // swap byte order if necessary\r
+        _swap32((int &)header.fact.fact_sample_len);    // int sample_length;\r
+\r
+        // if fact_len is larger than expected, skip the extra data\r
+        if (nDump > 0)\r
+        {\r
+            fseek(fptr, nDump, SEEK_CUR);\r
+        }\r
+\r
+        return 0;\r
+    }\r
+    else if (strcmp(label, dataStr) == 0)\r
+    {\r
+        // 'data' block\r
+        memcpy(header.data.data_field, dataStr, 4);\r
+        if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1;\r
+\r
+        // swap byte order if necessary\r
+        _swap32((int &)header.data.data_len);\r
+\r
+        return 1;\r
+    }\r
+    else\r
+    {\r
+        uint len, i;\r
+        uint temp;\r
+        // unknown block\r
+\r
+        // read length\r
+        if (fread(&len, sizeof(len), 1, fptr) != 1) return -1;\r
+        // scan through the block\r
+        for (i = 0; i < len; i ++)\r
+        {\r
+            if (fread(&temp, 1, 1, fptr) != 1) return -1;\r
+            if (feof(fptr)) return -1;   // unexpected eof\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+int WavInFile::readWavHeaders()\r
+{\r
+    int res;\r
+\r
+    memset(&header, 0, sizeof(header));\r
+\r
+    res = readRIFFBlock();\r
+    if (res) return 1;\r
+    // read header blocks until data block is found\r
+    do\r
+    {\r
+        // read header blocks\r
+        res = readHeaderBlock();\r
+        if (res < 0) return 1;  // error in file structure\r
+    } while (res == 0);\r
+    // check that all required tags are legal\r
+    return checkCharTags();\r
+}\r
+\r
+\r
+uint WavInFile::getNumChannels() const\r
+{\r
+    return header.format.channel_number;\r
+}\r
+\r
+\r
+uint WavInFile::getNumBits() const\r
+{\r
+    return header.format.bits_per_sample;\r
+}\r
+\r
+\r
+uint WavInFile::getBytesPerSample() const\r
+{\r
+    return getNumChannels() * getNumBits() / 8;\r
+}\r
+\r
+\r
+uint WavInFile::getSampleRate() const\r
+{\r
+    return header.format.sample_rate;\r
+}\r
+\r
+\r
+uint WavInFile::getDataSizeInBytes() const\r
+{\r
+    return header.data.data_len;\r
+}\r
+\r
+\r
+uint WavInFile::getNumSamples() const\r
+{\r
+    if (header.format.byte_per_sample == 0) return 0;\r
+    if (header.format.fixed > 1) return header.fact.fact_sample_len;\r
+    return header.data.data_len / (unsigned short)header.format.byte_per_sample;\r
+}\r
+\r
+\r
+uint WavInFile::getLengthMS() const\r
+{\r
+    double numSamples;\r
+    double sampleRate;\r
+\r
+    numSamples = (double)getNumSamples();\r
+    sampleRate = (double)getSampleRate();\r
+\r
+    return (uint)(1000.0 * numSamples / sampleRate + 0.5);\r
+}\r
+\r
+\r
+/// Returns how many milliseconds of audio have so far been read from the file\r
+uint WavInFile::getElapsedMS() const\r
+{\r
+    return (uint)(1000.0 * (double)dataRead / (double)header.format.byte_rate);\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Class WavOutFile\r
+//\r
+\r
+WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)\r
+{\r
+    bytesWritten = 0;\r
+    fptr = fopen(fileName, "wb");\r
+    if (fptr == NULL) \r
+    {\r
+        string msg = "Error : Unable to open file \"";\r
+        msg += fileName;\r
+        msg += "\" for writing.";\r
+        //pmsg = msg.c_str;\r
+        ST_THROW_RT_ERROR(msg.c_str());\r
+    }\r
+\r
+    fillInHeader(sampleRate, bits, channels);\r
+    writeHeader();\r
+}\r
+\r
+\r
+WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels)\r
+{\r
+    bytesWritten = 0;\r
+    fptr = file;\r
+    if (fptr == NULL) \r
+    {\r
+        string msg = "Error : Unable to access output file stream.";\r
+        ST_THROW_RT_ERROR(msg.c_str());\r
+    }\r
+\r
+    fillInHeader(sampleRate, bits, channels);\r
+    writeHeader();\r
+}\r
+\r
+\r
+WavOutFile::~WavOutFile()\r
+{\r
+    finishHeader();\r
+    if (fptr) fclose(fptr);\r
+    fptr = NULL;\r
+}\r
+\r
+\r
+void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)\r
+{\r
+    // fill in the 'riff' part..\r
+\r
+    // copy string 'RIFF' to riff_char\r
+    memcpy(&(header.riff.riff_char), riffStr, 4);\r
+    // package_len unknown so far\r
+    header.riff.package_len = 0;\r
+    // copy string 'WAVE' to wave\r
+    memcpy(&(header.riff.wave), waveStr, 4);\r
+\r
+    // fill in the 'format' part..\r
+\r
+    // copy string 'fmt ' to fmt\r
+    memcpy(&(header.format.fmt), fmtStr, 4);\r
+\r
+    header.format.format_len = 0x10;\r
+    header.format.fixed = 1;\r
+    header.format.channel_number = (short)channels;\r
+    header.format.sample_rate = (int)sampleRate;\r
+    header.format.bits_per_sample = (short)bits;\r
+    header.format.byte_per_sample = (short)(bits * channels / 8);\r
+    header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;\r
+    header.format.sample_rate = (int)sampleRate;\r
+\r
+    // fill in the 'fact' part...\r
+    memcpy(&(header.fact.fact_field), factStr, 4);\r
+       header.fact.fact_len = 4;\r
+       header.fact.fact_sample_len = 0;\r
+\r
+    // fill in the 'data' part..\r
+\r
+    // copy string 'data' to data_field\r
+    memcpy(&(header.data.data_field), dataStr, 4);\r
+    // data_len unknown so far\r
+    header.data.data_len = 0;\r
+}\r
+\r
+\r
+void WavOutFile::finishHeader()\r
+{\r
+    // supplement the file length into the header structure\r
+    header.riff.package_len = bytesWritten + sizeof(WavHeader) - sizeof(WavRiff) + 4;\r
+    header.data.data_len = bytesWritten;\r
+       header.fact.fact_sample_len = bytesWritten / header.format.byte_per_sample; \r
+       \r
+    writeHeader();\r
+}\r
+\r
+\r
+void WavOutFile::writeHeader()\r
+{\r
+    WavHeader hdrTemp;\r
+    int res;\r
+\r
+    // swap byte order if necessary\r
+    hdrTemp = header;\r
+    _swap32((int &)hdrTemp.riff.package_len);\r
+    _swap32((int &)hdrTemp.format.format_len);\r
+    _swap16((short &)hdrTemp.format.fixed);\r
+    _swap16((short &)hdrTemp.format.channel_number);\r
+    _swap32((int &)hdrTemp.format.sample_rate);\r
+    _swap32((int &)hdrTemp.format.byte_rate);\r
+    _swap16((short &)hdrTemp.format.byte_per_sample);\r
+    _swap16((short &)hdrTemp.format.bits_per_sample);\r
+    _swap32((int &)hdrTemp.data.data_len);\r
+    _swap32((int &)hdrTemp.fact.fact_len);\r
+    _swap32((int &)hdrTemp.fact.fact_sample_len);\r
+    \r
+    // write the supplemented header in the beginning of the file\r
+    fseek(fptr, 0, SEEK_SET);\r
+    res = (int)fwrite(&hdrTemp, sizeof(hdrTemp), 1, fptr);\r
+    if (res != 1)\r
+    {\r
+        ST_THROW_RT_ERROR("Error while writing to a wav file.");\r
+    }\r
+\r
+    // jump back to the end of the file\r
+    fseek(fptr, 0, SEEK_END);\r
+}\r
+\r
+\r
+void WavOutFile::write(const unsigned char *buffer, int numElems)\r
+{\r
+    int res;\r
+\r
+    if (header.format.bits_per_sample != 8)\r
+    {\r
+        ST_THROW_RT_ERROR("Error: WavOutFile::write(const char*, int) accepts only 8bit samples.");\r
+    }\r
+    assert(sizeof(char) == 1);\r
+\r
+    res = (int)fwrite(buffer, 1, numElems, fptr);\r
+    if (res != numElems) \r
+    {\r
+        ST_THROW_RT_ERROR("Error while writing to a wav file.");\r
+    }\r
+\r
+    bytesWritten += numElems;\r
+}\r
+\r
+\r
+void WavOutFile::write(const short *buffer, int numElems)\r
+{\r
+    int res;\r
+\r
+    // 16 bit samples\r
+    if (numElems < 1) return;   // nothing to do\r
+\r
+    switch (header.format.bits_per_sample)\r
+    {\r
+        case 8:\r
+        {\r
+            int i;\r
+            unsigned char *temp = (unsigned char *)getConvBuffer(numElems);\r
+            // convert from 16bit format to 8bit format\r
+            for (i = 0; i < numElems; i ++)\r
+            {\r
+                temp[i] = (unsigned char)(buffer[i] / 256 + 128);\r
+            }\r
+            // write in 8bit format\r
+            write(temp, numElems);\r
+            break;\r
+        }\r
+\r
+        case 16:\r
+        {\r
+            // 16bit format\r
+\r
+            // use temp buffer to swap byte order if necessary\r
+            short *pTemp = (short *)getConvBuffer(numElems * sizeof(short));\r
+            memcpy(pTemp, buffer, numElems * 2);\r
+            _swap16Buffer(pTemp, numElems);\r
+\r
+            res = (int)fwrite(pTemp, 2, numElems, fptr);\r
+\r
+            if (res != numElems) \r
+            {\r
+                ST_THROW_RT_ERROR("Error while writing to a wav file.");\r
+            }\r
+            bytesWritten += 2 * numElems;\r
+            break;\r
+        }\r
+\r
+        default:\r
+        {\r
+            stringstream ss;\r
+            ss << "\nOnly 8/16 bit sample WAV files supported in integer compilation. Can't open WAV file with ";\r
+            ss << (int)header.format.bits_per_sample;\r
+            ss << " bit sample format. ";\r
+            ST_THROW_RT_ERROR(ss.str().c_str());\r
+        }\r
+    }\r
+}\r
+\r
+\r
+/// Convert from float to integer and saturate\r
+inline int saturate(float fvalue, float minval, float maxval)\r
+{\r
+    if (fvalue > maxval) \r
+    {\r
+        fvalue = maxval;\r
+    } \r
+    else if (fvalue < minval)\r
+    {\r
+        fvalue = minval;\r
+    }\r
+    return (int)fvalue;\r
+}\r
+\r
+\r
+void WavOutFile::write(const float *buffer, int numElems)\r
+{\r
+    int numBytes;\r
+    int bytesPerSample;\r
+\r
+    if (numElems == 0) return;\r
+\r
+    bytesPerSample = header.format.bits_per_sample / 8;\r
+    numBytes = numElems * bytesPerSample;\r
+    short *temp = (short*)getConvBuffer(numBytes);\r
+\r
+    switch (bytesPerSample)\r
+    {\r
+        case 1:\r
+        {\r
+            unsigned char *temp2 = (unsigned char *)temp;\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                temp2[i] = (unsigned char)saturate(buffer[i] * 128.0f + 128.0f, 0.0f, 255.0f);\r
+            }\r
+            break;\r
+        }\r
+\r
+        case 2:\r
+        {\r
+            short *temp2 = (short *)temp;\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                short value = (short)saturate(buffer[i] * 32768.0f, -32768.0f, 32767.0f);\r
+                temp2[i] = _swap16(value);\r
+            }\r
+            break;\r
+        }\r
+\r
+        case 3:\r
+        {\r
+            char *temp2 = (char *)temp;\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                int value = saturate(buffer[i] * 8388608.0f, -8388608.0f, 8388607.0f);\r
+                *((int*)temp2) = _swap32(value);\r
+                temp2 += 3;\r
+            }\r
+            break;\r
+        }\r
+\r
+        case 4:\r
+        {\r
+            int *temp2 = (int *)temp;\r
+            for (int i = 0; i < numElems; i ++)\r
+            {\r
+                int value = saturate(buffer[i] * 2147483648.0f, -2147483648.0f, 2147483647.0f);\r
+                temp2[i] = _swap32(value);\r
+            }\r
+            break;\r
+        }\r
+\r
+        default:\r
+            assert(false);\r
+    }\r
+\r
+    int res = (int)fwrite(temp, 1, numBytes, fptr);\r
+\r
+    if (res != numBytes) \r
+    {\r
+        ST_THROW_RT_ERROR("Error while writing to a wav file.");\r
+    }\r
+    bytesWritten += numBytes;\r
+}\r
diff --git a/source/SoundStretch/WavFile.h b/source/SoundStretch/WavFile.h
new file mode 100644 (file)
index 0000000..b0f4d96
--- /dev/null
@@ -0,0 +1,277 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Classes for easy reading & writing of WAV sound files.\r
+///\r
+/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly\r
+/// parse the WAV files with such processors.\r
+/// \r
+/// Admittingly, more complete WAV reader routines may exist in public domain, but \r
+/// the reason for 'yet another' one is that those generic WAV reader libraries are\r
+/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e. \r
+/// something that's not already larger than rest of the SoundTouch/SoundStretch program...\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef WAVFILE_H\r
+#define WAVFILE_H\r
+\r
+#include <stdio.h>\r
+\r
+#ifndef uint\r
+typedef unsigned int uint;\r
+#endif           \r
+\r
+\r
+/// WAV audio file 'riff' section header\r
+typedef struct \r
+{\r
+    char riff_char[4];\r
+    uint package_len;\r
+    char wave[4];\r
+} WavRiff;\r
+\r
+/// WAV audio file 'format' section header\r
+typedef struct \r
+{\r
+    char  fmt[4];\r
+    unsigned int   format_len;\r
+    unsigned short fixed;\r
+    unsigned short channel_number;\r
+    unsigned int   sample_rate;\r
+    unsigned int   byte_rate;\r
+    unsigned short byte_per_sample;\r
+    unsigned short bits_per_sample;\r
+} WavFormat;\r
+\r
+/// WAV audio file 'fact' section header\r
+typedef struct \r
+{\r
+    char fact_field[4];\r
+    uint fact_len;\r
+    uint fact_sample_len;\r
+} WavFact;\r
+\r
+/// WAV audio file 'data' section header\r
+typedef struct \r
+{\r
+    char  data_field[4];\r
+    uint  data_len;\r
+} WavData;\r
+\r
+\r
+/// WAV audio file header\r
+typedef struct \r
+{\r
+    WavRiff   riff;\r
+    WavFormat format;\r
+    WavFact   fact;\r
+    WavData   data;\r
+} WavHeader;\r
+\r
+\r
+/// Base class for processing WAV audio files.\r
+class WavFileBase\r
+{\r
+private:\r
+    /// Conversion working buffer;\r
+    char *convBuff;\r
+    int convBuffSize;\r
+\r
+protected:\r
+    WavFileBase();\r
+    virtual ~WavFileBase();\r
+\r
+    /// Get pointer to conversion buffer of at min. given size\r
+    void *getConvBuffer(int sizeByte);\r
+};\r
+\r
+\r
+/// Class for reading WAV audio files.\r
+class WavInFile : protected WavFileBase\r
+{\r
+private:\r
+    /// File pointer.\r
+    FILE *fptr;\r
+\r
+    /// Position within the audio stream\r
+    long position;\r
+\r
+    /// Counter of how many bytes of sample data have been read from the file.\r
+    long dataRead;\r
+\r
+    /// WAV header information\r
+    WavHeader header;\r
+\r
+    /// Init the WAV file stream\r
+    void init();\r
+\r
+    /// Read WAV file headers.\r
+    /// \return zero if all ok, nonzero if file format is invalid.\r
+    int readWavHeaders();\r
+\r
+    /// Checks WAV file header tags.\r
+    /// \return zero if all ok, nonzero if file format is invalid.\r
+    int checkCharTags() const;\r
+\r
+    /// Reads a single WAV file header block.\r
+    /// \return zero if all ok, nonzero if file format is invalid.\r
+    int readHeaderBlock();\r
+\r
+    /// Reads WAV file 'riff' block\r
+    int readRIFFBlock();\r
+\r
+public:\r
+    /// Constructor: Opens the given WAV file. If the file can't be opened,\r
+    /// throws 'runtime_error' exception.\r
+    WavInFile(const char *filename);\r
+\r
+    WavInFile(FILE *file);\r
+\r
+    /// Destructor: Closes the file.\r
+    ~WavInFile();\r
+\r
+    /// Rewind to beginning of the file\r
+    void rewind();\r
+\r
+    /// Get sample rate.\r
+    uint getSampleRate() const;\r
+\r
+    /// Get number of bits per sample, i.e. 8 or 16.\r
+    uint getNumBits() const;\r
+\r
+    /// Get sample data size in bytes. Ahem, this should return same information as \r
+    /// 'getBytesPerSample'...\r
+    uint getDataSizeInBytes() const;\r
+\r
+    /// Get total number of samples in file.\r
+    uint getNumSamples() const;\r
+\r
+    /// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)\r
+    uint getBytesPerSample() const;\r
+    \r
+    /// Get number of audio channels in the file (1=mono, 2=stereo)\r
+    uint getNumChannels() const;\r
+\r
+    /// Get the audio file length in milliseconds\r
+    uint getLengthMS() const;\r
+\r
+    /// Returns how many milliseconds of audio have so far been read from the file\r
+    ///\r
+    /// \return elapsed duration in milliseconds\r
+    uint getElapsedMS() const;\r
+\r
+    /// Reads audio samples from the WAV file. This routine works only for 8 bit samples.\r
+    /// Reads given number of elements from the file or if end-of-file reached, as many \r
+    /// elements as are left in the file.\r
+    ///\r
+    /// \return Number of 8-bit integers read from the file.\r
+    int read(unsigned char *buffer, int maxElems);\r
+\r
+    /// Reads audio samples from the WAV file to 16 bit integer format. Reads given number \r
+    /// of elements from the file or if end-of-file reached, as many elements as are \r
+    /// left in the file.\r
+    ///\r
+    /// \return Number of 16-bit integers read from the file.\r
+    int read(short *buffer,     ///< Pointer to buffer where to read data.\r
+             int maxElems       ///< Size of 'buffer' array (number of array elements).\r
+             );\r
+\r
+    /// Reads audio samples from the WAV file to floating point format, converting \r
+    /// sample values to range [-1,1[. Reads given number of elements from the file\r
+    /// or if end-of-file reached, as many elements as are left in the file.\r
+    /// Notice that reading in float format supports 8/16/24/32bit sample formats.\r
+    ///\r
+    /// \return Number of elements read from the file.\r
+    int read(float *buffer,     ///< Pointer to buffer where to read data.\r
+             int maxElems       ///< Size of 'buffer' array (number of array elements).\r
+             );\r
+\r
+    /// Check end-of-file.\r
+    ///\r
+    /// \return Nonzero if end-of-file reached.\r
+    int eof() const;\r
+};\r
+\r
+\r
+/// Class for writing WAV audio files.\r
+class WavOutFile : protected WavFileBase\r
+{\r
+private:\r
+    /// Pointer to the WAV file\r
+    FILE *fptr;\r
+\r
+    /// WAV file header data.\r
+    WavHeader header;\r
+\r
+    /// Counter of how many bytes have been written to the file so far.\r
+    int bytesWritten;\r
+\r
+    /// Fills in WAV file header information.\r
+    void fillInHeader(const uint sampleRate, const uint bits, const uint channels);\r
+\r
+    /// Finishes the WAV file header by supplementing information of amount of\r
+    /// data written to file etc\r
+    void finishHeader();\r
+\r
+    /// Writes the WAV file header.\r
+    void writeHeader();\r
+\r
+public:\r
+    /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception \r
+    /// if file creation fails.\r
+    WavOutFile(const char *fileName,    ///< Filename\r
+               int sampleRate,          ///< Sample rate (e.g. 44100 etc)\r
+               int bits,                ///< Bits per sample (8 or 16 bits)\r
+               int channels             ///< Number of channels (1=mono, 2=stereo)\r
+               );\r
+\r
+    WavOutFile(FILE *file, int sampleRate, int bits, int channels);\r
+\r
+    /// Destructor: Finalizes & closes the WAV file.\r
+    ~WavOutFile();\r
+\r
+    /// Write data to WAV file. This function works only with 8bit samples. \r
+    /// Throws a 'runtime_error' exception if writing to file fails.\r
+    void write(const unsigned char *buffer, ///< Pointer to sample data buffer.\r
+               int numElems                 ///< How many array items are to be written to file.\r
+               );\r
+\r
+    /// Write data to WAV file. Throws a 'runtime_error' exception if writing to\r
+    /// file fails.\r
+    void write(const short *buffer,     ///< Pointer to sample data buffer.\r
+               int numElems             ///< How many array items are to be written to file.\r
+               );\r
+\r
+    /// Write data to WAV file in floating point format, saturating sample values to range\r
+    /// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails.\r
+    void write(const float *buffer,     ///< Pointer to sample data buffer.\r
+               int numElems             ///< How many array items are to be written to file.\r
+               );\r
+};\r
+\r
+#endif\r
diff --git a/source/SoundStretch/main.cpp b/source/SoundStretch/main.cpp
new file mode 100644 (file)
index 0000000..360ae8c
--- /dev/null
@@ -0,0 +1,322 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// SoundStretch main routine.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <stdexcept>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <time.h>\r
+#include "RunParameters.h"\r
+#include "WavFile.h"\r
+#include "SoundTouch.h"\r
+#include "BPMDetect.h"\r
+\r
+using namespace soundtouch;\r
+using namespace std;\r
+\r
+// Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...)\r
+#define BUFF_SIZE           6720\r
+\r
+#if _WIN32\r
+    #include <io.h>\r
+    #include <fcntl.h>\r
+\r
+    // Macro for Win32 standard input/output stream support: Sets a file stream into binary mode\r
+    #define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY))\r
+#else\r
+    // Not needed for GNU environment... \r
+    #define SET_STREAM_TO_BIN_MODE(f) {}\r
+#endif\r
+\r
+\r
+static const char _helloText[] = \r
+    "\n"\r
+    "   SoundStretch v%s -  Copyright (c) Olli Parviainen\n"\r
+    "=========================================================\n"\r
+    "author e-mail: <oparviai"\r
+    "@"\r
+    "iki.fi> - WWW: http://www.surina.net/soundtouch\n"\r
+    "\n"\r
+    "This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"\r
+    "more information.\n"\r
+    "\n";\r
+\r
+static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParameters *params)\r
+{\r
+    int bits, samplerate, channels;\r
+\r
+    if (strcmp(params->inFileName, "stdin") == 0)\r
+    {\r
+        // used 'stdin' as input file\r
+        SET_STREAM_TO_BIN_MODE(stdin);\r
+        *inFile = new WavInFile(stdin);\r
+    }\r
+    else\r
+    {\r
+        // open input file...\r
+        *inFile = new WavInFile(params->inFileName);\r
+    }\r
+\r
+    // ... open output file with same sound parameters\r
+    bits = (int)(*inFile)->getNumBits();\r
+    samplerate = (int)(*inFile)->getSampleRate();\r
+    channels = (int)(*inFile)->getNumChannels();\r
+\r
+    if (params->outFileName)\r
+    {\r
+        if (strcmp(params->outFileName, "stdout") == 0)\r
+        {\r
+            SET_STREAM_TO_BIN_MODE(stdout);\r
+            *outFile = new WavOutFile(stdout, samplerate, bits, channels);\r
+        }\r
+        else\r
+        {\r
+            *outFile = new WavOutFile(params->outFileName, samplerate, bits, channels);\r
+        }\r
+    }\r
+    else\r
+    {\r
+        *outFile = NULL;\r
+    }\r
+}\r
+\r
+\r
+// Sets the 'SoundTouch' object up according to input file sound format & \r
+// command line parameters\r
+static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunParameters *params)\r
+{\r
+    int sampleRate;\r
+    int channels;\r
+\r
+    sampleRate = (int)inFile->getSampleRate();\r
+    channels = (int)inFile->getNumChannels();\r
+    pSoundTouch->setSampleRate(sampleRate);\r
+    pSoundTouch->setChannels(channels);\r
+\r
+    pSoundTouch->setTempoChange(params->tempoDelta);\r
+    pSoundTouch->setPitchSemiTones(params->pitchDelta);\r
+    pSoundTouch->setRateChange(params->rateDelta);\r
+\r
+    pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, params->quick);\r
+    pSoundTouch->setSetting(SETTING_USE_AA_FILTER, !(params->noAntiAlias));\r
+\r
+    if (params->speech)\r
+    {\r
+        // use settings for speech processing\r
+        pSoundTouch->setSetting(SETTING_SEQUENCE_MS, 40);\r
+        pSoundTouch->setSetting(SETTING_SEEKWINDOW_MS, 15);\r
+        pSoundTouch->setSetting(SETTING_OVERLAP_MS, 8);\r
+        fprintf(stderr, "Tune processing parameters for speech processing.\n");\r
+    }\r
+\r
+    // print processing information\r
+    if (params->outFileName)\r
+    {\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+        fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");\r
+#else\r
+    #ifndef SOUNDTOUCH_FLOAT_SAMPLES\r
+        #error "Sampletype not defined"\r
+    #endif\r
+        fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");\r
+#endif\r
+        // print processing information only if outFileName given i.e. some processing will happen\r
+        fprintf(stderr, "Processing the file with the following changes:\n");\r
+        fprintf(stderr, "  tempo change = %+g %%\n", params->tempoDelta);\r
+        fprintf(stderr, "  pitch change = %+g semitones\n", params->pitchDelta);\r
+        fprintf(stderr, "  rate change  = %+g %%\n\n", params->rateDelta);\r
+        fprintf(stderr, "Working...");\r
+    }\r
+    else\r
+    {\r
+        // outFileName not given\r
+        fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n");\r
+    }\r
+\r
+    fflush(stderr);\r
+}\r
+\r
+\r
+// Processes the sound\r
+static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outFile)\r
+{\r
+    int nSamples;\r
+    int nChannels;\r
+    int buffSizeSamples;\r
+    SAMPLETYPE sampleBuffer[BUFF_SIZE];\r
+\r
+    if ((inFile == NULL) || (outFile == NULL)) return;  // nothing to do.\r
+\r
+    nChannels = (int)inFile->getNumChannels();\r
+    assert(nChannels > 0);\r
+    buffSizeSamples = BUFF_SIZE / nChannels;\r
+\r
+    // Process samples read from the input file\r
+    while (inFile->eof() == 0)\r
+    {\r
+        int num;\r
+\r
+        // Read a chunk of samples from the input file\r
+        num = inFile->read(sampleBuffer, BUFF_SIZE);\r
+        nSamples = num / (int)inFile->getNumChannels();\r
+\r
+        // Feed the samples into SoundTouch processor\r
+        pSoundTouch->putSamples(sampleBuffer, nSamples);\r
+\r
+        // Read ready samples from SoundTouch processor & write them output file.\r
+        // NOTES:\r
+        // - 'receiveSamples' doesn't necessarily return any samples at all\r
+        //   during some rounds!\r
+        // - On the other hand, during some round 'receiveSamples' may have more\r
+        //   ready samples than would fit into 'sampleBuffer', and for this reason \r
+        //   the 'receiveSamples' call is iterated for as many times as it\r
+        //   outputs samples.\r
+        do \r
+        {\r
+            nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);\r
+            outFile->write(sampleBuffer, nSamples * nChannels);\r
+        } while (nSamples != 0);\r
+    }\r
+\r
+    // Now the input file is processed, yet 'flush' few last samples that are\r
+    // hiding in the SoundTouch's internal processing pipeline.\r
+    pSoundTouch->flush();\r
+    do \r
+    {\r
+        nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);\r
+        outFile->write(sampleBuffer, nSamples * nChannels);\r
+    } while (nSamples != 0);\r
+}\r
+\r
+\r
+// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary\r
+static void detectBPM(WavInFile *inFile, RunParameters *params)\r
+{\r
+    float bpmValue;\r
+    int nChannels;\r
+    BPMDetect bpm(inFile->getNumChannels(), inFile->getSampleRate());\r
+    SAMPLETYPE sampleBuffer[BUFF_SIZE];\r
+\r
+    // detect bpm rate\r
+    fprintf(stderr, "Detecting BPM rate...");\r
+    fflush(stderr);\r
+\r
+    nChannels = (int)inFile->getNumChannels();\r
+    assert(BUFF_SIZE % nChannels == 0);\r
+\r
+    // Process the 'inFile' in small blocks, repeat until whole file has \r
+    // been processed\r
+    while (inFile->eof() == 0)\r
+    {\r
+        int num, samples;\r
+\r
+        // Read sample data from input file\r
+        num = inFile->read(sampleBuffer, BUFF_SIZE);\r
+\r
+        // Enter the new samples to the bpm analyzer class\r
+        samples = num / nChannels;\r
+        bpm.inputSamples(sampleBuffer, samples);\r
+    }\r
+\r
+    // Now the whole song data has been analyzed. Read the resulting bpm.\r
+    bpmValue = bpm.getBpm();\r
+    fprintf(stderr, "Done!\n");\r
+\r
+    // rewind the file after bpm detection\r
+    inFile->rewind();\r
+\r
+    if (bpmValue > 0)\r
+    {\r
+        fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue);\r
+    }\r
+    else\r
+    {\r
+        fprintf(stderr, "Couldn't detect BPM rate.\n\n");\r
+        return;\r
+    }\r
+\r
+    if (params->goalBPM > 0)\r
+    {\r
+        // adjust tempo to given bpm\r
+        params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f;\r
+        fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params->goalBPM);\r
+    }\r
+}\r
+\r
+\r
+int main(const int nParams, const char * const paramStr[])\r
+{\r
+    WavInFile *inFile;\r
+    WavOutFile *outFile;\r
+    RunParameters *params;\r
+    SoundTouch soundTouch;\r
+\r
+    fprintf(stderr, _helloText, SoundTouch::getVersionString());\r
+\r
+    try \r
+    {\r
+        // Parse command line parameters\r
+        params = new RunParameters(nParams, paramStr);\r
+\r
+        // Open input & output files\r
+        openFiles(&inFile, &outFile, params);\r
+\r
+        if (params->detectBPM == true)\r
+        {\r
+            // detect sound BPM (and adjust processing parameters\r
+            //  accordingly if necessary)\r
+            detectBPM(inFile, params);\r
+        }\r
+\r
+        // Setup the 'SoundTouch' object for processing the sound\r
+        setup(&soundTouch, inFile, params);\r
+\r
+        // clock_t cs = clock();    // for benchmarking processing duration\r
+        // Process the sound\r
+        process(&soundTouch, inFile, outFile);\r
+        // clock_t ce = clock();    // for benchmarking processing duration\r
+        // printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC);\r
+\r
+        // Close WAV file handles & dispose of the objects\r
+        delete inFile;\r
+        delete outFile;\r
+        delete params;\r
+\r
+        fprintf(stderr, "Done!\n");\r
+    } \r
+    catch (const runtime_error &e) \r
+    {\r
+        // An exception occurred during processing, display an error message\r
+        fprintf(stderr, "%s\n", e.what());\r
+        return -1;\r
+    }\r
+\r
+    return 0;\r
+}\r
diff --git a/source/SoundStretch/soundstretch.sln b/source/SoundStretch/soundstretch.sln
new file mode 100644 (file)
index 0000000..6a94f36
--- /dev/null
@@ -0,0 +1,37 @@
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 14\r
+VisualStudioVersion = 14.0.23107.0\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "soundstretch", "soundstretch.vcxproj", "{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "..\SoundTouch\SoundTouch.vcxproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Debug|x64 = Debug|x64\r
+               Release|Win32 = Release|Win32\r
+               Release|x64 = Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|Win32.Build.0 = Debug|Win32\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|x64.ActiveCfg = Debug|x64\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|x64.Build.0 = Debug|x64\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|Win32.ActiveCfg = Release|Win32\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|Win32.Build.0 = Release|Win32\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|x64.ActiveCfg = Release|x64\r
+               {5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|x64.Build.0 = Release|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.Build.0 = Debug|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.ActiveCfg = Debug|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.Build.0 = Debug|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.ActiveCfg = Release|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.Build.0 = Release|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.ActiveCfg = Release|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.Build.0 = Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/source/SoundStretch/soundstretch.vcxproj b/source/SoundStretch/soundstretch.vcxproj
new file mode 100644 (file)
index 0000000..86308e9
--- /dev/null
@@ -0,0 +1,337 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|x64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|x64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}</ProjectGuid>\r
+    <RootNamespace>soundstretch</RootNamespace>\r
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup>\r
+    <_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <TargetName>$(ProjectName)D</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <TargetName>$(ProjectName)D_x64</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <TargetName>$(ProjectName)_x64</TargetName>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <Midl>\r
+      <TypeLibraryName>.\Debug/soundstretch.tlb</TypeLibraryName>\r
+      <HeaderFileName />\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Disabled</Optimization>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
+      <StructMemberAlignment>16Bytes</StructMemberAlignment>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <BrowseInformation>true</BrowseInformation>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>\r
+      <GenerateMapFile>true</GenerateMapFile>\r
+      <MapFileName>$(OutDir)$(TargetName).map</MapFileName>\r
+      <SubSystem>Console</SubSystem>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <TargetMachine>MachineX86</TargetMachine>\r
+      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\bin mkdir ..\..\bin\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <Midl>\r
+      <TypeLibraryName>.\Release/soundstretch.tlb</TypeLibraryName>\r
+      <HeaderFileName />\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Full</Optimization>\r
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <StringPooling>true</StringPooling>\r
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat />\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <GenerateDebugInformation>false</GenerateDebugInformation>\r
+      <GenerateMapFile>true</GenerateMapFile>\r
+      <MapFileName>$(OutDir)$(TargetName).map</MapFileName>\r
+      <SubSystem>Console</SubSystem>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <TargetMachine>MachineX86</TargetMachine>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\bin mkdir ..\..\bin\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+      <TypeLibraryName>.\Debug/soundstretch.tlb</TypeLibraryName>\r
+      <HeaderFileName />\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Disabled</Optimization>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
+      <StructMemberAlignment>16Bytes</StructMemberAlignment>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <BrowseInformation>true</BrowseInformation>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>\r
+      </EnableEnhancedInstructionSet>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>\r
+      <GenerateMapFile>true</GenerateMapFile>\r
+      <MapFileName>$(OutDir)$(TargetName).map</MapFileName>\r
+      <SubSystem>Console</SubSystem>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <TargetMachine>MachineX64</TargetMachine>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\bin mkdir ..\..\bin\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+      <TypeLibraryName>.\Release/soundstretch.tlb</TypeLibraryName>\r
+      <HeaderFileName />\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Full</Optimization>\r
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <StringPooling>true</StringPooling>\r
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat />\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>\r
+      </EnableEnhancedInstructionSet>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Link>\r
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
+      <GenerateDebugInformation>false</GenerateDebugInformation>\r
+      <GenerateMapFile>true</GenerateMapFile>\r
+      <MapFileName>$(OutDir)$(TargetName).map</MapFileName>\r
+      <SubSystem>Console</SubSystem>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <TargetMachine>MachineX64</TargetMachine>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\bin mkdir ..\..\bin\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="main.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+    <ClCompile Include="RunParameters.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+    <ClCompile Include="WavFile.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="RunParameters.h" />\r
+    <ClInclude Include="WavFile.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\SoundTouch\SoundTouch.vcxproj">\r
+      <Project>{68a5dd20-7057-448b-8fe0-b6ac8d205509}</Project>\r
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
+    </ProjectReference>\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>
\ No newline at end of file
diff --git a/source/SoundTouch/AAFilter.cpp b/source/SoundTouch/AAFilter.cpp
new file mode 100644 (file)
index 0000000..76a3da6
--- /dev/null
@@ -0,0 +1,222 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// FIR low-pass (anti-alias) filter with filter coefficient design routine and\r
+/// MMX optimization. \r
+/// \r
+/// Anti-alias filter is used to prevent folding of high frequencies when \r
+/// transposing the sample rate with interpolation.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <memory.h>\r
+#include <assert.h>\r
+#include <math.h>\r
+#include <stdlib.h>\r
+#include "AAFilter.h"\r
+#include "FIRFilter.h"\r
+\r
+using namespace soundtouch;\r
+\r
+#define PI       3.14159265358979323846\r
+#define TWOPI    (2 * PI)\r
+\r
+// define this to save AA filter coefficients to a file\r
+// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS   1\r
+\r
+#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS\r
+    #include <stdio.h>\r
+\r
+    static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)\r
+    {\r
+        FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");\r
+        if (fptr == NULL) return;\r
+\r
+        for (int i = 0; i < len; i ++)\r
+        {\r
+            double temp = coeffs[i];\r
+            fprintf(fptr, "%lf\n", temp);\r
+        }\r
+        fclose(fptr);\r
+    }\r
+\r
+#else\r
+    #define _DEBUG_SAVE_AAFIR_COEFFS(x, y)\r
+#endif\r
+\r
+/*****************************************************************************\r
+ *\r
+ * Implementation of the class 'AAFilter'\r
+ *\r
+ *****************************************************************************/\r
+\r
+AAFilter::AAFilter(uint len)\r
+{\r
+    pFIR = FIRFilter::newInstance();\r
+    cutoffFreq = 0.5;\r
+    setLength(len);\r
+}\r
+\r
+\r
+AAFilter::~AAFilter()\r
+{\r
+    delete pFIR;\r
+}\r
+\r
+\r
+// Sets new anti-alias filter cut-off edge frequency, scaled to\r
+// sampling frequency (nyquist frequency = 0.5).\r
+// The filter will cut frequencies higher than the given frequency.\r
+void AAFilter::setCutoffFreq(double newCutoffFreq)\r
+{\r
+    cutoffFreq = newCutoffFreq;\r
+    calculateCoeffs();\r
+}\r
+\r
+\r
+// Sets number of FIR filter taps\r
+void AAFilter::setLength(uint newLength)\r
+{\r
+    length = newLength;\r
+    calculateCoeffs();\r
+}\r
+\r
+\r
+// Calculates coefficients for a low-pass FIR filter using Hamming window\r
+void AAFilter::calculateCoeffs()\r
+{\r
+    uint i;\r
+    double cntTemp, temp, tempCoeff,h, w;\r
+    double wc;\r
+    double scaleCoeff, sum;\r
+    double *work;\r
+    SAMPLETYPE *coeffs;\r
+\r
+    assert(length >= 2);\r
+    assert(length % 4 == 0);\r
+    assert(cutoffFreq >= 0);\r
+    assert(cutoffFreq <= 0.5);\r
+\r
+    work = new double[length];\r
+    coeffs = new SAMPLETYPE[length];\r
+\r
+    wc = 2.0 * PI * cutoffFreq;\r
+    tempCoeff = TWOPI / (double)length;\r
+\r
+    sum = 0;\r
+    for (i = 0; i < length; i ++) \r
+    {\r
+        cntTemp = (double)i - (double)(length / 2);\r
+\r
+        temp = cntTemp * wc;\r
+        if (temp != 0) \r
+        {\r
+            h = sin(temp) / temp;                     // sinc function\r
+        } \r
+        else \r
+        {\r
+            h = 1.0;\r
+        }\r
+        w = 0.54 + 0.46 * cos(tempCoeff * cntTemp);       // hamming window\r
+\r
+        temp = w * h;\r
+        work[i] = temp;\r
+\r
+        // calc net sum of coefficients \r
+        sum += temp;\r
+    }\r
+\r
+    // ensure the sum of coefficients is larger than zero\r
+    assert(sum > 0);\r
+\r
+    // ensure we've really designed a lowpass filter...\r
+    assert(work[length/2] > 0);\r
+    assert(work[length/2 + 1] > -1e-6);\r
+    assert(work[length/2 - 1] > -1e-6);\r
+\r
+    // Calculate a scaling coefficient in such a way that the result can be\r
+    // divided by 16384\r
+    scaleCoeff = 16384.0f / sum;\r
+\r
+    for (i = 0; i < length; i ++) \r
+    {\r
+        temp = work[i] * scaleCoeff;\r
+        // scale & round to nearest integer\r
+        temp += (temp >= 0) ? 0.5 : -0.5;\r
+        // ensure no overfloods\r
+        assert(temp >= -32768 && temp <= 32767);\r
+        coeffs[i] = (SAMPLETYPE)temp;\r
+    }\r
+\r
+    // Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384\r
+    pFIR->setCoefficients(coeffs, length, 14);\r
+\r
+    _DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);\r
+\r
+    delete[] work;\r
+    delete[] coeffs;\r
+}\r
+\r
+\r
+// Applies the filter to the given sequence of samples. \r
+// Note : The amount of outputted samples is by value of 'filter length' \r
+// smaller than the amount of input samples.\r
+uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const\r
+{\r
+    return pFIR->evaluate(dest, src, numSamples, numChannels);\r
+}\r
+\r
+\r
+/// Applies the filter to the given src & dest pipes, so that processed amount of\r
+/// samples get removed from src, and produced amount added to dest \r
+/// Note : The amount of outputted samples is by value of 'filter length' \r
+/// smaller than the amount of input samples.\r
+uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const\r
+{\r
+    SAMPLETYPE *pdest;\r
+    const SAMPLETYPE *psrc;\r
+    uint numSrcSamples;\r
+    uint result;\r
+    int numChannels = src.getChannels();\r
+\r
+    assert(numChannels == dest.getChannels());\r
+\r
+    numSrcSamples = src.numSamples();\r
+    psrc = src.ptrBegin();\r
+    pdest = dest.ptrEnd(numSrcSamples);\r
+    result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);\r
+    src.receiveSamples(result);\r
+    dest.putSamples(result);\r
+\r
+    return result;\r
+}\r
+\r
+\r
+uint AAFilter::getLength() const\r
+{\r
+    return pFIR->getLength();\r
+}\r
diff --git a/source/SoundTouch/AAFilter.h b/source/SoundTouch/AAFilter.h
new file mode 100644 (file)
index 0000000..8e5697f
--- /dev/null
@@ -0,0 +1,93 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo \r
+/// while maintaining the original pitch by using a time domain WSOLA-like method \r
+/// with several performance-increasing tweaks.\r
+///\r
+/// Anti-alias filter is used to prevent folding of high frequencies when \r
+/// transposing the sample rate with interpolation.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef AAFilter_H\r
+#define AAFilter_H\r
+\r
+#include "STTypes.h"\r
+#include "FIFOSampleBuffer.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+class AAFilter\r
+{\r
+protected:\r
+    class FIRFilter *pFIR;\r
+\r
+    /// Low-pass filter cut-off frequency, negative = invalid\r
+    double cutoffFreq;\r
+\r
+    /// num of filter taps\r
+    uint length;\r
+\r
+    /// Calculate the FIR coefficients realizing the given cutoff-frequency\r
+    void calculateCoeffs();\r
+public:\r
+    AAFilter(uint length);\r
+\r
+    ~AAFilter();\r
+\r
+    /// Sets new anti-alias filter cut-off edge frequency, scaled to sampling \r
+    /// frequency (nyquist frequency = 0.5). The filter will cut off the \r
+    /// frequencies than that.\r
+    void setCutoffFreq(double newCutoffFreq);\r
+\r
+    /// Sets number of FIR filter taps, i.e. ~filter complexity\r
+    void setLength(uint newLength);\r
+\r
+    uint getLength() const;\r
+\r
+    /// Applies the filter to the given sequence of samples. \r
+    /// Note : The amount of outputted samples is by value of 'filter length' \r
+    /// smaller than the amount of input samples.\r
+    uint evaluate(SAMPLETYPE *dest, \r
+                  const SAMPLETYPE *src, \r
+                  uint numSamples, \r
+                  uint numChannels) const;\r
+\r
+    /// Applies the filter to the given src & dest pipes, so that processed amount of\r
+    /// samples get removed from src, and produced amount added to dest \r
+    /// Note : The amount of outputted samples is by value of 'filter length' \r
+    /// smaller than the amount of input samples.\r
+    uint evaluate(FIFOSampleBuffer &dest, \r
+                  FIFOSampleBuffer &src) const;\r
+\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/source/SoundTouch/BPMDetect.cpp b/source/SoundTouch/BPMDetect.cpp
new file mode 100644 (file)
index 0000000..01202f0
--- /dev/null
@@ -0,0 +1,572 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Beats-per-minute (BPM) detection routine.\r
+///\r
+/// The beat detection algorithm works as follows:\r
+/// - Use function 'inputSamples' to input a chunks of samples to the class for\r
+///   analysis. It's a good idea to enter a large sound file or stream in smallish\r
+///   chunks of around few kilosamples in order not to extinguish too much RAM memory.\r
+/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden,\r
+///   which is basically ok as low (bass) frequencies mostly determine the beat rate.\r
+///   Simple averaging is used for anti-alias filtering because the resulting signal\r
+///   quality isn't of that high importance.\r
+/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by\r
+///   taking absolute value that's smoothed by sliding average. Signal levels that\r
+///   are below a couple of times the general RMS amplitude level are cut away to\r
+///   leave only notable peaks there.\r
+/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term \r
+///   autocorrelation function of the enveloped signal.\r
+/// - After whole sound data file has been analyzed as above, the bpm level is \r
+///   detected by function 'getBpm' that finds the highest peak of the autocorrelation \r
+///   function, calculates it's precise location and converts this reading to bpm's.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#define _USE_MATH_DEFINES\r
+\r
+#include <math.h>\r
+#include <assert.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+#include <cfloat>\r
+#include "FIFOSampleBuffer.h"\r
+#include "PeakFinder.h"\r
+#include "BPMDetect.h"\r
+\r
+using namespace soundtouch;\r
+\r
+// algorithm input sample block size\r
+static const int INPUT_BLOCK_SIZE = 2048;\r
+\r
+// decimated sample block size\r
+static const int DECIMATED_BLOCK_SIZE = 256;\r
+\r
+/// Target sample rate after decimation\r
+static const int TARGET_SRATE = 1000;\r
+\r
+/// XCorr update sequence size, update in about 200msec chunks\r
+static const int XCORR_UPDATE_SEQUENCE = (int)(TARGET_SRATE / 5);\r
+\r
+/// Moving average N size\r
+static const int MOVING_AVERAGE_N = 15;\r
+\r
+/// XCorr decay time constant, decay to half in 30 seconds\r
+/// If it's desired to have the system adapt quicker to beat rate \r
+/// changes within a continuing music stream, then the \r
+/// 'xcorr_decay_time_constant' value can be reduced, yet that\r
+/// can increase possibility of glitches in bpm detection.\r
+static const double XCORR_DECAY_TIME_CONSTANT = 30.0;\r
+\r
+/// Data overlap factor for beat detection algorithm\r
+static const int OVERLAP_FACTOR = 4;\r
+\r
+static const double TWOPI = (2 * M_PI);\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+// Enable following define to create bpm analysis file:\r
+\r
+//#define _CREATE_BPM_DEBUG_FILE\r
+\r
+#ifdef _CREATE_BPM_DEBUG_FILE\r
+\r
+    static void _SaveDebugData(const char *name, const float *data, int minpos, int maxpos, double coeff)\r
+    {\r
+        FILE *fptr = fopen(name, "wt");\r
+        int i;\r
+\r
+        if (fptr)\r
+        {\r
+            printf("\nWriting BPM debug data into file %s\n", name);\r
+            for (i = minpos; i < maxpos; i ++)\r
+            {\r
+                fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]);\r
+            }\r
+            fclose(fptr);\r
+        }\r
+    }\r
+\r
+    void _SaveDebugBeatPos(const char *name, const std::vector<BEAT> &beats)\r
+    {\r
+        printf("\nWriting beat detections data into file %s\n", name);\r
+\r
+        FILE *fptr = fopen(name, "wt");\r
+        if (fptr)\r
+        {\r
+            for (uint i = 0; i < beats.size(); i++)\r
+            {\r
+                BEAT b = beats[i];\r
+                fprintf(fptr, "%lf\t%lf\n", b.pos, b.strength);\r
+            }\r
+            fclose(fptr);\r
+        }\r
+    }\r
+#else\r
+    #define _SaveDebugData(name, a,b,c,d)\r
+    #define _SaveDebugBeatPos(name, b)\r
+#endif\r
+\r
+// Hamming window\r
+void hamming(float *w, int N)\r
+{\r
+    for (int i = 0; i < N; i++)\r
+    {\r
+        w[i] = (float)(0.54 - 0.46 * cos(TWOPI * i / (N - 1)));\r
+    }\r
+\r
+}\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// IIR2_filter - 2nd order IIR filter\r
+\r
+IIR2_filter::IIR2_filter(const double *lpf_coeffs)\r
+{\r
+    memcpy(coeffs, lpf_coeffs, 5 * sizeof(double));\r
+    memset(prev, 0, sizeof(prev));\r
+}\r
+\r
+\r
+float IIR2_filter::update(float x)\r
+{\r
+    prev[0] = x;\r
+    double y = x * coeffs[0];\r
+\r
+    for (int i = 4; i >= 1; i--)\r
+    {\r
+        y += coeffs[i] * prev[i];\r
+        prev[i] = prev[i - 1];\r
+    }\r
+\r
+    prev[3] = y;\r
+    return (float)y;\r
+}\r
+\r
+\r
+// IIR low-pass filter coefficients, calculated with matlab/octave cheby2(2,40,0.05)\r
+const double _LPF_coeffs[5] = { 0.00996655391939, -0.01944529148401, 0.00996655391939, 1.96867605796247, -0.96916387431724 };\r
+\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+BPMDetect::BPMDetect(int numChannels, int aSampleRate) :\r
+    beat_lpf(_LPF_coeffs)\r
+{\r
+    beats.reserve(250); // initial reservation to prevent frequent reallocation\r
+\r
+    this->sampleRate = aSampleRate;\r
+    this->channels = numChannels;\r
+\r
+    decimateSum = 0;\r
+    decimateCount = 0;\r
+\r
+    // choose decimation factor so that result is approx. 1000 Hz\r
+    decimateBy = sampleRate / TARGET_SRATE;\r
+    assert(decimateBy > 0);\r
+    assert(INPUT_BLOCK_SIZE < decimateBy * DECIMATED_BLOCK_SIZE);\r
+\r
+    // Calculate window length & starting item according to desired min & max bpms\r
+    windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);\r
+    windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM_RANGE);\r
+\r
+    assert(windowLen > windowStart);\r
+\r
+    // allocate new working objects\r
+    xcorr = new float[windowLen];\r
+    memset(xcorr, 0, windowLen * sizeof(float));\r
+\r
+    pos = 0;\r
+    peakPos = 0;\r
+    peakVal = 0;\r
+    init_scaler = 1;\r
+    beatcorr_ringbuffpos = 0;\r
+    beatcorr_ringbuff = new float[windowLen];\r
+    memset(beatcorr_ringbuff, 0, windowLen * sizeof(float));\r
+\r
+    // allocate processing buffer\r
+    buffer = new FIFOSampleBuffer();\r
+    // we do processing in mono mode\r
+    buffer->setChannels(1);\r
+    buffer->clear();\r
+\r
+    // calculate hamming windows\r
+    hamw = new float[XCORR_UPDATE_SEQUENCE];\r
+    hamming(hamw, XCORR_UPDATE_SEQUENCE);\r
+    hamw2 = new float[XCORR_UPDATE_SEQUENCE / 2];\r
+    hamming(hamw2, XCORR_UPDATE_SEQUENCE / 2);\r
+}\r
+\r
+\r
+BPMDetect::~BPMDetect()\r
+{\r
+    delete[] xcorr;\r
+    delete[] beatcorr_ringbuff;\r
+    delete[] hamw;\r
+    delete[] hamw2;\r
+    delete buffer;\r
+}\r
+\r
+\r
+/// convert to mono, low-pass filter & decimate to about 500 Hz. \r
+/// return number of outputted samples.\r
+///\r
+/// Decimation is used to remove the unnecessary frequencies and thus to reduce \r
+/// the amount of data needed to be processed as calculating autocorrelation \r
+/// function is a very-very heavy operation.\r
+///\r
+/// Anti-alias filtering is done simply by averaging the samples. This is really a \r
+/// poor-man's anti-alias filtering, but it's not so critical in this kind of application\r
+/// (it'd also be difficult to design a high-quality filter with steep cut-off at very \r
+/// narrow band)\r
+int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)\r
+{\r
+    int count, outcount;\r
+    LONG_SAMPLETYPE out;\r
+\r
+    assert(channels > 0);\r
+    assert(decimateBy > 0);\r
+    outcount = 0;\r
+    for (count = 0; count < numsamples; count ++) \r
+    {\r
+        int j;\r
+\r
+        // convert to mono and accumulate\r
+        for (j = 0; j < channels; j ++)\r
+        {\r
+            decimateSum += src[j];\r
+        }\r
+        src += j;\r
+\r
+        decimateCount ++;\r
+        if (decimateCount >= decimateBy) \r
+        {\r
+            // Store every Nth sample only\r
+            out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels));\r
+            decimateSum = 0;\r
+            decimateCount = 0;\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+            // check ranges for sure (shouldn't actually be necessary)\r
+            if (out > 32767) \r
+            {\r
+                out = 32767;\r
+            } \r
+            else if (out < -32768) \r
+            {\r
+                out = -32768;\r
+            }\r
+#endif // SOUNDTOUCH_INTEGER_SAMPLES\r
+            dest[outcount] = (SAMPLETYPE)out;\r
+            outcount ++;\r
+        }\r
+    }\r
+    return outcount;\r
+}\r
+\r
+\r
+// Calculates autocorrelation function of the sample history buffer\r
+void BPMDetect::updateXCorr(int process_samples)\r
+{\r
+    int offs;\r
+    SAMPLETYPE *pBuffer;\r
+    \r
+    assert(buffer->numSamples() >= (uint)(process_samples + windowLen));\r
+    assert(process_samples == XCORR_UPDATE_SEQUENCE);\r
+\r
+    pBuffer = buffer->ptrBegin();\r
+\r
+    // calculate decay factor for xcorr filtering\r
+    float xcorr_decay = (float)pow(0.5, 1.0 / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE / process_samples));\r
+\r
+    // prescale pbuffer\r
+    float tmp[XCORR_UPDATE_SEQUENCE];\r
+    for (int i = 0; i < process_samples; i++)\r
+    {\r
+        tmp[i] = hamw[i] * hamw[i] * pBuffer[i];\r
+    }\r
+\r
+    #pragma omp parallel for\r
+    for (offs = windowStart; offs < windowLen; offs ++) \r
+    {\r
+        double sum;\r
+        int i;\r
+\r
+        sum = 0;\r
+        for (i = 0; i < process_samples; i ++) \r
+        {\r
+            sum += tmp[i] * pBuffer[i + offs];  // scaling the sub-result shouldn't be necessary\r
+        }\r
+        xcorr[offs] *= xcorr_decay;   // decay 'xcorr' here with suitable time constant.\r
+\r
+        xcorr[offs] += (float)fabs(sum);\r
+    }\r
+}\r
+\r
+\r
+// Detect individual beat positions\r
+void BPMDetect::updateBeatPos(int process_samples)\r
+{\r
+    SAMPLETYPE *pBuffer;\r
+\r
+    assert(buffer->numSamples() >= (uint)(process_samples + windowLen));\r
+\r
+    pBuffer = buffer->ptrBegin();\r
+    assert(process_samples == XCORR_UPDATE_SEQUENCE / 2);\r
+\r
+    //    static double thr = 0.0003;\r
+    double posScale = (double)this->decimateBy / (double)this->sampleRate;\r
+    int resetDur = (int)(0.12 / posScale + 0.5);\r
+    double corrScale = 1.0 / (double)(windowLen - windowStart);\r
+\r
+    // prescale pbuffer\r
+    float tmp[XCORR_UPDATE_SEQUENCE / 2];\r
+    for (int i = 0; i < process_samples; i++)\r
+    {\r
+        tmp[i] = hamw2[i] * hamw2[i] * pBuffer[i];\r
+    }\r
+\r
+    #pragma omp parallel for\r
+    for (int offs = windowStart; offs < windowLen; offs++)\r
+    {\r
+        double sum = 0;\r
+        for (int i = 0; i < process_samples; i++)\r
+        {\r
+            sum += tmp[i] * pBuffer[offs + i];\r
+        }\r
+        beatcorr_ringbuff[(beatcorr_ringbuffpos + offs) % windowLen] += (float)((sum > 0) ? sum : 0); // accumulate only positive correlations\r
+    }\r
+\r
+    int skipstep = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;\r
+\r
+    // compensate empty buffer at beginning by scaling coefficient\r
+    float scale = (float)windowLen / (float)(skipstep * init_scaler);\r
+    if (scale > 1.0f)\r
+    {\r
+        init_scaler++;\r
+    }\r
+    else\r
+    {\r
+        scale = 1.0f;\r
+    }\r
+\r
+    // detect beats\r
+    for (int i = 0; i < skipstep; i++)\r
+    {\r
+        LONG_SAMPLETYPE max = 0;\r
+\r
+        float sum = beatcorr_ringbuff[beatcorr_ringbuffpos];\r
+        sum -= beat_lpf.update(sum);\r
+\r
+        if (sum > peakVal)\r
+        {\r
+            // found new local largest value\r
+            peakVal = sum;\r
+            peakPos = pos;\r
+        }\r
+        if (pos > peakPos + resetDur)\r
+        {\r
+            // largest value not updated for 200msec => accept as beat\r
+            peakPos += skipstep;\r
+            if (peakVal > 0)\r
+            {\r
+                // add detected beat to end of "beats" vector\r
+                BEAT temp = { (float)(peakPos * posScale), (float)(peakVal * scale) };\r
+                beats.push_back(temp);\r
+            }\r
+\r
+            peakVal = 0;\r
+            peakPos = pos;\r
+        }\r
+\r
+        beatcorr_ringbuff[beatcorr_ringbuffpos] = 0;\r
+        pos++;\r
+        beatcorr_ringbuffpos = (beatcorr_ringbuffpos + 1) % windowLen;\r
+    }\r
+}\r
+\r
+\r
+#define max(x,y) ((x) > (y) ? (x) : (y))\r
+\r
+void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)\r
+{\r
+    SAMPLETYPE decimated[DECIMATED_BLOCK_SIZE];\r
+\r
+    // iterate so that max INPUT_BLOCK_SAMPLES processed per iteration\r
+    while (numSamples > 0)\r
+    {\r
+        int block;\r
+        int decSamples;\r
+\r
+        block = (numSamples > INPUT_BLOCK_SIZE) ? INPUT_BLOCK_SIZE : numSamples;\r
+\r
+        // decimate. note that converts to mono at the same time\r
+        decSamples = decimate(decimated, samples, block);\r
+        samples += block * channels;\r
+        numSamples -= block;\r
+\r
+        buffer->putSamples(decimated, decSamples);\r
+    }\r
+\r
+    // when the buffer has enough samples for processing...\r
+    int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE);\r
+    while ((int)buffer->numSamples() >= req) \r
+    {\r
+        // ... update autocorrelations...\r
+        updateXCorr(XCORR_UPDATE_SEQUENCE);\r
+        // ...update beat position calculation...\r
+        updateBeatPos(XCORR_UPDATE_SEQUENCE / 2);\r
+        // ... and remove proceessed samples from the buffer\r
+        int n = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;\r
+        buffer->receiveSamples(n);\r
+    }\r
+}\r
+\r
+\r
+void BPMDetect::removeBias()\r
+{\r
+    int i;\r
+\r
+    // Remove linear bias: calculate linear regression coefficient\r
+    // 1. calc mean of 'xcorr' and 'i'\r
+    double mean_i = 0;\r
+    double mean_x = 0;\r
+    for (i = windowStart; i < windowLen; i++)\r
+    {\r
+        mean_x += xcorr[i];\r
+    }\r
+    mean_x /= (windowLen - windowStart);\r
+    mean_i = 0.5 * (windowLen - 1 + windowStart);\r
+\r
+    // 2. calculate linear regression coefficient\r
+    double b = 0;\r
+    double div = 0;\r
+    for (i = windowStart; i < windowLen; i++)\r
+    {\r
+        double xt = xcorr[i] - mean_x;\r
+        double xi = i - mean_i;\r
+        b += xt * xi;\r
+        div += xi * xi;\r
+    }\r
+    b /= div;\r
+\r
+    // subtract linear regression and resolve min. value bias\r
+    float minval = FLT_MAX;   // arbitrary large number\r
+    for (i = windowStart; i < windowLen; i ++)\r
+    {\r
+        xcorr[i] -= (float)(b * i);\r
+        if (xcorr[i] < minval)\r
+        {\r
+            minval = xcorr[i];\r
+        }\r
+    }\r
+\r
+    // subtract min.value\r
+    for (i = windowStart; i < windowLen; i ++)\r
+    {\r
+        xcorr[i] -= minval;\r
+    }\r
+}\r
+\r
+\r
+// Calculate N-point moving average for "source" values\r
+void MAFilter(float *dest, const float *source, int start, int end, int N)\r
+{\r
+    for (int i = start; i < end; i++)\r
+    {\r
+        int i1 = i - N / 2;\r
+        int i2 = i + N / 2 + 1;\r
+        if (i1 < start) i1 = start;\r
+        if (i2 > end)   i2 = end;\r
+\r
+        double sum = 0;\r
+        for (int j = i1; j < i2; j ++)\r
+        { \r
+            sum += source[j];\r
+        }\r
+        dest[i] = (float)(sum / (i2 - i1));\r
+    }\r
+}\r
+\r
+\r
+float BPMDetect::getBpm()\r
+{\r
+    double peakPos;\r
+    double coeff;\r
+    PeakFinder peakFinder;\r
+\r
+    // remove bias from xcorr data\r
+    removeBias();\r
+\r
+    coeff = 60.0 * ((double)sampleRate / (double)decimateBy);\r
+\r
+    // save bpm debug data if debug data writing enabled\r
+    _SaveDebugData("soundtouch-bpm-xcorr.txt", xcorr, windowStart, windowLen, coeff);\r
+\r
+    // Smoothen by N-point moving-average\r
+    float *data = new float[windowLen];\r
+    memset(data, 0, sizeof(float) * windowLen);\r
+    MAFilter(data, xcorr, windowStart, windowLen, MOVING_AVERAGE_N);\r
+\r
+    // find peak position\r
+    peakPos = peakFinder.detectPeak(data, windowStart, windowLen);\r
+\r
+    // save bpm debug data if debug data writing enabled\r
+    _SaveDebugData("soundtouch-bpm-smoothed.txt", data, windowStart, windowLen, coeff);\r
+\r
+    delete[] data;\r
+\r
+    assert(decimateBy != 0);\r
+    if (peakPos < 1e-9) return 0.0; // detection failed.\r
+\r
+    _SaveDebugBeatPos("soundtouch-detected-beats.txt", beats);\r
+\r
+    // calculate BPM\r
+    float bpm = (float)(coeff / peakPos);\r
+    return (bpm >= MIN_BPM && bpm <= MAX_BPM_VALID) ? bpm : 0;\r
+}\r
+\r
+\r
+/// Get beat position arrays. Note: The array includes also really low beat detection values \r
+/// in absence of clear strong beats. Consumer may wish to filter low values away.\r
+/// - "pos" receive array of beat positions\r
+/// - "values" receive array of beat detection strengths\r
+/// - max_num indicates max.size of "pos" and "values" array.  \r
+///\r
+/// You can query a suitable array sized by calling this with NULL in "pos" & "values".\r
+///\r
+/// \return number of beats in the arrays.\r
+int BPMDetect::getBeats(float *pos, float *values, int max_num)\r
+{\r
+    int num = beats.size();\r
+    if ((!pos) || (!values)) return num;    // pos or values NULL, return just size\r
+\r
+    for (int i = 0; (i < num) && (i < max_num); i++)\r
+    {\r
+        pos[i] = beats[i].pos;\r
+        values[i] = beats[i].strength;\r
+    }\r
+    return num;\r
+}\r
diff --git a/source/SoundTouch/FIFOSampleBuffer.cpp b/source/SoundTouch/FIFOSampleBuffer.cpp
new file mode 100644 (file)
index 0000000..8341163
--- /dev/null
@@ -0,0 +1,267 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// A buffer class for temporarily storaging sound samples, operates as a \r
+/// first-in-first-out pipe.\r
+///\r
+/// Samples are added to the end of the sample buffer with the 'putSamples' \r
+/// function, and are received from the beginning of the buffer by calling\r
+/// the 'receiveSamples' function. The class automatically removes the \r
+/// outputted samples from the buffer, as well as grows the buffer size \r
+/// whenever necessary.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <stdlib.h>\r
+#include <memory.h>\r
+#include <string.h>\r
+#include <assert.h>\r
+\r
+#include "FIFOSampleBuffer.h"\r
+\r
+using namespace soundtouch;\r
+\r
+// Constructor\r
+FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)\r
+{\r
+    assert(numChannels > 0);\r
+    sizeInBytes = 0; // reasonable initial value\r
+    buffer = NULL;\r
+    bufferUnaligned = NULL;\r
+    samplesInBuffer = 0;\r
+    bufferPos = 0;\r
+    channels = (uint)numChannels;\r
+    ensureCapacity(32);     // allocate initial capacity \r
+}\r
+\r
+\r
+// destructor\r
+FIFOSampleBuffer::~FIFOSampleBuffer()\r
+{\r
+    delete[] bufferUnaligned;\r
+    bufferUnaligned = NULL;\r
+    buffer = NULL;\r
+}\r
+\r
+\r
+// Sets number of channels, 1 = mono, 2 = stereo\r
+void FIFOSampleBuffer::setChannels(int numChannels)\r
+{\r
+    uint usedBytes;\r
+\r
+    if (!verifyNumberOfChannels(numChannels)) return;\r
+\r
+    usedBytes = channels * samplesInBuffer;\r
+    channels = (uint)numChannels;\r
+    samplesInBuffer = usedBytes / channels;\r
+}\r
+\r
+\r
+// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and\r
+// zeroes this pointer by copying samples from the 'bufferPos' pointer \r
+// location on to the beginning of the buffer.\r
+void FIFOSampleBuffer::rewind()\r
+{\r
+    if (buffer && bufferPos) \r
+    {\r
+        memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);\r
+        bufferPos = 0;\r
+    }\r
+}\r
+\r
+\r
+// Adds 'numSamples' pcs of samples from the 'samples' memory position to \r
+// the sample buffer.\r
+void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)\r
+{\r
+    memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);\r
+    samplesInBuffer += nSamples;\r
+}\r
+\r
+\r
+// Increases the number of samples in the buffer without copying any actual\r
+// samples.\r
+//\r
+// This function is used to update the number of samples in the sample buffer\r
+// when accessing the buffer directly with 'ptrEnd' function. Please be \r
+// careful though!\r
+void FIFOSampleBuffer::putSamples(uint nSamples)\r
+{\r
+    uint req;\r
+\r
+    req = samplesInBuffer + nSamples;\r
+    ensureCapacity(req);\r
+    samplesInBuffer += nSamples;\r
+}\r
+\r
+\r
+// Returns a pointer to the end of the used part of the sample buffer (i.e. \r
+// where the new samples are to be inserted). This function may be used for \r
+// inserting new samples into the sample buffer directly. Please be careful! \r
+//\r
+// Parameter 'slackCapacity' tells the function how much free capacity (in\r
+// terms of samples) there _at least_ should be, in order to the caller to\r
+// successfully insert all the required samples to the buffer. When necessary, \r
+// the function grows the buffer size to comply with this requirement.\r
+//\r
+// When using this function as means for inserting new samples, also remember \r
+// to increase the sample count afterwards, by calling  the \r
+// 'putSamples(numSamples)' function.\r
+SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity) \r
+{\r
+    ensureCapacity(samplesInBuffer + slackCapacity);\r
+    return buffer + samplesInBuffer * channels;\r
+}\r
+\r
+\r
+// Returns a pointer to the beginning of the currently non-outputted samples. \r
+// This function is provided for accessing the output samples directly. \r
+// Please be careful!\r
+//\r
+// When using this function to output samples, also remember to 'remove' the\r
+// outputted samples from the buffer by calling the \r
+// 'receiveSamples(numSamples)' function\r
+SAMPLETYPE *FIFOSampleBuffer::ptrBegin()\r
+{\r
+    assert(buffer);\r
+    return buffer + bufferPos * channels;\r
+}\r
+\r
+\r
+// Ensures that the buffer has enough capacity, i.e. space for _at least_\r
+// 'capacityRequirement' number of samples. The buffer is grown in steps of\r
+// 4 kilobytes to eliminate the need for frequently growing up the buffer,\r
+// as well as to round the buffer size up to the virtual memory page size.\r
+void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)\r
+{\r
+    SAMPLETYPE *tempUnaligned, *temp;\r
+\r
+    if (capacityRequirement > getCapacity()) \r
+    {\r
+        // enlarge the buffer in 4kbyte steps (round up to next 4k boundary)\r
+        sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;\r
+        assert(sizeInBytes % 2 == 0);\r
+        tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];\r
+        if (tempUnaligned == NULL)\r
+        {\r
+            ST_THROW_RT_ERROR("Couldn't allocate memory!\n");\r
+        }\r
+        // Align the buffer to begin at 16byte cache line boundary for optimal performance\r
+        temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned);\r
+        if (samplesInBuffer)\r
+        {\r
+            memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));\r
+        }\r
+        delete[] bufferUnaligned;\r
+        buffer = temp;\r
+        bufferUnaligned = tempUnaligned;\r
+        bufferPos = 0;\r
+    } \r
+    else \r
+    {\r
+        // simply rewind the buffer (if necessary)\r
+        rewind();\r
+    }\r
+}\r
+\r
+\r
+// Returns the current buffer capacity in terms of samples\r
+uint FIFOSampleBuffer::getCapacity() const\r
+{\r
+    return sizeInBytes / (channels * sizeof(SAMPLETYPE));\r
+}\r
+\r
+\r
+// Returns the number of samples currently in the buffer\r
+uint FIFOSampleBuffer::numSamples() const\r
+{\r
+    return samplesInBuffer;\r
+}\r
+\r
+\r
+// Output samples from beginning of the sample buffer. Copies demanded number\r
+// of samples to output and removes them from the sample buffer. If there\r
+// are less than 'numsample' samples in the buffer, returns all available.\r
+//\r
+// Returns number of samples copied.\r
+uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)\r
+{\r
+    uint num;\r
+\r
+    num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;\r
+\r
+    memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);\r
+    return receiveSamples(num);\r
+}\r
+\r
+\r
+// Removes samples from the beginning of the sample buffer without copying them\r
+// anywhere. Used to reduce the number of samples in the buffer, when accessing\r
+// the sample buffer with the 'ptrBegin' function.\r
+uint FIFOSampleBuffer::receiveSamples(uint maxSamples)\r
+{\r
+    if (maxSamples >= samplesInBuffer)\r
+    {\r
+        uint temp;\r
+\r
+        temp = samplesInBuffer;\r
+        samplesInBuffer = 0;\r
+        return temp;\r
+    }\r
+\r
+    samplesInBuffer -= maxSamples;\r
+    bufferPos += maxSamples;\r
+\r
+    return maxSamples;\r
+}\r
+\r
+\r
+// Returns nonzero if the sample buffer is empty\r
+int FIFOSampleBuffer::isEmpty() const\r
+{\r
+    return (samplesInBuffer == 0) ? 1 : 0;\r
+}\r
+\r
+\r
+// Clears the sample buffer\r
+void FIFOSampleBuffer::clear()\r
+{\r
+    samplesInBuffer = 0;\r
+    bufferPos = 0;\r
+}\r
+\r
+\r
+/// allow trimming (downwards) amount of samples in pipeline.\r
+/// Returns adjusted amount of samples\r
+uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)\r
+{\r
+    if (numSamples < samplesInBuffer)\r
+    {\r
+        samplesInBuffer = numSamples;\r
+    }\r
+    return samplesInBuffer;\r
+}\r
diff --git a/source/SoundTouch/FIRFilter.cpp b/source/SoundTouch/FIRFilter.cpp
new file mode 100644 (file)
index 0000000..218e50e
--- /dev/null
@@ -0,0 +1,324 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// General FIR digital filter routines with MMX optimization. \r
+///\r
+/// Notes : MMX optimized functions reside in a separate, platform-specific file, \r
+/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'\r
+///\r
+/// This source file contains OpenMP optimizations that allow speeding up the\r
+/// corss-correlation algorithm by executing it in several threads / CPU cores \r
+/// in parallel. See the following article link for more detailed discussion \r
+/// about SoundTouch OpenMP optimizations:\r
+/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <memory.h>\r
+#include <assert.h>\r
+#include <math.h>\r
+#include <stdlib.h>\r
+#include "FIRFilter.h"\r
+#include "cpu_detect.h"\r
+\r
+using namespace soundtouch;\r
+\r
+/*****************************************************************************\r
+ *\r
+ * Implementation of the class 'FIRFilter'\r
+ *\r
+ *****************************************************************************/\r
+\r
+FIRFilter::FIRFilter()\r
+{\r
+    resultDivFactor = 0;\r
+    resultDivider = 0;\r
+    length = 0;\r
+    lengthDiv8 = 0;\r
+    filterCoeffs = NULL;\r
+}\r
+\r
+\r
+FIRFilter::~FIRFilter()\r
+{\r
+    delete[] filterCoeffs;\r
+}\r
+\r
+\r
+// Usual C-version of the filter routine for stereo sound\r
+uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const\r
+{\r
+    int j, end;\r
+#ifdef SOUNDTOUCH_FLOAT_SAMPLES\r
+    // when using floating point samples, use a scaler instead of a divider\r
+    // because division is much slower operation than multiplying.\r
+    double dScaler = 1.0 / (double)resultDivider;\r
+#endif\r
+\r
+    assert(length != 0);\r
+    assert(src != NULL);\r
+    assert(dest != NULL);\r
+    assert(filterCoeffs != NULL);\r
+\r
+    end = 2 * (numSamples - length);\r
+\r
+    #pragma omp parallel for\r
+    for (j = 0; j < end; j += 2) \r
+    {\r
+        const SAMPLETYPE *ptr;\r
+        LONG_SAMPLETYPE suml, sumr;\r
+        uint i;\r
+\r
+        suml = sumr = 0;\r
+        ptr = src + j;\r
+\r
+        for (i = 0; i < length; i += 4) \r
+        {\r
+            // loop is unrolled by factor of 4 here for efficiency\r
+            suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +\r
+                    ptr[2 * i + 2] * filterCoeffs[i + 1] +\r
+                    ptr[2 * i + 4] * filterCoeffs[i + 2] +\r
+                    ptr[2 * i + 6] * filterCoeffs[i + 3];\r
+            sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +\r
+                    ptr[2 * i + 3] * filterCoeffs[i + 1] +\r
+                    ptr[2 * i + 5] * filterCoeffs[i + 2] +\r
+                    ptr[2 * i + 7] * filterCoeffs[i + 3];\r
+        }\r
+\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+        suml >>= resultDivFactor;\r
+        sumr >>= resultDivFactor;\r
+        // saturate to 16 bit integer limits\r
+        suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;\r
+        // saturate to 16 bit integer limits\r
+        sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;\r
+#else\r
+        suml *= dScaler;\r
+        sumr *= dScaler;\r
+#endif // SOUNDTOUCH_INTEGER_SAMPLES\r
+        dest[j] = (SAMPLETYPE)suml;\r
+        dest[j + 1] = (SAMPLETYPE)sumr;\r
+    }\r
+    return numSamples - length;\r
+}\r
+\r
+\r
+// Usual C-version of the filter routine for mono sound\r
+uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const\r
+{\r
+    int j, end;\r
+#ifdef SOUNDTOUCH_FLOAT_SAMPLES\r
+    // when using floating point samples, use a scaler instead of a divider\r
+    // because division is much slower operation than multiplying.\r
+    double dScaler = 1.0 / (double)resultDivider;\r
+#endif\r
+\r
+    assert(length != 0);\r
+\r
+    end = numSamples - length;\r
+    #pragma omp parallel for\r
+    for (j = 0; j < end; j ++) \r
+    {\r
+        const SAMPLETYPE *pSrc = src + j;\r
+        LONG_SAMPLETYPE sum;\r
+        uint i;\r
+\r
+        sum = 0;\r
+        for (i = 0; i < length; i += 4) \r
+        {\r
+            // loop is unrolled by factor of 4 here for efficiency\r
+            sum += pSrc[i + 0] * filterCoeffs[i + 0] + \r
+                   pSrc[i + 1] * filterCoeffs[i + 1] + \r
+                   pSrc[i + 2] * filterCoeffs[i + 2] + \r
+                   pSrc[i + 3] * filterCoeffs[i + 3];\r
+        }\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+        sum >>= resultDivFactor;\r
+        // saturate to 16 bit integer limits\r
+        sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;\r
+#else\r
+        sum *= dScaler;\r
+#endif // SOUNDTOUCH_INTEGER_SAMPLES\r
+        dest[j] = (SAMPLETYPE)sum;\r
+    }\r
+    return end;\r
+}\r
+\r
+\r
+uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)\r
+{\r
+    int j, end;\r
+\r
+#ifdef SOUNDTOUCH_FLOAT_SAMPLES\r
+    // when using floating point samples, use a scaler instead of a divider\r
+    // because division is much slower operation than multiplying.\r
+    double dScaler = 1.0 / (double)resultDivider;\r
+#endif\r
+\r
+    assert(length != 0);\r
+    assert(src != NULL);\r
+    assert(dest != NULL);\r
+    assert(filterCoeffs != NULL);\r
+    assert(numChannels < 16);\r
+\r
+    end = numChannels * (numSamples - length);\r
+\r
+    #pragma omp parallel for\r
+    for (j = 0; j < end; j += numChannels)\r
+    {\r
+        const SAMPLETYPE *ptr;\r
+        LONG_SAMPLETYPE sums[16];\r
+        uint c, i;\r
+\r
+        for (c = 0; c < numChannels; c ++)\r
+        {\r
+            sums[c] = 0;\r
+        }\r
+\r
+        ptr = src + j;\r
+\r
+        for (i = 0; i < length; i ++)\r
+        {\r
+            SAMPLETYPE coef=filterCoeffs[i];\r
+            for (c = 0; c < numChannels; c ++)\r
+            {\r
+                sums[c] += ptr[0] * coef;\r
+                ptr ++;\r
+            }\r
+        }\r
+        \r
+        for (c = 0; c < numChannels; c ++)\r
+        {\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+            sums[c] >>= resultDivFactor;\r
+#else\r
+            sums[c] *= dScaler;\r
+#endif // SOUNDTOUCH_INTEGER_SAMPLES\r
+            dest[j+c] = (SAMPLETYPE)sums[c];\r
+        }\r
+    }\r
+    return numSamples - length;\r
+}\r
+\r
+\r
+// Set filter coeffiecients and length.\r
+//\r
+// Throws an exception if filter length isn't divisible by 8\r
+void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)\r
+{\r
+    assert(newLength > 0);\r
+    if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8");\r
+\r
+    lengthDiv8 = newLength / 8;\r
+    length = lengthDiv8 * 8;\r
+    assert(length == newLength);\r
+\r
+    resultDivFactor = uResultDivFactor;\r
+    resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);\r
+\r
+    delete[] filterCoeffs;\r
+    filterCoeffs = new SAMPLETYPE[length];\r
+    memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));\r
+}\r
+\r
+\r
+uint FIRFilter::getLength() const\r
+{\r
+    return length;\r
+}\r
+\r
+\r
+// Applies the filter to the given sequence of samples. \r
+//\r
+// Note : The amount of outputted samples is by value of 'filter_length' \r
+// smaller than the amount of input samples.\r
+uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) \r
+{\r
+    assert(length > 0);\r
+    assert(lengthDiv8 * 8 == length);\r
+\r
+    if (numSamples < length) return 0;\r
+\r
+#ifndef USE_MULTICH_ALWAYS\r
+    if (numChannels == 1)\r
+    {\r
+        return evaluateFilterMono(dest, src, numSamples);\r
+    } \r
+    else if (numChannels == 2)\r
+    {\r
+        return evaluateFilterStereo(dest, src, numSamples);\r
+    }\r
+    else\r
+#endif // USE_MULTICH_ALWAYS\r
+    {\r
+        assert(numChannels > 0);\r
+        return evaluateFilterMulti(dest, src, numSamples, numChannels);\r
+    }\r
+}\r
+\r
+\r
+// Operator 'new' is overloaded so that it automatically creates a suitable instance \r
+// depending on if we've a MMX-capable CPU available or not.\r
+void * FIRFilter::operator new(size_t s)\r
+{\r
+    // Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!\r
+    ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");\r
+    return newInstance();\r
+}\r
+\r
+\r
+FIRFilter * FIRFilter::newInstance()\r
+{\r
+    uint uExtensions;\r
+\r
+    uExtensions = detectCPUextensions();\r
+\r
+    // Check if MMX/SSE instruction set extensions supported by CPU\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_MMX\r
+    // MMX routines available only with integer sample types\r
+    if (uExtensions & SUPPORT_MMX)\r
+    {\r
+        return ::new FIRFilterMMX;\r
+    }\r
+    else\r
+#endif // SOUNDTOUCH_ALLOW_MMX\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_SSE\r
+    if (uExtensions & SUPPORT_SSE)\r
+    {\r
+        // SSE support\r
+        return ::new FIRFilterSSE;\r
+    }\r
+    else\r
+#endif // SOUNDTOUCH_ALLOW_SSE\r
+\r
+    {\r
+        // ISA optimizations not supported, use plain C version\r
+        return ::new FIRFilter;\r
+    }\r
+}\r
diff --git a/source/SoundTouch/FIRFilter.h b/source/SoundTouch/FIRFilter.h
new file mode 100644 (file)
index 0000000..297b0f8
--- /dev/null
@@ -0,0 +1,139 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// General FIR digital filter routines with MMX optimization. \r
+///\r
+/// Note : MMX optimized functions reside in a separate, platform-specific file, \r
+/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef FIRFilter_H\r
+#define FIRFilter_H\r
+\r
+#include <stddef.h>\r
+#include "STTypes.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+class FIRFilter \r
+{\r
+protected:\r
+    // Number of FIR filter taps\r
+    uint length;    \r
+    // Number of FIR filter taps divided by 8\r
+    uint lengthDiv8;\r
+\r
+    // Result divider factor in 2^k format\r
+    uint resultDivFactor;\r
+\r
+    // Result divider value.\r
+    SAMPLETYPE resultDivider;\r
+\r
+    // Memory for filter coefficients\r
+    SAMPLETYPE *filterCoeffs;\r
+\r
+    virtual uint evaluateFilterStereo(SAMPLETYPE *dest, \r
+                                      const SAMPLETYPE *src, \r
+                                      uint numSamples) const;\r
+    virtual uint evaluateFilterMono(SAMPLETYPE *dest, \r
+                                    const SAMPLETYPE *src, \r
+                                    uint numSamples) const;\r
+    virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels);\r
+\r
+public:\r
+    FIRFilter();\r
+    virtual ~FIRFilter();\r
+\r
+    /// Operator 'new' is overloaded so that it automatically creates a suitable instance \r
+    /// depending on if we've a MMX-capable CPU available or not.\r
+    static void * operator new(size_t s);\r
+\r
+    static FIRFilter *newInstance();\r
+\r
+    /// Applies the filter to the given sequence of samples. \r
+    /// Note : The amount of outputted samples is by value of 'filter_length' \r
+    /// smaller than the amount of input samples.\r
+    ///\r
+    /// \return Number of samples copied to 'dest'.\r
+    uint evaluate(SAMPLETYPE *dest, \r
+                  const SAMPLETYPE *src, \r
+                  uint numSamples, \r
+                  uint numChannels);\r
+\r
+    uint getLength() const;\r
+\r
+    virtual void setCoefficients(const SAMPLETYPE *coeffs, \r
+                                 uint newLength, \r
+                                 uint uResultDivFactor);\r
+};\r
+\r
+\r
+// Optional subclasses that implement CPU-specific optimizations:\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_MMX\r
+\r
+/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.\r
+    class FIRFilterMMX : public FIRFilter\r
+    {\r
+    protected:\r
+        short *filterCoeffsUnalign;\r
+        short *filterCoeffsAlign;\r
+\r
+        virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const;\r
+    public:\r
+        FIRFilterMMX();\r
+        ~FIRFilterMMX();\r
+\r
+        virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor);\r
+    };\r
+\r
+#endif // SOUNDTOUCH_ALLOW_MMX\r
+\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_SSE\r
+    /// Class that implements SSE optimized functions exclusive for floating point samples type.\r
+    class FIRFilterSSE : public FIRFilter\r
+    {\r
+    protected:\r
+        float *filterCoeffsUnalign;\r
+        float *filterCoeffsAlign;\r
+\r
+        virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;\r
+    public:\r
+        FIRFilterSSE();\r
+        ~FIRFilterSSE();\r
+\r
+        virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);\r
+    };\r
+\r
+#endif // SOUNDTOUCH_ALLOW_SSE\r
+\r
+}\r
+\r
+#endif  // FIRFilter_H\r
diff --git a/source/SoundTouch/InterpolateCubic.cpp b/source/SoundTouch/InterpolateCubic.cpp
new file mode 100644 (file)
index 0000000..fe49684
--- /dev/null
@@ -0,0 +1,196 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Cubic interpolation routine.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <stddef.h>\r
+#include <math.h>\r
+#include "InterpolateCubic.h"\r
+#include "STTypes.h"\r
+\r
+using namespace soundtouch;\r
+\r
+// cubic interpolation coefficients\r
+static const float _coeffs[]= \r
+{ -0.5f,  1.0f, -0.5f, 0.0f,\r
+   1.5f, -2.5f,  0.0f, 1.0f,\r
+  -1.5f,  2.0f,  0.5f, 0.0f,\r
+   0.5f, -0.5f,  0.0f, 0.0f};\r
+\r
+\r
+InterpolateCubic::InterpolateCubic()\r
+{\r
+    fract = 0;\r
+}\r
+\r
+\r
+void InterpolateCubic::resetRegisters()\r
+{\r
+    fract = 0;\r
+}\r
+\r
+\r
+/// Transpose mono audio. Returns number of produced output samples, and \r
+/// updates "srcSamples" to amount of consumed source samples\r
+int InterpolateCubic::transposeMono(SAMPLETYPE *pdest, \r
+                    const SAMPLETYPE *psrc, \r
+                    int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 4;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        float out;\r
+        const float x3 = 1.0f;\r
+        const float x2 = (float)fract;    // x\r
+        const float x1 = x2*x2;           // x^2\r
+        const float x0 = x1*x2;           // x^3\r
+        float y0, y1, y2, y3;\r
+\r
+        assert(fract < 1.0);\r
+\r
+        y0 =  _coeffs[0] * x0 +  _coeffs[1] * x1 +  _coeffs[2] * x2 +  _coeffs[3] * x3;\r
+        y1 =  _coeffs[4] * x0 +  _coeffs[5] * x1 +  _coeffs[6] * x2 +  _coeffs[7] * x3;\r
+        y2 =  _coeffs[8] * x0 +  _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;\r
+        y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;\r
+\r
+        out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3];\r
+\r
+        pdest[i] = (SAMPLETYPE)out;\r
+        i ++;\r
+\r
+        // update position fraction\r
+        fract += rate;\r
+        // update whole positions\r
+        int whole = (int)fract;\r
+        fract -= whole;\r
+        psrc += whole;\r
+        srcCount += whole;\r
+    }\r
+    srcSamples = srcCount;\r
+    return i;\r
+}\r
+\r
+\r
+/// Transpose stereo audio. Returns number of produced output samples, and \r
+/// updates "srcSamples" to amount of consumed source samples\r
+int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest, \r
+                    const SAMPLETYPE *psrc, \r
+                    int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 4;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        const float x3 = 1.0f;\r
+        const float x2 = (float)fract;    // x\r
+        const float x1 = x2*x2;           // x^2\r
+        const float x0 = x1*x2;           // x^3\r
+        float y0, y1, y2, y3;\r
+        float out0, out1;\r
+\r
+        assert(fract < 1.0);\r
+\r
+        y0 =  _coeffs[0] * x0 +  _coeffs[1] * x1 +  _coeffs[2] * x2 +  _coeffs[3] * x3;\r
+        y1 =  _coeffs[4] * x0 +  _coeffs[5] * x1 +  _coeffs[6] * x2 +  _coeffs[7] * x3;\r
+        y2 =  _coeffs[8] * x0 +  _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;\r
+        y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;\r
+\r
+        out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6];\r
+        out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7];\r
+\r
+        pdest[2*i]   = (SAMPLETYPE)out0;\r
+        pdest[2*i+1] = (SAMPLETYPE)out1;\r
+        i ++;\r
+\r
+        // update position fraction\r
+        fract += rate;\r
+        // update whole positions\r
+        int whole = (int)fract;\r
+        fract -= whole;\r
+        psrc += 2*whole;\r
+        srcCount += whole;\r
+    }\r
+    srcSamples = srcCount;\r
+    return i;\r
+}\r
+\r
+\r
+/// Transpose multi-channel audio. Returns number of produced output samples, and \r
+/// updates "srcSamples" to amount of consumed source samples\r
+int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest, \r
+                    const SAMPLETYPE *psrc, \r
+                    int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 4;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        const float x3 = 1.0f;\r
+        const float x2 = (float)fract;    // x\r
+        const float x1 = x2*x2;           // x^2\r
+        const float x0 = x1*x2;           // x^3\r
+        float y0, y1, y2, y3;\r
+\r
+        assert(fract < 1.0);\r
+\r
+        y0 =  _coeffs[0] * x0 +  _coeffs[1] * x1 +  _coeffs[2] * x2 +  _coeffs[3] * x3;\r
+        y1 =  _coeffs[4] * x0 +  _coeffs[5] * x1 +  _coeffs[6] * x2 +  _coeffs[7] * x3;\r
+        y2 =  _coeffs[8] * x0 +  _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;\r
+        y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;\r
+\r
+        for (int c = 0; c < numChannels; c ++)\r
+        {\r
+            float out;\r
+            out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels];\r
+            pdest[0] = (SAMPLETYPE)out;\r
+            pdest ++;\r
+        }\r
+        i ++;\r
+\r
+        // update position fraction\r
+        fract += rate;\r
+        // update whole positions\r
+        int whole = (int)fract;\r
+        fract -= whole;\r
+        psrc += numChannels*whole;\r
+        srcCount += whole;\r
+    }\r
+    srcSamples = srcCount;\r
+    return i;\r
+}\r
diff --git a/source/SoundTouch/InterpolateCubic.h b/source/SoundTouch/InterpolateCubic.h
new file mode 100644 (file)
index 0000000..4578210
--- /dev/null
@@ -0,0 +1,63 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Cubic interpolation routine.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _InterpolateCubic_H_\r
+#define _InterpolateCubic_H_\r
+\r
+#include "RateTransposer.h"\r
+#include "STTypes.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+class InterpolateCubic : public TransposerBase\r
+{\r
+protected:\r
+    virtual void resetRegisters();\r
+    virtual int transposeMono(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples);\r
+    virtual int transposeStereo(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples);\r
+    virtual int transposeMulti(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples);\r
+\r
+    double fract;\r
+\r
+public:\r
+    InterpolateCubic();\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/source/SoundTouch/InterpolateLinear.cpp b/source/SoundTouch/InterpolateLinear.cpp
new file mode 100644 (file)
index 0000000..c3aa199
--- /dev/null
@@ -0,0 +1,296 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Linear interpolation algorithm.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <assert.h>\r
+#include <stdlib.h>\r
+#include "InterpolateLinear.h"\r
+\r
+using namespace soundtouch;\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// InterpolateLinearInteger - integer arithmetic implementation\r
+// \r
+\r
+/// fixed-point interpolation routine precision\r
+#define SCALE    65536\r
+\r
+\r
+// Constructor\r
+InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase()\r
+{\r
+    // Notice: use local function calling syntax for sake of clarity, \r
+    // to indicate the fact that C++ constructor can't call virtual functions.\r
+    resetRegisters();\r
+    setRate(1.0f);\r
+}\r
+\r
+\r
+void InterpolateLinearInteger::resetRegisters()\r
+{\r
+    iFract = 0;\r
+}\r
+\r
+\r
+// Transposes the sample rate of the given samples using linear interpolation. \r
+// 'Mono' version of the routine. Returns the number of samples returned in \r
+// the "dest" buffer\r
+int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 1;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        LONG_SAMPLETYPE temp;\r
+    \r
+        assert(iFract < SCALE);\r
+\r
+        temp = (SCALE - iFract) * src[0] + iFract * src[1];\r
+        dest[i] = (SAMPLETYPE)(temp / SCALE);\r
+        i++;\r
+\r
+        iFract += iRate;\r
+\r
+        int iWhole = iFract / SCALE;\r
+        iFract -= iWhole * SCALE;\r
+        srcCount += iWhole;\r
+        src += iWhole;\r
+    }\r
+    srcSamples = srcCount;\r
+\r
+    return i;\r
+}\r
+\r
+\r
+// Transposes the sample rate of the given samples using linear interpolation. \r
+// 'Stereo' version of the routine. Returns the number of samples returned in \r
+// the "dest" buffer\r
+int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 1;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        LONG_SAMPLETYPE temp0;\r
+        LONG_SAMPLETYPE temp1;\r
+    \r
+        assert(iFract < SCALE);\r
+\r
+        temp0 = (SCALE - iFract) * src[0] + iFract * src[2];\r
+        temp1 = (SCALE - iFract) * src[1] + iFract * src[3];\r
+        dest[0] = (SAMPLETYPE)(temp0 / SCALE);\r
+        dest[1] = (SAMPLETYPE)(temp1 / SCALE);\r
+        dest += 2;\r
+        i++;\r
+\r
+        iFract += iRate;\r
+\r
+        int iWhole = iFract / SCALE;\r
+        iFract -= iWhole * SCALE;\r
+        srcCount += iWhole;\r
+        src += 2*iWhole;\r
+    }\r
+    srcSamples = srcCount;\r
+\r
+    return i;\r
+}\r
+\r
+\r
+int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 1;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        LONG_SAMPLETYPE temp, vol1;\r
+    \r
+        assert(iFract < SCALE);\r
+        vol1 = (SCALE - iFract);\r
+        for (int c = 0; c < numChannels; c ++)\r
+        {\r
+            temp = vol1 * src[c] + iFract * src[c + numChannels];\r
+            dest[0] = (SAMPLETYPE)(temp / SCALE);\r
+            dest ++;\r
+        }\r
+        i++;\r
+\r
+        iFract += iRate;\r
+\r
+        int iWhole = iFract / SCALE;\r
+        iFract -= iWhole * SCALE;\r
+        srcCount += iWhole;\r
+        src += iWhole * numChannels;\r
+    }\r
+    srcSamples = srcCount;\r
+\r
+    return i;\r
+}\r
+\r
+\r
+// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower \r
+// iRate, larger faster iRates.\r
+void InterpolateLinearInteger::setRate(double newRate)\r
+{\r
+    iRate = (int)(newRate * SCALE + 0.5);\r
+    TransposerBase::setRate(newRate);\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// InterpolateLinearFloat - floating point arithmetic implementation\r
+// \r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+// Constructor\r
+InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase()\r
+{\r
+    // Notice: use local function calling syntax for sake of clarity, \r
+    // to indicate the fact that C++ constructor can't call virtual functions.\r
+    resetRegisters();\r
+    setRate(1.0);\r
+}\r
+\r
+\r
+void InterpolateLinearFloat::resetRegisters()\r
+{\r
+    fract = 0;\r
+}\r
+\r
+\r
+// Transposes the sample rate of the given samples using linear interpolation. \r
+// 'Mono' version of the routine. Returns the number of samples returned in \r
+// the "dest" buffer\r
+int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 1;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        double out;\r
+        assert(fract < 1.0);\r
+\r
+        out = (1.0 - fract) * src[0] + fract * src[1];\r
+        dest[i] = (SAMPLETYPE)out;\r
+        i ++;\r
+\r
+        // update position fraction\r
+        fract += rate;\r
+        // update whole positions\r
+        int whole = (int)fract;\r
+        fract -= whole;\r
+        src += whole;\r
+        srcCount += whole;\r
+    }\r
+    srcSamples = srcCount;\r
+    return i;\r
+}\r
+\r
+\r
+// Transposes the sample rate of the given samples using linear interpolation. \r
+// 'Mono' version of the routine. Returns the number of samples returned in \r
+// the "dest" buffer\r
+int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 1;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        double out0, out1;\r
+        assert(fract < 1.0);\r
+\r
+        out0 = (1.0 - fract) * src[0] + fract * src[2];\r
+        out1 = (1.0 - fract) * src[1] + fract * src[3];\r
+        dest[2*i]   = (SAMPLETYPE)out0;\r
+        dest[2*i+1] = (SAMPLETYPE)out1;\r
+        i ++;\r
+\r
+        // update position fraction\r
+        fract += rate;\r
+        // update whole positions\r
+        int whole = (int)fract;\r
+        fract -= whole;\r
+        src += 2*whole;\r
+        srcCount += whole;\r
+    }\r
+    srcSamples = srcCount;\r
+    return i;\r
+}\r
+\r
+\r
+int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 1;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        float temp, vol1, fract_float;\r
+    \r
+        vol1 = (float)(1.0 - fract);\r
+               fract_float = (float)fract;\r
+        for (int c = 0; c < numChannels; c ++)\r
+        {\r
+                       temp = vol1 * src[c] + fract_float * src[c + numChannels];\r
+            *dest = (SAMPLETYPE)temp;\r
+            dest ++;\r
+        }\r
+        i++;\r
+\r
+        fract += rate;\r
+\r
+        int iWhole = (int)fract;\r
+        fract -= iWhole;\r
+        srcCount += iWhole;\r
+        src += iWhole * numChannels;\r
+    }\r
+    srcSamples = srcCount;\r
+\r
+    return i;\r
+}\r
diff --git a/source/SoundTouch/InterpolateLinear.h b/source/SoundTouch/InterpolateLinear.h
new file mode 100644 (file)
index 0000000..faa2e2c
--- /dev/null
@@ -0,0 +1,88 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Linear interpolation routine.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _InterpolateLinear_H_\r
+#define _InterpolateLinear_H_\r
+\r
+#include "RateTransposer.h"\r
+#include "STTypes.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+/// Linear transposer class that uses integer arithmetic\r
+class InterpolateLinearInteger : public TransposerBase\r
+{\r
+protected:\r
+    int iFract;\r
+    int iRate;\r
+\r
+    virtual void resetRegisters();\r
+\r
+    virtual int transposeMono(SAMPLETYPE *dest, \r
+                       const SAMPLETYPE *src, \r
+                       int &srcSamples);\r
+    virtual int transposeStereo(SAMPLETYPE *dest, \r
+                         const SAMPLETYPE *src, \r
+                         int &srcSamples);\r
+    virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);\r
+public:\r
+    InterpolateLinearInteger();\r
+\r
+    /// Sets new target rate. Normal rate = 1.0, smaller values represent slower \r
+    /// rate, larger faster rates.\r
+    virtual void setRate(double newRate);\r
+};\r
+\r
+\r
+/// Linear transposer class that uses floating point arithmetic\r
+class InterpolateLinearFloat : public TransposerBase\r
+{\r
+protected:\r
+    double fract;\r
+\r
+    virtual void resetRegisters();\r
+\r
+    virtual int transposeMono(SAMPLETYPE *dest, \r
+                       const SAMPLETYPE *src, \r
+                       int &srcSamples);\r
+    virtual int transposeStereo(SAMPLETYPE *dest, \r
+                         const SAMPLETYPE *src, \r
+                         int &srcSamples);\r
+    virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);\r
+\r
+public:\r
+    InterpolateLinearFloat();\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/source/SoundTouch/InterpolateShannon.cpp b/source/SoundTouch/InterpolateShannon.cpp
new file mode 100644 (file)
index 0000000..1d69a2e
--- /dev/null
@@ -0,0 +1,181 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Sample interpolation routine using 8-tap band-limited Shannon interpolation \r
+/// with kaiser window.\r
+///\r
+/// Notice. This algorithm is remarkably much heavier than linear or cubic\r
+/// interpolation, and not remarkably better than cubic algorithm. Thus mostly\r
+/// for experimental purposes\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <math.h>\r
+#include "InterpolateShannon.h"\r
+#include "STTypes.h"\r
+\r
+using namespace soundtouch;\r
+\r
+\r
+/// Kaiser window with beta = 2.0\r
+/// Values scaled down by 5% to avoid overflows\r
+static const double _kaiser8[8] = \r
+{\r
+   0.41778693317814,\r
+   0.64888025049173,\r
+   0.83508562409944,\r
+   0.93887857733412,\r
+   0.93887857733412,\r
+   0.83508562409944,\r
+   0.64888025049173,\r
+   0.41778693317814\r
+};\r
+\r
+\r
+InterpolateShannon::InterpolateShannon()\r
+{\r
+    fract = 0;\r
+}\r
+\r
+\r
+void InterpolateShannon::resetRegisters()\r
+{\r
+    fract = 0;\r
+}\r
+\r
+\r
+#define PI 3.1415926536\r
+#define sinc(x) (sin(PI * (x)) / (PI * (x)))\r
+\r
+/// Transpose mono audio. Returns number of produced output samples, and \r
+/// updates "srcSamples" to amount of consumed source samples\r
+int InterpolateShannon::transposeMono(SAMPLETYPE *pdest, \r
+                    const SAMPLETYPE *psrc, \r
+                    int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 8;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        double out;\r
+        assert(fract < 1.0);\r
+\r
+        out  = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0];\r
+        out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1];\r
+        out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2];\r
+        if (fract < 1e-6)\r
+        {\r
+            out += psrc[3] * _kaiser8[3];     // sinc(0) = 1\r
+        }\r
+        else\r
+        {\r
+            out += psrc[3] * sinc(- fract) * _kaiser8[3];\r
+        }\r
+        out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4];\r
+        out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5];\r
+        out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6];\r
+        out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7];\r
+\r
+        pdest[i] = (SAMPLETYPE)out;\r
+        i ++;\r
+\r
+        // update position fraction\r
+        fract += rate;\r
+        // update whole positions\r
+        int whole = (int)fract;\r
+        fract -= whole;\r
+        psrc += whole;\r
+        srcCount += whole;\r
+    }\r
+    srcSamples = srcCount;\r
+    return i;\r
+}\r
+\r
+\r
+/// Transpose stereo audio. Returns number of produced output samples, and \r
+/// updates "srcSamples" to amount of consumed source samples\r
+int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest, \r
+                    const SAMPLETYPE *psrc, \r
+                    int &srcSamples)\r
+{\r
+    int i;\r
+    int srcSampleEnd = srcSamples - 8;\r
+    int srcCount = 0;\r
+\r
+    i = 0;\r
+    while (srcCount < srcSampleEnd)\r
+    {\r
+        double out0, out1, w;\r
+        assert(fract < 1.0);\r
+\r
+        w = sinc(-3.0 - fract) * _kaiser8[0];\r
+        out0 = psrc[0] * w; out1 = psrc[1] * w;\r
+        w = sinc(-2.0 - fract) * _kaiser8[1];\r
+        out0 += psrc[2] * w; out1 += psrc[3] * w;\r
+        w = sinc(-1.0 - fract) * _kaiser8[2];\r
+        out0 += psrc[4] * w; out1 += psrc[5] * w;\r
+        w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract));   // sinc(0) = 1\r
+        out0 += psrc[6] * w; out1 += psrc[7] * w;\r
+        w = sinc( 1.0 - fract) * _kaiser8[4];\r
+        out0 += psrc[8] * w; out1 += psrc[9] * w;\r
+        w = sinc( 2.0 - fract) * _kaiser8[5];\r
+        out0 += psrc[10] * w; out1 += psrc[11] * w;\r
+        w = sinc( 3.0 - fract) * _kaiser8[6];\r
+        out0 += psrc[12] * w; out1 += psrc[13] * w;\r
+        w = sinc( 4.0 - fract) * _kaiser8[7];\r
+        out0 += psrc[14] * w; out1 += psrc[15] * w;\r
+\r
+        pdest[2*i]   = (SAMPLETYPE)out0;\r
+        pdest[2*i+1] = (SAMPLETYPE)out1;\r
+        i ++;\r
+\r
+        // update position fraction\r
+        fract += rate;\r
+        // update whole positions\r
+        int whole = (int)fract;\r
+        fract -= whole;\r
+        psrc += 2*whole;\r
+        srcCount += whole;\r
+    }\r
+    srcSamples = srcCount;\r
+    return i;\r
+}\r
+\r
+\r
+/// Transpose stereo audio. Returns number of produced output samples, and \r
+/// updates "srcSamples" to amount of consumed source samples\r
+int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, \r
+                    const SAMPLETYPE *psrc, \r
+                    int &srcSamples)\r
+{\r
+    // not implemented\r
+    assert(false);\r
+    return 0;\r
+}\r
diff --git a/source/SoundTouch/InterpolateShannon.h b/source/SoundTouch/InterpolateShannon.h
new file mode 100644 (file)
index 0000000..c621cf1
--- /dev/null
@@ -0,0 +1,68 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Sample interpolation routine using 8-tap band-limited Shannon interpolation \r
+/// with kaiser window.\r
+///\r
+/// Notice. This algorithm is remarkably much heavier than linear or cubic\r
+/// interpolation, and not remarkably better than cubic algorithm. Thus mostly\r
+/// for experimental purposes\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _InterpolateShannon_H_\r
+#define _InterpolateShannon_H_\r
+\r
+#include "RateTransposer.h"\r
+#include "STTypes.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+class InterpolateShannon : public TransposerBase\r
+{\r
+protected:\r
+    void resetRegisters();\r
+    int transposeMono(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples);\r
+    int transposeStereo(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples);\r
+    int transposeMulti(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples);\r
+\r
+    double fract;\r
+\r
+public:\r
+    InterpolateShannon();\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/source/SoundTouch/Makefile.am b/source/SoundTouch/Makefile.am
new file mode 100644 (file)
index 0000000..54e330a
--- /dev/null
@@ -0,0 +1,74 @@
+## Process this file with automake to create Makefile.in\r
+##\r
+## This file is part of SoundTouch, an audio processing library for pitch/time adjustments\r
+## \r
+## SoundTouch is free software; you can redistribute it and/or modify it under the\r
+## terms of the GNU General Public License as published by the Free Software\r
+## Foundation; either version 2 of the License, or (at your option) any later\r
+## version.\r
+## \r
+## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY\r
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR\r
+## A PARTICULAR PURPOSE.  See the GNU General Public License for more details.\r
+## \r
+## You should have received a copy of the GNU General Public License along with\r
+## this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
+## Place - Suite 330, Boston, MA  02111-1307, USA\r
+\r
+\r
+include $(top_srcdir)/config/am_include.mk\r
+\r
+\r
+# set to something if you want other stuff to be included in the distribution tarball\r
+EXTRA_DIST=SoundTouch.sln SoundTouch.vcxproj\r
+\r
+noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h \\r
+    InterpolateCubic.h InterpolateLinear.h InterpolateShannon.h\r
+\r
+lib_LTLIBRARIES=libSoundTouch.la\r
+#\r
+libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp    \\r
+    RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp      \\r
+    BPMDetect.cpp PeakFinder.cpp InterpolateLinear.cpp InterpolateCubic.cpp \\r
+    InterpolateShannon.cpp\r
+\r
+# Compiler flags\r
+AM_CXXFLAGS+=-O3\r
+\r
+# Compile the files that need MMX and SSE individually.\r
+libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la\r
+noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la\r
+libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp\r
+libSoundTouchSSE_la_SOURCES=sse_optimized.cpp\r
+\r
+# We enable optimizations by default.\r
+# If MMX is supported compile with -mmmx.\r
+# Do not assume -msse is also supported.\r
+if HAVE_MMX\r
+libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS)\r
+else\r
+libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)\r
+endif\r
+\r
+# We enable optimizations by default.\r
+# If SSE is supported compile with -msse.\r
+if HAVE_SSE\r
+libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS)\r
+else\r
+libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)\r
+endif\r
+\r
+# Let the user disable optimizations if he wishes to.\r
+if !X86_OPTIMIZATIONS\r
+libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)\r
+libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)\r
+endif\r
+\r
+# Modify the default 0.0.0 to LIB_SONAME.0.0\r
+libSoundTouch_la_LDFLAGS=-version-info @LIB_SONAME@\r
+\r
+# other linking flags to add\r
+# noinst_LTLIBRARIES = libSoundTouchOpt.la\r
+# libSoundTouch_la_LIBADD = libSoundTouchOpt.la\r
+# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp \r
+# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include\r
diff --git a/source/SoundTouch/PeakFinder.cpp b/source/SoundTouch/PeakFinder.cpp
new file mode 100644 (file)
index 0000000..258571a
--- /dev/null
@@ -0,0 +1,277 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Peak detection routine. \r
+///\r
+/// The routine detects highest value on an array of values and calculates the \r
+/// precise peak location as a mass-center of the 'hump' around the peak value.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <math.h>\r
+#include <assert.h>\r
+\r
+#include "PeakFinder.h"\r
+\r
+using namespace soundtouch;\r
+\r
+#define max(x, y) (((x) > (y)) ? (x) : (y))\r
+\r
+\r
+PeakFinder::PeakFinder()\r
+{\r
+    minPos = maxPos = 0;\r
+}\r
+\r
+\r
+// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.\r
+int PeakFinder::findTop(const float *data, int peakpos) const\r
+{\r
+    int i;\r
+    int start, end;\r
+    float refvalue;\r
+\r
+    refvalue = data[peakpos];\r
+\r
+    // seek within �10 points\r
+    start = peakpos - 10;\r
+    if (start < minPos) start = minPos;\r
+    end = peakpos + 10;\r
+    if (end > maxPos) end = maxPos;\r
+\r
+    for (i = start; i <= end; i ++)\r
+    {\r
+        if (data[i] > refvalue)\r
+        {\r
+            peakpos = i;\r
+            refvalue = data[i];\r
+        }\r
+    }\r
+\r
+    // failure if max value is at edges of seek range => it's not peak, it's at slope.\r
+    if ((peakpos == start) || (peakpos == end)) return 0;\r
+\r
+    return peakpos;\r
+}\r
+\r
+\r
+// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding\r
+// to direction defined by 'direction' until next 'hump' after minimum value will \r
+// begin\r
+int PeakFinder::findGround(const float *data, int peakpos, int direction) const\r
+{\r
+    int lowpos;\r
+    int pos;\r
+    int climb_count;\r
+    float refvalue;\r
+    float delta;\r
+\r
+    climb_count = 0;\r
+    refvalue = data[peakpos];\r
+    lowpos = peakpos;\r
+\r
+    pos = peakpos;\r
+\r
+    while ((pos > minPos+1) && (pos < maxPos-1))\r
+    {\r
+        int prevpos;\r
+\r
+        prevpos = pos;\r
+        pos += direction;\r
+\r
+        // calculate derivate\r
+        delta = data[pos] - data[prevpos];\r
+        if (delta <= 0)\r
+        {\r
+            // going downhill, ok\r
+            if (climb_count)\r
+            {\r
+                climb_count --;  // decrease climb count\r
+            }\r
+\r
+            // check if new minimum found\r
+            if (data[pos] < refvalue)\r
+            {\r
+                // new minimum found\r
+                lowpos = pos;\r
+                refvalue = data[pos];\r
+            }\r
+        }\r
+        else\r
+        {\r
+            // going uphill, increase climbing counter\r
+            climb_count ++;\r
+            if (climb_count > 5) break;    // we've been climbing too long => it's next uphill => quit\r
+        }\r
+    }\r
+    return lowpos;\r
+}\r
+\r
+\r
+// Find offset where the value crosses the given level, when starting from 'peakpos' and\r
+// proceeds to direction defined in 'direction'\r
+int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const\r
+{\r
+    float peaklevel;\r
+    int pos;\r
+\r
+    peaklevel = data[peakpos];\r
+    assert(peaklevel >= level);\r
+    pos = peakpos;\r
+    while ((pos >= minPos) && (pos < maxPos))\r
+    {\r
+        if (data[pos + direction] < level) return pos;   // crossing found\r
+        pos += direction;\r
+    }\r
+    return -1;  // not found\r
+}\r
+\r
+\r
+// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos'\r
+double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const\r
+{\r
+    int i;\r
+    float sum;\r
+    float wsum;\r
+\r
+    sum = 0;\r
+    wsum = 0;\r
+    for (i = firstPos; i <= lastPos; i ++)\r
+    {\r
+        sum += (float)i * data[i];\r
+        wsum += data[i];\r
+    }\r
+\r
+    if (wsum < 1e-6) return 0;\r
+    return sum / wsum;\r
+}\r
+\r
+\r
+/// get exact center of peak near given position by calculating local mass of center\r
+double PeakFinder::getPeakCenter(const float *data, int peakpos) const\r
+{\r
+    float peakLevel;            // peak level\r
+    int crosspos1, crosspos2;   // position where the peak 'hump' crosses cutting level\r
+    float cutLevel;             // cutting value\r
+    float groundLevel;          // ground level of the peak\r
+    int gp1, gp2;               // bottom positions of the peak 'hump'\r
+\r
+    // find ground positions.\r
+    gp1 = findGround(data, peakpos, -1);\r
+    gp2 = findGround(data, peakpos, 1);\r
+\r
+    peakLevel = data[peakpos];\r
+\r
+    if (gp1 == gp2) \r
+    {\r
+        // avoid rounding errors when all are equal\r
+        assert(gp1 == peakpos);\r
+        cutLevel = groundLevel = peakLevel;\r
+    } else {\r
+        // get average of the ground levels\r
+        groundLevel = 0.5f * (data[gp1] + data[gp2]);\r
+\r
+        // calculate 70%-level of the peak\r
+        cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;\r
+    }\r
+\r
+    // find mid-level crossings\r
+    crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);\r
+    crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);\r
+\r
+    if ((crosspos1 < 0) || (crosspos2 < 0)) return 0;   // no crossing, no peak..\r
+\r
+    // calculate mass center of the peak surroundings\r
+    return calcMassCenter(data, crosspos1, crosspos2);\r
+}\r
+\r
+\r
+double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos) \r
+{\r
+\r
+    int i;\r
+    int peakpos;                // position of peak level\r
+    double highPeak, peak;\r
+\r
+    this->minPos = aminPos;\r
+    this->maxPos = amaxPos;\r
+\r
+    // find absolute peak\r
+    peakpos = minPos;\r
+    peak = data[minPos];\r
+    for (i = minPos + 1; i < maxPos; i ++)\r
+    {\r
+        if (data[i] > peak) \r
+        {\r
+            peak = data[i];\r
+            peakpos = i;\r
+        }\r
+    }\r
+    \r
+    // Calculate exact location of the highest peak mass center\r
+    highPeak = getPeakCenter(data, peakpos);\r
+    peak = highPeak;\r
+\r
+    // Now check if the highest peak were in fact harmonic of the true base beat peak \r
+    // - sometimes the highest peak can be Nth harmonic of the true base peak yet \r
+    // just a slightly higher than the true base\r
+\r
+    for (i = 1; i < 3; i ++)\r
+    {\r
+        double peaktmp, harmonic;\r
+        int i1,i2;\r
+\r
+        harmonic = (double)pow(2.0, i);\r
+        peakpos = (int)(highPeak / harmonic + 0.5f);\r
+        if (peakpos < minPos) break;\r
+        peakpos = findTop(data, peakpos);   // seek true local maximum index\r
+        if (peakpos == 0) continue;         // no local max here\r
+\r
+        // calculate mass-center of possible harmonic peak\r
+        peaktmp = getPeakCenter(data, peakpos);\r
+\r
+        // accept harmonic peak if \r
+        // (a) it is found\r
+        // (b) is within �4% of the expected harmonic interval\r
+        // (c) has at least half x-corr value of the max. peak\r
+\r
+        double diff = harmonic * peaktmp / highPeak;\r
+        if ((diff < 0.96) || (diff > 1.04)) continue;   // peak too afar from expected\r
+\r
+        // now compare to highest detected peak\r
+        i1 = (int)(highPeak + 0.5);\r
+        i2 = (int)(peaktmp + 0.5);\r
+        if (data[i2] >= 0.4*data[i1])\r
+        {\r
+            // The harmonic is at least half as high primary peak,\r
+            // thus use the harmonic peak instead\r
+            peak = peaktmp;\r
+        }\r
+    }\r
+\r
+    return peak;\r
+}\r
diff --git a/source/SoundTouch/PeakFinder.h b/source/SoundTouch/PeakFinder.h
new file mode 100644 (file)
index 0000000..9fe66ad
--- /dev/null
@@ -0,0 +1,90 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// The routine detects highest value on an array of values and calculates the \r
+/// precise peak location as a mass-center of the 'hump' around the peak value.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _PeakFinder_H_\r
+#define _PeakFinder_H_\r
+\r
+namespace soundtouch\r
+{\r
+\r
+class PeakFinder\r
+{\r
+protected:\r
+    /// Min, max allowed peak positions within the data vector\r
+    int minPos, maxPos;\r
+\r
+    /// Calculates the mass center between given vector items.\r
+    double calcMassCenter(const float *data, ///< Data vector.\r
+                         int firstPos,      ///< Index of first vector item belonging to the peak.\r
+                         int lastPos        ///< Index of last vector item belonging to the peak.\r
+                         ) const;\r
+\r
+    /// Finds the data vector index where the monotoniously decreasing signal crosses the\r
+    /// given level.\r
+    int   findCrossingLevel(const float *data,  ///< Data vector.\r
+                            float level,        ///< Goal crossing level.\r
+                            int peakpos,        ///< Peak position index within the data vector.\r
+                            int direction       /// Direction where to proceed from the peak: 1 = right, -1 = left.\r
+                            ) const;\r
+\r
+    // Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.\r
+    int findTop(const float *data, int peakpos) const;\r
+\r
+\r
+    /// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right- \r
+    /// or left-hand side of the given peak position.\r
+    int   findGround(const float *data,     /// Data vector.\r
+                     int peakpos,           /// Peak position index within the data vector.\r
+                     int direction          /// Direction where to proceed from the peak: 1 = right, -1 = left.\r
+                     ) const;\r
+\r
+    /// get exact center of peak near given position by calculating local mass of center\r
+    double getPeakCenter(const float *data, int peakpos) const;\r
+\r
+public:\r
+    /// Constructor. \r
+    PeakFinder();\r
+\r
+    /// Detect exact peak position of the data vector by finding the largest peak 'hump'\r
+    /// and calculating the mass-center location of the peak hump.\r
+    ///\r
+    /// \return The location of the largest base harmonic peak hump.\r
+    double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has\r
+                                        /// to be at least 'maxPos' items long.\r
+                     int minPos,        ///< Min allowed peak location within the vector data.\r
+                     int maxPos         ///< Max allowed peak location within the vector data.\r
+                     );\r
+};\r
+\r
+}\r
+\r
+#endif // _PeakFinder_H_\r
diff --git a/source/SoundTouch/RateTransposer.cpp b/source/SoundTouch/RateTransposer.cpp
new file mode 100644 (file)
index 0000000..2efaf04
--- /dev/null
@@ -0,0 +1,307 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Sample rate transposer. Changes sample rate by using linear interpolation \r
+/// together with anti-alias filtering (first order interpolation with anti-\r
+/// alias filtering should be quite adequate for this application)\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <memory.h>\r
+#include <assert.h>\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include "RateTransposer.h"\r
+#include "InterpolateLinear.h"\r
+#include "InterpolateCubic.h"\r
+#include "InterpolateShannon.h"\r
+#include "AAFilter.h"\r
+\r
+using namespace soundtouch;\r
+\r
+// Define default interpolation algorithm here\r
+TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;\r
+\r
+\r
+// Constructor\r
+RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)\r
+{\r
+    bUseAAFilter = \r
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER\r
+        true;\r
+#else\r
+        // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover\r
+        false;\r
+#endif\r
+\r
+    // Instantiates the anti-alias filter\r
+    pAAFilter = new AAFilter(64);\r
+    pTransposer = TransposerBase::newInstance();\r
+}\r
+\r
+\r
+RateTransposer::~RateTransposer()\r
+{\r
+    delete pAAFilter;\r
+    delete pTransposer;\r
+}\r
+\r
+\r
+/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable\r
+void RateTransposer::enableAAFilter(bool newMode)\r
+{\r
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER\r
+    // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover\r
+    bUseAAFilter = newMode;\r
+#endif\r
+}\r
+\r
+\r
+/// Returns nonzero if anti-alias filter is enabled.\r
+bool RateTransposer::isAAFilterEnabled() const\r
+{\r
+    return bUseAAFilter;\r
+}\r
+\r
+\r
+AAFilter *RateTransposer::getAAFilter()\r
+{\r
+    return pAAFilter;\r
+}\r
+\r
+\r
+// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower \r
+// iRate, larger faster iRates.\r
+void RateTransposer::setRate(double newRate)\r
+{\r
+    double fCutoff;\r
+\r
+    pTransposer->setRate(newRate);\r
+\r
+    // design a new anti-alias filter\r
+    if (newRate > 1.0) \r
+    {\r
+        fCutoff = 0.5 / newRate;\r
+    } \r
+    else \r
+    {\r
+        fCutoff = 0.5 * newRate;\r
+    }\r
+    pAAFilter->setCutoffFreq(fCutoff);\r
+}\r
+\r
+\r
+// Adds 'nSamples' pcs of samples from the 'samples' memory position into\r
+// the input of the object.\r
+void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)\r
+{\r
+    processSamples(samples, nSamples);\r
+}\r
+\r
+\r
+// Transposes sample rate by applying anti-alias filter to prevent folding. \r
+// Returns amount of samples returned in the "dest" buffer.\r
+// The maximum amount of samples that can be returned at a time is set by\r
+// the 'set_returnBuffer_size' function.\r
+void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)\r
+{\r
+    uint count;\r
+\r
+    if (nSamples == 0) return;\r
+\r
+    // Store samples to input buffer\r
+    inputBuffer.putSamples(src, nSamples);\r
+\r
+    // If anti-alias filter is turned off, simply transpose without applying\r
+    // the filter\r
+    if (bUseAAFilter == false) \r
+    {\r
+        count = pTransposer->transpose(outputBuffer, inputBuffer);\r
+        return;\r
+    }\r
+\r
+    assert(pAAFilter);\r
+\r
+    // Transpose with anti-alias filter\r
+    if (pTransposer->rate < 1.0f) \r
+    {\r
+        // If the parameter 'Rate' value is smaller than 1, first transpose\r
+        // the samples and then apply the anti-alias filter to remove aliasing.\r
+\r
+        // Transpose the samples, store the result to end of "midBuffer"\r
+        pTransposer->transpose(midBuffer, inputBuffer);\r
+\r
+        // Apply the anti-alias filter for transposed samples in midBuffer\r
+        pAAFilter->evaluate(outputBuffer, midBuffer);\r
+    } \r
+    else  \r
+    {\r
+        // If the parameter 'Rate' value is larger than 1, first apply the\r
+        // anti-alias filter to remove high frequencies (prevent them from folding\r
+        // over the lover frequencies), then transpose.\r
+\r
+        // Apply the anti-alias filter for samples in inputBuffer\r
+        pAAFilter->evaluate(midBuffer, inputBuffer);\r
+\r
+        // Transpose the AA-filtered samples in "midBuffer"\r
+        pTransposer->transpose(outputBuffer, midBuffer);\r
+    }\r
+}\r
+\r
+\r
+// Sets the number of channels, 1 = mono, 2 = stereo\r
+void RateTransposer::setChannels(int nChannels)\r
+{\r
+    if (!verifyNumberOfChannels(nChannels) ||\r
+        (pTransposer->numChannels == nChannels)) return;\r
+\r
+    pTransposer->setChannels(nChannels);\r
+    inputBuffer.setChannels(nChannels);\r
+    midBuffer.setChannels(nChannels);\r
+    outputBuffer.setChannels(nChannels);\r
+}\r
+\r
+\r
+// Clears all the samples in the object\r
+void RateTransposer::clear()\r
+{\r
+    outputBuffer.clear();\r
+    midBuffer.clear();\r
+    inputBuffer.clear();\r
+}\r
+\r
+\r
+// Returns nonzero if there aren't any samples available for outputting.\r
+int RateTransposer::isEmpty() const\r
+{\r
+    int res;\r
+\r
+    res = FIFOProcessor::isEmpty();\r
+    if (res == 0) return 0;\r
+    return inputBuffer.isEmpty();\r
+}\r
+\r
+\r
+/// Return approximate initial input-output latency\r
+int RateTransposer::getLatency() const\r
+{\r
+    return (bUseAAFilter) ? pAAFilter->getLength() : 0;\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TransposerBase - Base class for interpolation\r
+// \r
+\r
+// static function to set interpolation algorithm\r
+void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)\r
+{\r
+    TransposerBase::algorithm = a;\r
+}\r
+\r
+\r
+// Transposes the sample rate of the given samples using linear interpolation. \r
+// Returns the number of samples returned in the "dest" buffer\r
+int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)\r
+{\r
+    int numSrcSamples = src.numSamples();\r
+    int sizeDemand = (int)((double)numSrcSamples / rate) + 8;\r
+    int numOutput;\r
+    SAMPLETYPE *psrc = src.ptrBegin();\r
+    SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);\r
+\r
+#ifndef USE_MULTICH_ALWAYS\r
+    if (numChannels == 1)\r
+    {\r
+        numOutput = transposeMono(pdest, psrc, numSrcSamples);\r
+    }\r
+    else if (numChannels == 2) \r
+    {\r
+        numOutput = transposeStereo(pdest, psrc, numSrcSamples);\r
+    } \r
+    else \r
+#endif // USE_MULTICH_ALWAYS\r
+    {\r
+        assert(numChannels > 0);\r
+        numOutput = transposeMulti(pdest, psrc, numSrcSamples);\r
+    }\r
+    dest.putSamples(numOutput);\r
+    src.receiveSamples(numSrcSamples);\r
+    return numOutput;\r
+}\r
+\r
+\r
+TransposerBase::TransposerBase()\r
+{\r
+    numChannels = 0;\r
+    rate = 1.0f;\r
+}\r
+\r
+\r
+TransposerBase::~TransposerBase()\r
+{\r
+}\r
+\r
+\r
+void TransposerBase::setChannels(int channels)\r
+{\r
+    numChannels = channels;\r
+    resetRegisters();\r
+}\r
+\r
+\r
+void TransposerBase::setRate(double newRate)\r
+{\r
+    rate = newRate;\r
+}\r
+\r
+\r
+// static factory function\r
+TransposerBase *TransposerBase::newInstance()\r
+{\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+    // Notice: For integer arithmetic support only linear algorithm (due to simplest calculus)\r
+    return ::new InterpolateLinearInteger;\r
+#else\r
+    switch (algorithm)\r
+    {\r
+        case LINEAR:\r
+            return new InterpolateLinearFloat;\r
+\r
+        case CUBIC:\r
+            return new InterpolateCubic;\r
+\r
+        case SHANNON:\r
+            return new InterpolateShannon;\r
+\r
+        default:\r
+            assert(false);\r
+            return NULL;\r
+    }\r
+#endif\r
+}\r
diff --git a/source/SoundTouch/RateTransposer.h b/source/SoundTouch/RateTransposer.h
new file mode 100644 (file)
index 0000000..52b7441
--- /dev/null
@@ -0,0 +1,163 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Sample rate transposer. Changes sample rate by using linear interpolation \r
+/// together with anti-alias filtering (first order interpolation with anti-\r
+/// alias filtering should be quite adequate for this application).\r
+///\r
+/// Use either of the derived classes of 'RateTransposerInteger' or \r
+/// 'RateTransposerFloat' for corresponding integer/floating point tranposing\r
+/// algorithm implementation.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef RateTransposer_H\r
+#define RateTransposer_H\r
+\r
+#include <stddef.h>\r
+#include "AAFilter.h"\r
+#include "FIFOSamplePipe.h"\r
+#include "FIFOSampleBuffer.h"\r
+\r
+#include "STTypes.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc)\r
+class TransposerBase\r
+{\r
+public:\r
+        enum ALGORITHM {\r
+        LINEAR = 0,\r
+        CUBIC,\r
+        SHANNON\r
+    };\r
+\r
+protected:\r
+    virtual void resetRegisters() = 0;\r
+\r
+    virtual int transposeMono(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples)  = 0;\r
+    virtual int transposeStereo(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples) = 0;\r
+    virtual int transposeMulti(SAMPLETYPE *dest, \r
+                        const SAMPLETYPE *src, \r
+                        int &srcSamples) = 0;\r
+\r
+    static ALGORITHM algorithm;\r
+\r
+public:\r
+    double rate;\r
+    int numChannels;\r
+\r
+    TransposerBase();\r
+    virtual ~TransposerBase();\r
+\r
+    virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);\r
+    virtual void setRate(double newRate);\r
+    virtual void setChannels(int channels);\r
+\r
+    // static factory function\r
+    static TransposerBase *newInstance();\r
+\r
+    // static function to set interpolation algorithm\r
+    static void setAlgorithm(ALGORITHM a);\r
+};\r
+\r
+\r
+/// A common linear samplerate transposer class.\r
+///\r
+class RateTransposer : public FIFOProcessor\r
+{\r
+protected:\r
+    /// Anti-alias filter object\r
+    AAFilter *pAAFilter;\r
+    TransposerBase *pTransposer;\r
+\r
+    /// Buffer for collecting samples to feed the anti-alias filter between\r
+    /// two batches\r
+    FIFOSampleBuffer inputBuffer;\r
+\r
+    /// Buffer for keeping samples between transposing & anti-alias filter\r
+    FIFOSampleBuffer midBuffer;\r
+\r
+    /// Output sample buffer\r
+    FIFOSampleBuffer outputBuffer;\r
+\r
+    bool bUseAAFilter;\r
+\r
+\r
+    /// Transposes sample rate by applying anti-alias filter to prevent folding. \r
+    /// Returns amount of samples returned in the "dest" buffer.\r
+    /// The maximum amount of samples that can be returned at a time is set by\r
+    /// the 'set_returnBuffer_size' function.\r
+    void processSamples(const SAMPLETYPE *src, \r
+                        uint numSamples);\r
+\r
+public:\r
+    RateTransposer();\r
+    virtual ~RateTransposer();\r
+\r
+    /// Returns the output buffer object\r
+    FIFOSamplePipe *getOutput() { return &outputBuffer; };\r
+\r
+    /// Return anti-alias filter object\r
+    AAFilter *getAAFilter();\r
+\r
+    /// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable\r
+    void enableAAFilter(bool newMode);\r
+\r
+    /// Returns nonzero if anti-alias filter is enabled.\r
+    bool isAAFilterEnabled() const;\r
+\r
+    /// Sets new target rate. Normal rate = 1.0, smaller values represent slower \r
+    /// rate, larger faster rates.\r
+    virtual void setRate(double newRate);\r
+\r
+    /// Sets the number of channels, 1 = mono, 2 = stereo\r
+    void setChannels(int channels);\r
+\r
+    /// Adds 'numSamples' pcs of samples from the 'samples' memory position into\r
+    /// the input of the object.\r
+    void putSamples(const SAMPLETYPE *samples, uint numSamples);\r
+\r
+    /// Clears all the samples in the object\r
+    void clear();\r
+\r
+    /// Returns nonzero if there aren't any samples available for outputting.\r
+    int isEmpty() const;\r
+\r
+    /// Return approximate initial input-output latency\r
+    int getLatency() const;\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/source/SoundTouch/SoundTouch.cpp b/source/SoundTouch/SoundTouch.cpp
new file mode 100644 (file)
index 0000000..1618884
--- /dev/null
@@ -0,0 +1,538 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// SoundTouch - main class for tempo/pitch/rate adjusting routines. \r
+///\r
+/// Notes:\r
+/// - Initialize the SoundTouch object instance by setting up the sound stream \r
+///   parameters with functions 'setSampleRate' and 'setChannels', then set \r
+///   desired tempo/pitch/rate settings with the corresponding functions.\r
+///\r
+/// - The SoundTouch class behaves like a first-in-first-out pipeline: The \r
+///   samples that are to be processed are fed into one of the pipe by calling\r
+///   function 'putSamples', while the ready processed samples can be read \r
+///   from the other end of the pipeline with function 'receiveSamples'.\r
+/// \r
+/// - The SoundTouch processing classes require certain sized 'batches' of \r
+///   samples in order to process the sound. For this reason the classes buffer \r
+///   incoming samples until there are enough of samples available for \r
+///   processing, then they carry out the processing step and consequently\r
+///   make the processed samples available for outputting.\r
+/// \r
+/// - For the above reason, the processing routines introduce a certain \r
+///   'latency' between the input and output, so that the samples input to\r
+///   SoundTouch may not be immediately available in the output, and neither \r
+///   the amount of outputtable samples may not immediately be in direct \r
+///   relationship with the amount of previously input samples.\r
+///\r
+/// - The tempo/pitch/rate control parameters can be altered during processing.\r
+///   Please notice though that they aren't currently protected by semaphores,\r
+///   so in multi-thread application external semaphore protection may be\r
+///   required.\r
+///\r
+/// - This class utilizes classes 'TDStretch' for tempo change (without modifying\r
+///   pitch) and 'RateTransposer' for changing the playback rate (that is, both \r
+///   tempo and pitch in the same ratio) of the sound. The third available control \r
+///   'pitch' (change pitch but maintain tempo) is produced by a combination of\r
+///   combining the two other controls.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <assert.h>\r
+#include <stdlib.h>\r
+#include <memory.h>\r
+#include <math.h>\r
+#include <stdio.h>\r
+\r
+#include "SoundTouch.h"\r
+#include "TDStretch.h"\r
+#include "RateTransposer.h"\r
+#include "cpu_detect.h"\r
+\r
+using namespace soundtouch;\r
+    \r
+/// test if two floating point numbers are equal\r
+#define TEST_FLOAT_EQUAL(a, b)  (fabs(a - b) < 1e-10)\r
+\r
+\r
+/// Print library version string for autoconf\r
+extern "C" void soundtouch_ac_test()\r
+{\r
+    printf("SoundTouch Version: %s\n",SOUNDTOUCH_VERSION);\r
+} \r
+\r
+\r
+SoundTouch::SoundTouch()\r
+{\r
+    // Initialize rate transposer and tempo changer instances\r
+\r
+    pRateTransposer = new RateTransposer();\r
+    pTDStretch = TDStretch::newInstance();\r
+\r
+    setOutPipe(pTDStretch);\r
+\r
+    rate = tempo = 0;\r
+\r
+    virtualPitch = \r
+    virtualRate = \r
+    virtualTempo = 1.0;\r
+\r
+    calcEffectiveRateAndTempo();\r
+\r
+    samplesExpectedOut = 0;\r
+    samplesOutput = 0;\r
+\r
+    channels = 0;\r
+    bSrateSet = false;\r
+}\r
+\r
+\r
+SoundTouch::~SoundTouch()\r
+{\r
+    delete pRateTransposer;\r
+    delete pTDStretch;\r
+}\r
+\r
+\r
+/// Get SoundTouch library version string\r
+const char *SoundTouch::getVersionString()\r
+{\r
+    static const char *_version = SOUNDTOUCH_VERSION;\r
+\r
+    return _version;\r
+}\r
+\r
+\r
+/// Get SoundTouch library version Id\r
+uint SoundTouch::getVersionId()\r
+{\r
+    return SOUNDTOUCH_VERSION_ID;\r
+}\r
+\r
+\r
+// Sets the number of channels, 1 = mono, 2 = stereo\r
+void SoundTouch::setChannels(uint numChannels)\r
+{\r
+    if (!verifyNumberOfChannels(numChannels)) return;\r
+\r
+    channels = numChannels;\r
+    pRateTransposer->setChannels((int)numChannels);\r
+    pTDStretch->setChannels((int)numChannels);\r
+}\r
+\r
+\r
+// Sets new rate control value. Normal rate = 1.0, smaller values\r
+// represent slower rate, larger faster rates.\r
+void SoundTouch::setRate(double newRate)\r
+{\r
+    virtualRate = newRate;\r
+    calcEffectiveRateAndTempo();\r
+}\r
+\r
+\r
+// Sets new rate control value as a difference in percents compared\r
+// to the original rate (-50 .. +100 %)\r
+void SoundTouch::setRateChange(double newRate)\r
+{\r
+    virtualRate = 1.0 + 0.01 * newRate;\r
+    calcEffectiveRateAndTempo();\r
+}\r
+\r
+\r
+// Sets new tempo control value. Normal tempo = 1.0, smaller values\r
+// represent slower tempo, larger faster tempo.\r
+void SoundTouch::setTempo(double newTempo)\r
+{\r
+    virtualTempo = newTempo;\r
+    calcEffectiveRateAndTempo();\r
+}\r
+\r
+\r
+// Sets new tempo control value as a difference in percents compared\r
+// to the original tempo (-50 .. +100 %)\r
+void SoundTouch::setTempoChange(double newTempo)\r
+{\r
+    virtualTempo = 1.0 + 0.01 * newTempo;\r
+    calcEffectiveRateAndTempo();\r
+}\r
+\r
+\r
+// Sets new pitch control value. Original pitch = 1.0, smaller values\r
+// represent lower pitches, larger values higher pitch.\r
+void SoundTouch::setPitch(double newPitch)\r
+{\r
+    virtualPitch = newPitch;\r
+    calcEffectiveRateAndTempo();\r
+}\r
+\r
+\r
+// Sets pitch change in octaves compared to the original pitch\r
+// (-1.00 .. +1.00)\r
+void SoundTouch::setPitchOctaves(double newPitch)\r
+{\r
+    virtualPitch = exp(0.69314718056 * newPitch);\r
+    calcEffectiveRateAndTempo();\r
+}\r
+\r
+\r
+// Sets pitch change in semi-tones compared to the original pitch\r
+// (-12 .. +12)\r
+void SoundTouch::setPitchSemiTones(int newPitch)\r
+{\r
+    setPitchOctaves((double)newPitch / 12.0);\r
+}\r
+\r
+\r
+void SoundTouch::setPitchSemiTones(double newPitch)\r
+{\r
+    setPitchOctaves(newPitch / 12.0);\r
+}\r
+\r
+\r
+// Calculates 'effective' rate and tempo values from the\r
+// nominal control values.\r
+void SoundTouch::calcEffectiveRateAndTempo()\r
+{\r
+    double oldTempo = tempo;\r
+    double oldRate = rate;\r
+\r
+    tempo = virtualTempo / virtualPitch;\r
+    rate = virtualPitch * virtualRate;\r
+\r
+    if (!TEST_FLOAT_EQUAL(rate,oldRate)) pRateTransposer->setRate(rate);\r
+    if (!TEST_FLOAT_EQUAL(tempo, oldTempo)) pTDStretch->setTempo(tempo);\r
+\r
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER\r
+    if (rate <= 1.0f) \r
+    {\r
+        if (output != pTDStretch) \r
+        {\r
+            FIFOSamplePipe *tempoOut;\r
+\r
+            assert(output == pRateTransposer);\r
+            // move samples in the current output buffer to the output of pTDStretch\r
+            tempoOut = pTDStretch->getOutput();\r
+            tempoOut->moveSamples(*output);\r
+            // move samples in pitch transposer's store buffer to tempo changer's input\r
+            // deprecated : pTDStretch->moveSamples(*pRateTransposer->getStore());\r
+\r
+            output = pTDStretch;\r
+        }\r
+    }\r
+    else\r
+#endif\r
+    {\r
+        if (output != pRateTransposer) \r
+        {\r
+            FIFOSamplePipe *transOut;\r
+\r
+            assert(output == pTDStretch);\r
+            // move samples in the current output buffer to the output of pRateTransposer\r
+            transOut = pRateTransposer->getOutput();\r
+            transOut->moveSamples(*output);\r
+            // move samples in tempo changer's input to pitch transposer's input\r
+            pRateTransposer->moveSamples(*pTDStretch->getInput());\r
+\r
+            output = pRateTransposer;\r
+        }\r
+    } \r
+}\r
+\r
+\r
+// Sets sample rate.\r
+void SoundTouch::setSampleRate(uint srate)\r
+{\r
+    // set sample rate, leave other tempo changer parameters as they are.\r
+    pTDStretch->setParameters((int)srate);\r
+    bSrateSet = true;\r
+}\r
+\r
+\r
+// Adds 'numSamples' pcs of samples from the 'samples' memory position into\r
+// the input of the object.\r
+void SoundTouch::putSamples(const SAMPLETYPE *samples, uint nSamples)\r
+{\r
+    if (bSrateSet == false) \r
+    {\r
+        ST_THROW_RT_ERROR("SoundTouch : Sample rate not defined");\r
+    } \r
+    else if (channels == 0) \r
+    {\r
+        ST_THROW_RT_ERROR("SoundTouch : Number of channels not defined");\r
+    }\r
+\r
+    // accumulate how many samples are expected out from processing, given the current \r
+    // processing setting\r
+    samplesExpectedOut += (double)nSamples / ((double)rate * (double)tempo);\r
+\r
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER\r
+    if (rate <= 1.0f) \r
+    {\r
+        // transpose the rate down, output the transposed sound to tempo changer buffer\r
+        assert(output == pTDStretch);\r
+        pRateTransposer->putSamples(samples, nSamples);\r
+        pTDStretch->moveSamples(*pRateTransposer);\r
+    } \r
+    else \r
+#endif\r
+    {\r
+        // evaluate the tempo changer, then transpose the rate up, \r
+        assert(output == pRateTransposer);\r
+        pTDStretch->putSamples(samples, nSamples);\r
+        pRateTransposer->moveSamples(*pTDStretch);\r
+    }\r
+}\r
+\r
+\r
+// Flushes the last samples from the processing pipeline to the output.\r
+// Clears also the internal processing buffers.\r
+//\r
+// Note: This function is meant for extracting the last samples of a sound\r
+// stream. This function may introduce additional blank samples in the end\r
+// of the sound stream, and thus it's not recommended to call this function\r
+// in the middle of a sound stream.\r
+void SoundTouch::flush()\r
+{\r
+    int i;\r
+    int numStillExpected;\r
+    SAMPLETYPE *buff = new SAMPLETYPE[128 * channels];\r
+\r
+    // how many samples are still expected to output\r
+    numStillExpected = (int)((long)(samplesExpectedOut + 0.5) - samplesOutput);\r
+    if (numStillExpected < 0) numStillExpected = 0;\r
+\r
+    memset(buff, 0, 128 * channels * sizeof(SAMPLETYPE));\r
+    // "Push" the last active samples out from the processing pipeline by\r
+    // feeding blank samples into the processing pipeline until new, \r
+    // processed samples appear in the output (not however, more than \r
+    // 24ksamples in any case)\r
+    for (i = 0; (numStillExpected > (int)numSamples()) && (i < 200); i ++)\r
+    {\r
+        putSamples(buff, 128);\r
+    }\r
+\r
+    adjustAmountOfSamples(numStillExpected);\r
+\r
+    delete[] buff;\r
+\r
+    // Clear input buffers\r
+    pTDStretch->clearInput();\r
+    // yet leave the output intouched as that's where the\r
+    // flushed samples are!\r
+}\r
+\r
+\r
+// Changes a setting controlling the processing system behaviour. See the\r
+// 'SETTING_...' defines for available setting ID's.\r
+bool SoundTouch::setSetting(int settingId, int value)\r
+{\r
+    int sampleRate, sequenceMs, seekWindowMs, overlapMs;\r
+\r
+    // read current tdstretch routine parameters\r
+    pTDStretch->getParameters(&sampleRate, &sequenceMs, &seekWindowMs, &overlapMs);\r
+\r
+    switch (settingId) \r
+    {\r
+        case SETTING_USE_AA_FILTER :\r
+            // enables / disabless anti-alias filter\r
+            pRateTransposer->enableAAFilter((value != 0) ? true : false);\r
+            return true;\r
+\r
+        case SETTING_AA_FILTER_LENGTH :\r
+            // sets anti-alias filter length\r
+            pRateTransposer->getAAFilter()->setLength(value);\r
+            return true;\r
+\r
+        case SETTING_USE_QUICKSEEK :\r
+            // enables / disables tempo routine quick seeking algorithm\r
+            pTDStretch->enableQuickSeek((value != 0) ? true : false);\r
+            return true;\r
+\r
+        case SETTING_SEQUENCE_MS:\r
+            // change time-stretch sequence duration parameter\r
+            pTDStretch->setParameters(sampleRate, value, seekWindowMs, overlapMs);\r
+            return true;\r
+\r
+        case SETTING_SEEKWINDOW_MS:\r
+            // change time-stretch seek window length parameter\r
+            pTDStretch->setParameters(sampleRate, sequenceMs, value, overlapMs);\r
+            return true;\r
+\r
+        case SETTING_OVERLAP_MS:\r
+            // change time-stretch overlap length parameter\r
+            pTDStretch->setParameters(sampleRate, sequenceMs, seekWindowMs, value);\r
+            return true;\r
+\r
+        default :\r
+            return false;\r
+    }\r
+}\r
+\r
+\r
+// Reads a setting controlling the processing system behaviour. See the\r
+// 'SETTING_...' defines for available setting ID's.\r
+//\r
+// Returns the setting value.\r
+int SoundTouch::getSetting(int settingId) const\r
+{\r
+    int temp;\r
+\r
+    switch (settingId) \r
+    {\r
+        case SETTING_USE_AA_FILTER :\r
+            return (uint)pRateTransposer->isAAFilterEnabled();\r
+\r
+        case SETTING_AA_FILTER_LENGTH :\r
+            return pRateTransposer->getAAFilter()->getLength();\r
+\r
+        case SETTING_USE_QUICKSEEK :\r
+            return (uint)pTDStretch->isQuickSeekEnabled();\r
+\r
+        case SETTING_SEQUENCE_MS:\r
+            pTDStretch->getParameters(NULL, &temp, NULL, NULL);\r
+            return temp;\r
+\r
+        case SETTING_SEEKWINDOW_MS:\r
+            pTDStretch->getParameters(NULL, NULL, &temp, NULL);\r
+            return temp;\r
+\r
+        case SETTING_OVERLAP_MS:\r
+            pTDStretch->getParameters(NULL, NULL, NULL, &temp);\r
+            return temp;\r
+\r
+        case SETTING_NOMINAL_INPUT_SEQUENCE :\r
+        {\r
+            int size = pTDStretch->getInputSampleReq();\r
+\r
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER\r
+            if (rate <= 1.0)\r
+            {\r
+                // transposing done before timestretch, which impacts latency\r
+                return (int)(size * rate + 0.5);\r
+            }\r
+#endif\r
+            return size;\r
+        }\r
+\r
+        case SETTING_NOMINAL_OUTPUT_SEQUENCE :\r
+        {\r
+            int size = pTDStretch->getOutputBatchSize();\r
+\r
+            if (rate > 1.0)\r
+            {\r
+                // transposing done after timestretch, which impacts latency\r
+                return (int)(size / rate + 0.5);\r
+            }\r
+            return size;\r
+        }\r
+\r
+        case SETTING_INITIAL_LATENCY:\r
+        {\r
+            double latency = pTDStretch->getLatency();\r
+            int latency_tr = pRateTransposer->getLatency();\r
+\r
+#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER\r
+            if (rate <= 1.0)\r
+            {\r
+                // transposing done before timestretch, which impacts latency\r
+                latency = (latency + latency_tr) * rate;\r
+            }\r
+            else\r
+#endif\r
+            {\r
+                latency += (double)latency_tr / rate;\r
+            }\r
+\r
+            return (int)(latency + 0.5);\r
+        }\r
+\r
+        default :\r
+            return 0;\r
+    }\r
+}\r
+\r
+\r
+// Clears all the samples in the object's output and internal processing\r
+// buffers.\r
+void SoundTouch::clear()\r
+{\r
+    samplesExpectedOut = 0;\r
+    samplesOutput = 0;\r
+    pRateTransposer->clear();\r
+    pTDStretch->clear();\r
+}\r
+\r
+\r
+/// Returns number of samples currently unprocessed.\r
+uint SoundTouch::numUnprocessedSamples() const\r
+{\r
+    FIFOSamplePipe * psp;\r
+    if (pTDStretch)\r
+    {\r
+        psp = pTDStretch->getInput();\r
+        if (psp)\r
+        {\r
+            return psp->numSamples();\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+/// Output samples from beginning of the sample buffer. Copies requested samples to \r
+/// output buffer and removes them from the sample buffer. If there are less than \r
+/// 'numsample' samples in the buffer, returns all that available.\r
+///\r
+/// \return Number of samples returned.\r
+uint SoundTouch::receiveSamples(SAMPLETYPE *output, uint maxSamples)\r
+{\r
+    uint ret = FIFOProcessor::receiveSamples(output, maxSamples);\r
+    samplesOutput += (long)ret;\r
+    return ret;\r
+}\r
+\r
+\r
+/// Adjusts book-keeping so that given number of samples are removed from beginning of the \r
+/// sample buffer without copying them anywhere. \r
+///\r
+/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+/// with 'ptrBegin' function.\r
+uint SoundTouch::receiveSamples(uint maxSamples)\r
+{\r
+    uint ret = FIFOProcessor::receiveSamples(maxSamples);\r
+    samplesOutput += (long)ret;\r
+    return ret;\r
+}\r
+\r
+\r
+/// Get ratio between input and output audio durations, useful for calculating\r
+/// processed output duration: if you'll process a stream of N samples, then \r
+/// you can expect to get out N * getInputOutputSampleRatio() samples.\r
+double SoundTouch::getInputOutputSampleRatio()\r
+{\r
+    return 1.0 / (tempo * rate);\r
+}\r
diff --git a/source/SoundTouch/SoundTouch.sln b/source/SoundTouch/SoundTouch.sln
new file mode 100644 (file)
index 0000000..0e08834
--- /dev/null
@@ -0,0 +1,29 @@
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 14\r
+VisualStudioVersion = 14.0.23107.0\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "SoundTouch.vcxproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Debug|x64 = Debug|x64\r
+               Release|Win32 = Release|Win32\r
+               Release|x64 = Release|x64\r
+               ReleaseX64|Win32 = ReleaseX64|Win32\r
+               ReleaseX64|x64 = ReleaseX64|x64\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.ActiveCfg = Debug|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.ActiveCfg = Release|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.ActiveCfg = Release|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|Win32.ActiveCfg = ReleaseX64|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|Win32.Build.0 = ReleaseX64|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|x64.ActiveCfg = ReleaseX64|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|x64.Build.0 = ReleaseX64|x64\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/source/SoundTouch/SoundTouch.vcxproj b/source/SoundTouch/SoundTouch.vcxproj
new file mode 100644 (file)
index 0000000..82e6288
--- /dev/null
@@ -0,0 +1,338 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|x64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|x64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{68A5DD20-7057-448B-8FE0-B6AC8D205509}</ProjectGuid>\r
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <UseOfMfc>false</UseOfMfc>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup>\r
+    <_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)_x64</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)D</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)D_x64</TargetName>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <ClCompile>\r
+      <Optimization>Full</Optimization>\r
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <StringPooling>true</StringPooling>\r
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeader />\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat />\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\r
+      <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>\r
+      <BrowseInformationFile>$(IntDir)</BrowseInformationFile>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Lib>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+    </Lib>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Full</Optimization>\r
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <StringPooling>true</StringPooling>\r
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeader />\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat />\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>\r
+      </EnableEnhancedInstructionSet>\r
+      <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>\r
+      <BrowseInformationFile>$(IntDir)</BrowseInformationFile>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Lib>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+    </Lib>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <ClCompile>\r
+      <Optimization>Disabled</Optimization>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeader />\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <BrowseInformation>true</BrowseInformation>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\r
+      <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>\r
+      <BrowseInformationFile>$(IntDir)</BrowseInformationFile>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Lib>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+    </Lib>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Disabled</Optimization>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
+      <FloatingPointModel>Fast</FloatingPointModel>\r
+      <PrecompiledHeader />\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <BrowseInformation>true</BrowseInformation>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <CompileAs>Default</CompileAs>\r
+      <EnableEnhancedInstructionSet>\r
+      </EnableEnhancedInstructionSet>\r
+      <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>\r
+      <BrowseInformationFile>$(IntDir)</BrowseInformationFile>\r
+    </ClCompile>\r
+    <ResourceCompile>\r
+      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <Culture>0x040b</Culture>\r
+    </ResourceCompile>\r
+    <Lib>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <SuppressStartupBanner>true</SuppressStartupBanner>\r
+    </Lib>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="AAFilter.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+    <ClCompile Include="BPMDetect.cpp">\r
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4996</DisableSpecificWarnings>\r
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4996</DisableSpecificWarnings>\r
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4996</DisableSpecificWarnings>\r
+      <DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4996</DisableSpecificWarnings>\r
+    </ClCompile>\r
+    <ClCompile Include="cpu_detect_x86.cpp" />\r
+    <ClCompile Include="FIFOSampleBuffer.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+    <ClCompile Include="FIRFilter.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+    <ClCompile Include="InterpolateCubic.cpp" />\r
+    <ClCompile Include="InterpolateLinear.cpp" />\r
+    <ClCompile Include="InterpolateShannon.cpp" />\r
+    <ClCompile Include="mmx_optimized.cpp" />\r
+    <ClCompile Include="PeakFinder.cpp" />\r
+    <ClCompile Include="RateTransposer.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+    <ClCompile Include="SoundTouch.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+    <ClCompile Include="sse_optimized.cpp" />\r
+    <ClCompile Include="TDStretch.cpp">\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
+      <BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>\r
+      <BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
+      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
+    </ClCompile>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="..\..\include\BPMDetect.h" />\r
+    <ClInclude Include="..\..\include\FIFOSampleBuffer.h" />\r
+    <ClInclude Include="..\..\include\FIFOSamplePipe.h" />\r
+    <ClInclude Include="..\..\include\SoundTouch.h" />\r
+    <ClInclude Include="..\..\include\STTypes.h" />\r
+    <ClInclude Include="AAFilter.h" />\r
+    <ClInclude Include="cpu_detect.h" />\r
+    <ClInclude Include="FIRFilter.h" />\r
+    <ClInclude Include="InterpolateCubic.h" />\r
+    <ClInclude Include="InterpolateLinear.h" />\r
+    <ClInclude Include="InterpolateShannon.h" />\r
+    <ClInclude Include="PeakFinder.h" />\r
+    <ClInclude Include="RateTransposer.h" />\r
+    <ClInclude Include="TDStretch.h" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>
\ No newline at end of file
diff --git a/source/SoundTouch/TDStretch.cpp b/source/SoundTouch/TDStretch.cpp
new file mode 100644 (file)
index 0000000..ce49310
--- /dev/null
@@ -0,0 +1,1111 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo \r
+/// while maintaining the original pitch by using a time domain WSOLA-like \r
+/// method with several performance-increasing tweaks.\r
+///\r
+/// Notes : MMX optimized functions reside in a separate, platform-specific \r
+/// file, e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'.\r
+///\r
+/// This source file contains OpenMP optimizations that allow speeding up the\r
+/// corss-correlation algorithm by executing it in several threads / CPU cores \r
+/// in parallel. See the following article link for more detailed discussion \r
+/// about SoundTouch OpenMP optimizations:\r
+/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <string.h>\r
+#include <limits.h>\r
+#include <assert.h>\r
+#include <math.h>\r
+#include <float.h>\r
+\r
+#include "STTypes.h"\r
+#include "cpu_detect.h"\r
+#include "TDStretch.h"\r
+\r
+using namespace soundtouch;\r
+\r
+#define max(x, y) (((x) > (y)) ? (x) : (y))\r
+\r
+\r
+/*****************************************************************************\r
+ *\r
+ * Constant definitions\r
+ *\r
+ *****************************************************************************/\r
+\r
+// Table for the hierarchical mixing position seeking algorithm\r
+const short _scanOffsets[5][24]={\r
+    { 124,  186,  248,  310,  372,  434,  496,  558,  620,  682,  744, 806,\r
+      868,  930,  992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488,   0},\r
+    {-100,  -75,  -50,  -25,   25,   50,   75,  100,    0,    0,    0,   0,\r
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0},\r
+    { -20,  -15,  -10,   -5,    5,   10,   15,   20,    0,    0,    0,   0,\r
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0},\r
+    {  -4,   -3,   -2,   -1,    1,    2,    3,    4,    0,    0,    0,   0,\r
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,   0},\r
+    { 121,  114,   97,  114,   98,  105,  108,   32,  104,   99,  117,  111,\r
+      116,  100,  110,  117,  111,  115,    0,    0,    0,    0,    0,   0}};\r
+\r
+/*****************************************************************************\r
+ *\r
+ * Implementation of the class 'TDStretch'\r
+ *\r
+ *****************************************************************************/\r
+\r
+\r
+TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)\r
+{\r
+    bQuickSeek = false;\r
+    channels = 2;\r
+\r
+    pMidBuffer = NULL;\r
+    pMidBufferUnaligned = NULL;\r
+    overlapLength = 0;\r
+\r
+    bAutoSeqSetting = true;\r
+    bAutoSeekSetting = true;\r
+\r
+    maxnorm = 0;\r
+    maxnormf = 1e8;\r
+\r
+    skipFract = 0;\r
+\r
+    tempo = 1.0f;\r
+    setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);\r
+    setTempo(1.0f);\r
+\r
+    clear();\r
+}\r
+\r
+\r
+\r
+TDStretch::~TDStretch()\r
+{\r
+    delete[] pMidBufferUnaligned;\r
+}\r
+\r
+\r
+\r
+// Sets routine control parameters. These control are certain time constants\r
+// defining how the sound is stretched to the desired duration.\r
+//\r
+// 'sampleRate' = sample rate of the sound\r
+// 'sequenceMS' = one processing sequence length in milliseconds (default = 82 ms)\r
+// 'seekwindowMS' = seeking window length for scanning the best overlapping \r
+//      position (default = 28 ms)\r
+// 'overlapMS' = overlapping length (default = 12 ms)\r
+\r
+void TDStretch::setParameters(int aSampleRate, int aSequenceMS, \r
+                              int aSeekWindowMS, int aOverlapMS)\r
+{\r
+    // accept only positive parameter values - if zero or negative, use old values instead\r
+    if (aSampleRate > 0)\r
+    {\r
+        if (aSampleRate > 192000) ST_THROW_RT_ERROR("Error: Excessive samplerate");\r
+        this->sampleRate = aSampleRate;\r
+    }\r
+\r
+    if (aOverlapMS > 0) this->overlapMs = aOverlapMS;\r
+\r
+    if (aSequenceMS > 0)\r
+    {\r
+        this->sequenceMs = aSequenceMS;\r
+        bAutoSeqSetting = false;\r
+    } \r
+    else if (aSequenceMS == 0)\r
+    {\r
+        // if zero, use automatic setting\r
+        bAutoSeqSetting = true;\r
+    }\r
+\r
+    if (aSeekWindowMS > 0) \r
+    {\r
+        this->seekWindowMs = aSeekWindowMS;\r
+        bAutoSeekSetting = false;\r
+    } \r
+    else if (aSeekWindowMS == 0) \r
+    {\r
+        // if zero, use automatic setting\r
+        bAutoSeekSetting = true;\r
+    }\r
+\r
+    calcSeqParameters();\r
+\r
+    calculateOverlapLength(overlapMs);\r
+\r
+    // set tempo to recalculate 'sampleReq'\r
+    setTempo(tempo);\r
+}\r
+\r
+\r
+\r
+/// Get routine control parameters, see setParameters() function.\r
+/// Any of the parameters to this function can be NULL, in such case corresponding parameter\r
+/// value isn't returned.\r
+void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const\r
+{\r
+    if (pSampleRate)\r
+    {\r
+        *pSampleRate = sampleRate;\r
+    }\r
+\r
+    if (pSequenceMs)\r
+    {\r
+        *pSequenceMs = (bAutoSeqSetting) ? (USE_AUTO_SEQUENCE_LEN) : sequenceMs;\r
+    }\r
+\r
+    if (pSeekWindowMs)\r
+    {\r
+        *pSeekWindowMs = (bAutoSeekSetting) ? (USE_AUTO_SEEKWINDOW_LEN) : seekWindowMs;\r
+    }\r
+\r
+    if (pOverlapMs)\r
+    {\r
+        *pOverlapMs = overlapMs;\r
+    }\r
+}\r
+\r
+\r
+// Overlaps samples in 'midBuffer' with the samples in 'pInput'\r
+void TDStretch::overlapMono(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput) const\r
+{\r
+    int i;\r
+    SAMPLETYPE m1, m2;\r
+\r
+    m1 = (SAMPLETYPE)0;\r
+    m2 = (SAMPLETYPE)overlapLength;\r
+\r
+    for (i = 0; i < overlapLength ; i ++) \r
+    {\r
+        pOutput[i] = (pInput[i] * m1 + pMidBuffer[i] * m2 ) / overlapLength;\r
+        m1 += 1;\r
+        m2 -= 1;\r
+    }\r
+}\r
+\r
+\r
+\r
+void TDStretch::clearMidBuffer()\r
+{\r
+    memset(pMidBuffer, 0, channels * sizeof(SAMPLETYPE) * overlapLength);\r
+}\r
+\r
+\r
+void TDStretch::clearInput()\r
+{\r
+    inputBuffer.clear();\r
+    clearMidBuffer();\r
+    isBeginning = true;\r
+}\r
+\r
+\r
+// Clears the sample buffers\r
+void TDStretch::clear()\r
+{\r
+    outputBuffer.clear();\r
+    clearInput();\r
+}\r
+\r
+\r
+\r
+// Enables/disables the quick position seeking algorithm. Zero to disable, nonzero\r
+// to enable\r
+void TDStretch::enableQuickSeek(bool enable)\r
+{\r
+    bQuickSeek = enable;\r
+}\r
+\r
+\r
+// Returns nonzero if the quick seeking algorithm is enabled.\r
+bool TDStretch::isQuickSeekEnabled() const\r
+{\r
+    return bQuickSeek;\r
+}\r
+\r
+\r
+// Seeks for the optimal overlap-mixing position.\r
+int TDStretch::seekBestOverlapPosition(const SAMPLETYPE *refPos)\r
+{\r
+    if (bQuickSeek) \r
+    {\r
+        return seekBestOverlapPositionQuick(refPos);\r
+    }\r
+    else \r
+    {\r
+        return seekBestOverlapPositionFull(refPos);\r
+    }\r
+}\r
+\r
+\r
+// Overlaps samples in 'midBuffer' with the samples in 'pInputBuffer' at position\r
+// of 'ovlPos'.\r
+inline void TDStretch::overlap(SAMPLETYPE *pOutput, const SAMPLETYPE *pInput, uint ovlPos) const\r
+{\r
+#ifndef USE_MULTICH_ALWAYS\r
+    if (channels == 1)\r
+    {\r
+        // mono sound.\r
+        overlapMono(pOutput, pInput + ovlPos);\r
+    }\r
+    else if (channels == 2)\r
+    {\r
+        // stereo sound\r
+        overlapStereo(pOutput, pInput + 2 * ovlPos);\r
+    } \r
+    else \r
+#endif // USE_MULTICH_ALWAYS\r
+    {\r
+        assert(channels > 0);\r
+        overlapMulti(pOutput, pInput + channels * ovlPos);\r
+    }\r
+}\r
+\r
+\r
+// Seeks for the optimal overlap-mixing position. The 'stereo' version of the\r
+// routine\r
+//\r
+// The best position is determined as the position where the two overlapped\r
+// sample sequences are 'most alike', in terms of the highest cross-correlation\r
+// value over the overlapping period\r
+int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos) \r
+{\r
+    int bestOffs;\r
+    double bestCorr;\r
+    int i;\r
+    double norm;\r
+\r
+    bestCorr = -FLT_MAX;\r
+    bestOffs = 0;\r
+\r
+    // Scans for the best correlation value by testing each possible position\r
+    // over the permitted range.\r
+    bestCorr = calcCrossCorr(refPos, pMidBuffer, norm);\r
+    bestCorr = (bestCorr + 0.1) * 0.75;\r
+\r
+    #pragma omp parallel for\r
+    for (i = 1; i < seekLength; i ++) \r
+    {\r
+        double corr;\r
+        // Calculates correlation value for the mixing position corresponding to 'i'\r
+#ifdef _OPENMP\r
+        // in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't\r
+        // iterate the loop in sequential order\r
+        corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm);\r
+#else\r
+        // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same\r
+        // as "calcCrossCorr", but saves time by reusing & updating previously stored \r
+        // "norm" value\r
+        corr = calcCrossCorrAccumulate(refPos + channels * i, pMidBuffer, norm);\r
+#endif\r
+        // heuristic rule to slightly favour values close to mid of the range\r
+        double tmp = (double)(2 * i - seekLength) / (double)seekLength;\r
+        corr = ((corr + 0.1) * (1.0 - 0.25 * tmp * tmp));\r
+\r
+        // Checks for the highest correlation value\r
+        if (corr > bestCorr) \r
+        {\r
+            // For optimal performance, enter critical section only in case that best value found.\r
+            // in such case repeat 'if' condition as it's possible that parallel execution may have\r
+            // updated the bestCorr value in the mean time\r
+            #pragma omp critical\r
+            if (corr > bestCorr)\r
+            {\r
+                bestCorr = corr;\r
+                bestOffs = i;\r
+            }\r
+        }\r
+    }\r
+\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+    adaptNormalizer();\r
+#endif\r
+\r
+    // clear cross correlation routine state if necessary (is so e.g. in MMX routines).\r
+    clearCrossCorrState();\r
+\r
+    return bestOffs;\r
+}\r
+\r
+\r
+// Quick seek algorithm for improved runtime-performance: First roughly scans through the \r
+// correlation area, and then scan surroundings of two best preliminary correlation candidates\r
+// with improved precision\r
+//\r
+// Based on testing:\r
+// - This algorithm gives on average 99% as good match as the full algorithm\r
+// - this quick seek algorithm finds the best match on ~90% of cases\r
+// - on those 10% of cases when this algorithm doesn't find best match, \r
+//   it still finds on average ~90% match vs. the best possible match\r
+int TDStretch::seekBestOverlapPositionQuick(const SAMPLETYPE *refPos)\r
+{\r
+#define _MIN(a, b)   (((a) < (b)) ? (a) : (b))\r
+#define SCANSTEP    16\r
+#define SCANWIND    8\r
+\r
+    int bestOffs;\r
+    int i;\r
+    int bestOffs2;\r
+    float bestCorr, corr;\r
+    float bestCorr2;\r
+    double norm;\r
+\r
+    // note: 'float' types used in this function in case that the platform would need to use software-fp\r
+\r
+    bestCorr =\r
+    bestCorr2 = -FLT_MAX;\r
+    bestOffs = \r
+    bestOffs2 = SCANWIND;\r
+\r
+    // Scans for the best correlation value by testing each possible position\r
+    // over the permitted range. Look for two best matches on the first pass to\r
+    // increase possibility of ideal match.\r
+    //\r
+    // Begin from "SCANSTEP" instead of SCANWIND to make the calculation\r
+    // catch the 'middlepoint' of seekLength vector as that's the a-priori \r
+    // expected best match position\r
+    //\r
+    // Roughly:\r
+    // - 15% of cases find best result directly on the first round,\r
+    // - 75% cases find better match on 2nd round around the best match from 1st round\r
+    // - 10% cases find better match on 2nd round around the 2nd-best-match from 1st round\r
+    for (i = SCANSTEP; i < seekLength - SCANWIND - 1; i += SCANSTEP)\r
+    {\r
+        // Calculates correlation value for the mixing position corresponding\r
+        // to 'i'\r
+        corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm);\r
+        // heuristic rule to slightly favour values close to mid of the seek range\r
+        float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength;\r
+        corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp));\r
+\r
+        // Checks for the highest correlation value\r
+        if (corr > bestCorr)\r
+        {\r
+            // found new best match. keep the previous best as 2nd best match\r
+            bestCorr2 = bestCorr;\r
+            bestOffs2 = bestOffs;\r
+            bestCorr = corr;\r
+            bestOffs = i;\r
+        }\r
+        else if (corr > bestCorr2)\r
+        {\r
+            // not new best, but still new 2nd best match\r
+            bestCorr2 = corr;\r
+            bestOffs2 = i;\r
+        }\r
+    }\r
+\r
+    // Scans surroundings of the found best match with small stepping\r
+    int end = _MIN(bestOffs + SCANWIND + 1, seekLength);\r
+    for (i = bestOffs - SCANWIND; i < end; i++)\r
+    {\r
+        if (i == bestOffs) continue;    // this offset already calculated, thus skip\r
+\r
+        // Calculates correlation value for the mixing position corresponding\r
+        // to 'i'\r
+        corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm);\r
+        // heuristic rule to slightly favour values close to mid of the range\r
+        float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength;\r
+        corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp));\r
+\r
+        // Checks for the highest correlation value\r
+        if (corr > bestCorr)\r
+        {\r
+            bestCorr = corr;\r
+            bestOffs = i;\r
+        }\r
+    }\r
+\r
+    // Scans surroundings of the 2nd best match with small stepping\r
+    end = _MIN(bestOffs2 + SCANWIND + 1, seekLength);\r
+    for (i = bestOffs2 - SCANWIND; i < end; i++)\r
+    {\r
+        if (i == bestOffs2) continue;    // this offset already calculated, thus skip\r
+\r
+        // Calculates correlation value for the mixing position corresponding\r
+        // to 'i'\r
+        corr = (float)calcCrossCorr(refPos + channels*i, pMidBuffer, norm);\r
+        // heuristic rule to slightly favour values close to mid of the range\r
+        float tmp = (float)(2 * i - seekLength - 1) / (float)seekLength;\r
+        corr = ((corr + 0.1f) * (1.0f - 0.25f * tmp * tmp));\r
+\r
+        // Checks for the highest correlation value\r
+        if (corr > bestCorr)\r
+        {\r
+            bestCorr = corr;\r
+            bestOffs = i;\r
+        }\r
+    }\r
+\r
+    // clear cross correlation routine state if necessary (is so e.g. in MMX routines).\r
+    clearCrossCorrState();\r
+\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+    adaptNormalizer();\r
+#endif\r
+\r
+    return bestOffs;\r
+}\r
+\r
+\r
+\r
+\r
+/// For integer algorithm: adapt normalization factor divider with music so that \r
+/// it'll not be pessimistically restrictive that can degrade quality on quieter sections\r
+/// yet won't cause integer overflows either\r
+void TDStretch::adaptNormalizer()\r
+{\r
+    // Do not adapt normalizer over too silent sequences to avoid averaging filter depleting to\r
+    // too low values during pauses in music\r
+    if ((maxnorm > 1000) || (maxnormf > 40000000))\r
+    { \r
+        //norm averaging filter\r
+        maxnormf = 0.9f * maxnormf + 0.1f * (float)maxnorm;\r
+\r
+        if ((maxnorm > 800000000) && (overlapDividerBitsNorm < 16))\r
+        {\r
+            // large values, so increase divider\r
+            overlapDividerBitsNorm++;\r
+            if (maxnorm > 1600000000) overlapDividerBitsNorm++; // extra large value => extra increase\r
+        }\r
+        else if ((maxnormf < 1000000) && (overlapDividerBitsNorm > 0))\r
+        {\r
+            // extra small values, decrease divider\r
+            overlapDividerBitsNorm--;\r
+        }\r
+    }\r
+\r
+    maxnorm = 0;\r
+}\r
+\r
+\r
+/// clear cross correlation routine state if necessary \r
+void TDStretch::clearCrossCorrState()\r
+{\r
+    // default implementation is empty.\r
+}\r
+\r
+\r
+/// Calculates processing sequence length according to tempo setting\r
+void TDStretch::calcSeqParameters()\r
+{\r
+    // Adjust tempo param according to tempo, so that variating processing sequence length is used\r
+    // at various tempo settings, between the given low...top limits\r
+    #define AUTOSEQ_TEMPO_LOW   0.5     // auto setting low tempo range (-50%)\r
+    #define AUTOSEQ_TEMPO_TOP   2.0     // auto setting top tempo range (+100%)\r
+\r
+    // sequence-ms setting values at above low & top tempo\r
+    #define AUTOSEQ_AT_MIN      90.0\r
+    #define AUTOSEQ_AT_MAX      40.0\r
+    #define AUTOSEQ_K           ((AUTOSEQ_AT_MAX - AUTOSEQ_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))\r
+    #define AUTOSEQ_C           (AUTOSEQ_AT_MIN - (AUTOSEQ_K) * (AUTOSEQ_TEMPO_LOW))\r
+\r
+    // seek-window-ms setting values at above low & top tempoq\r
+    #define AUTOSEEK_AT_MIN     20.0\r
+    #define AUTOSEEK_AT_MAX     15.0\r
+    #define AUTOSEEK_K          ((AUTOSEEK_AT_MAX - AUTOSEEK_AT_MIN) / (AUTOSEQ_TEMPO_TOP - AUTOSEQ_TEMPO_LOW))\r
+    #define AUTOSEEK_C          (AUTOSEEK_AT_MIN - (AUTOSEEK_K) * (AUTOSEQ_TEMPO_LOW))\r
+\r
+    #define CHECK_LIMITS(x, mi, ma) (((x) < (mi)) ? (mi) : (((x) > (ma)) ? (ma) : (x)))\r
+\r
+    double seq, seek;\r
+    \r
+    if (bAutoSeqSetting)\r
+    {\r
+        seq = AUTOSEQ_C + AUTOSEQ_K * tempo;\r
+        seq = CHECK_LIMITS(seq, AUTOSEQ_AT_MAX, AUTOSEQ_AT_MIN);\r
+        sequenceMs = (int)(seq + 0.5);\r
+    }\r
+\r
+    if (bAutoSeekSetting)\r
+    {\r
+        seek = AUTOSEEK_C + AUTOSEEK_K * tempo;\r
+        seek = CHECK_LIMITS(seek, AUTOSEEK_AT_MAX, AUTOSEEK_AT_MIN);\r
+        seekWindowMs = (int)(seek + 0.5);\r
+    }\r
+\r
+    // Update seek window lengths\r
+    seekWindowLength = (sampleRate * sequenceMs) / 1000;\r
+    if (seekWindowLength < 2 * overlapLength) \r
+    {\r
+        seekWindowLength = 2 * overlapLength;\r
+    }\r
+    seekLength = (sampleRate * seekWindowMs) / 1000;\r
+}\r
+\r
+\r
+\r
+// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower \r
+// tempo, larger faster tempo.\r
+void TDStretch::setTempo(double newTempo)\r
+{\r
+    int intskip;\r
+\r
+    tempo = newTempo;\r
+\r
+    // Calculate new sequence duration\r
+    calcSeqParameters();\r
+\r
+    // Calculate ideal skip length (according to tempo value) \r
+    nominalSkip = tempo * (seekWindowLength - overlapLength);\r
+    intskip = (int)(nominalSkip + 0.5);\r
+\r
+    // Calculate how many samples are needed in the 'inputBuffer' to \r
+    // process another batch of samples\r
+    //sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength / 2;\r
+    sampleReq = max(intskip + overlapLength, seekWindowLength) + seekLength;\r
+}\r
+\r
+\r
+\r
+// Sets the number of channels, 1 = mono, 2 = stereo\r
+void TDStretch::setChannels(int numChannels)\r
+{\r
+    if (!verifyNumberOfChannels(numChannels) ||\r
+        (channels == numChannels)) return;\r
+\r
+    channels = numChannels;\r
+    inputBuffer.setChannels(channels);\r
+    outputBuffer.setChannels(channels);\r
+\r
+    // re-init overlap/buffer\r
+    overlapLength=0;\r
+    setParameters(sampleRate);\r
+}\r
+\r
+\r
+// nominal tempo, no need for processing, just pass the samples through\r
+// to outputBuffer\r
+/*\r
+void TDStretch::processNominalTempo()\r
+{\r
+    assert(tempo == 1.0f);\r
+\r
+    if (bMidBufferDirty) \r
+    {\r
+        // If there are samples in pMidBuffer waiting for overlapping,\r
+        // do a single sliding overlapping with them in order to prevent a \r
+        // clicking distortion in the output sound\r
+        if (inputBuffer.numSamples() < overlapLength) \r
+        {\r
+            // wait until we've got overlapLength input samples\r
+            return;\r
+        }\r
+        // Mix the samples in the beginning of 'inputBuffer' with the \r
+        // samples in 'midBuffer' using sliding overlapping \r
+        overlap(outputBuffer.ptrEnd(overlapLength), inputBuffer.ptrBegin(), 0);\r
+        outputBuffer.putSamples(overlapLength);\r
+        inputBuffer.receiveSamples(overlapLength);\r
+        clearMidBuffer();\r
+        // now we've caught the nominal sample flow and may switch to\r
+        // bypass mode\r
+    }\r
+\r
+    // Simply bypass samples from input to output\r
+    outputBuffer.moveSamples(inputBuffer);\r
+}\r
+*/\r
+\r
+\r
+// Processes as many processing frames of the samples 'inputBuffer', store\r
+// the result into 'outputBuffer'\r
+void TDStretch::processSamples()\r
+{\r
+    int ovlSkip;\r
+    int offset = 0;\r
+    int temp;\r
+\r
+    /* Removed this small optimization - can introduce a click to sound when tempo setting\r
+       crosses the nominal value\r
+    if (tempo == 1.0f) \r
+    {\r
+        // tempo not changed from the original, so bypass the processing\r
+        processNominalTempo();\r
+        return;\r
+    }\r
+    */\r
+\r
+    // Process samples as long as there are enough samples in 'inputBuffer'\r
+    // to form a processing frame.\r
+    while ((int)inputBuffer.numSamples() >= sampleReq) \r
+    {\r
+        if (isBeginning == false)\r
+        {\r
+            // apart from the very beginning of the track, \r
+            // scan for the best overlapping position & do overlap-add\r
+            offset = seekBestOverlapPosition(inputBuffer.ptrBegin());\r
+\r
+            // Mix the samples in the 'inputBuffer' at position of 'offset' with the \r
+            // samples in 'midBuffer' using sliding overlapping\r
+            // ... first partially overlap with the end of the previous sequence\r
+            // (that's in 'midBuffer')\r
+            overlap(outputBuffer.ptrEnd((uint)overlapLength), inputBuffer.ptrBegin(), (uint)offset);\r
+            outputBuffer.putSamples((uint)overlapLength);\r
+            offset += overlapLength;\r
+        }\r
+        else\r
+        {\r
+            // Adjust processing offset at beginning of track by not perform initial overlapping\r
+            // and compensating that in the 'input buffer skip' calculation\r
+            isBeginning = false;\r
+            int skip = (int)(tempo * overlapLength + 0.5);\r
+\r
+            #ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION\r
+                #ifdef SOUNDTOUCH_ALLOW_SSE\r
+                // if SSE mode, round the skip amount to value corresponding to aligned memory address\r
+                if (channels == 1)\r
+                {\r
+                    skip &= -4;\r
+                }\r
+                else if (channels == 2)\r
+                {\r
+                    skip &= -2;\r
+                }\r
+                #endif\r
+            #endif\r
+            skipFract -= skip;\r
+            assert(nominalSkip >= -skipFract);\r
+        }\r
+\r
+        // ... then copy sequence samples from 'inputBuffer' to output:\r
+\r
+        // crosscheck that we don't have buffer overflow...\r
+        if ((int)inputBuffer.numSamples() < (offset + seekWindowLength - overlapLength))\r
+        {\r
+            continue;    // just in case, shouldn't really happen\r
+        }\r
+\r
+        // length of sequence\r
+        temp = (seekWindowLength - 2 * overlapLength);\r
+        outputBuffer.putSamples(inputBuffer.ptrBegin() + channels * offset, (uint)temp);\r
+\r
+        // Copies the end of the current sequence from 'inputBuffer' to \r
+        // 'midBuffer' for being mixed with the beginning of the next \r
+        // processing sequence and so on\r
+        assert((offset + temp + overlapLength) <= (int)inputBuffer.numSamples());\r
+        memcpy(pMidBuffer, inputBuffer.ptrBegin() + channels * (offset + temp), \r
+            channels * sizeof(SAMPLETYPE) * overlapLength);\r
+\r
+        // Remove the processed samples from the input buffer. Update\r
+        // the difference between integer & nominal skip step to 'skipFract'\r
+        // in order to prevent the error from accumulating over time.\r
+        skipFract += nominalSkip;   // real skip size\r
+        ovlSkip = (int)skipFract;   // rounded to integer skip\r
+        skipFract -= ovlSkip;       // maintain the fraction part, i.e. real vs. integer skip\r
+        inputBuffer.receiveSamples((uint)ovlSkip);\r
+    }\r
+}\r
+\r
+\r
+// Adds 'numsamples' pcs of samples from the 'samples' memory position into\r
+// the input of the object.\r
+void TDStretch::putSamples(const SAMPLETYPE *samples, uint nSamples)\r
+{\r
+    // Add the samples into the input buffer\r
+    inputBuffer.putSamples(samples, nSamples);\r
+    // Process the samples in input buffer\r
+    processSamples();\r
+}\r
+\r
+\r
+\r
+/// Set new overlap length parameter & reallocate RefMidBuffer if necessary.\r
+void TDStretch::acceptNewOverlapLength(int newOverlapLength)\r
+{\r
+    int prevOvl;\r
+\r
+    assert(newOverlapLength >= 0);\r
+    prevOvl = overlapLength;\r
+    overlapLength = newOverlapLength;\r
+\r
+    if (overlapLength > prevOvl)\r
+    {\r
+        delete[] pMidBufferUnaligned;\r
+\r
+        pMidBufferUnaligned = new SAMPLETYPE[overlapLength * channels + 16 / sizeof(SAMPLETYPE)];\r
+        // ensure that 'pMidBuffer' is aligned to 16 byte boundary for efficiency\r
+        pMidBuffer = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(pMidBufferUnaligned);\r
+\r
+        clearMidBuffer();\r
+    }\r
+}\r
+\r
+\r
+// Operator 'new' is overloaded so that it automatically creates a suitable instance \r
+// depending on if we've a MMX/SSE/etc-capable CPU available or not.\r
+void * TDStretch::operator new(size_t s)\r
+{\r
+    // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!\r
+    ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!");\r
+    return newInstance();\r
+}\r
+\r
+\r
+TDStretch * TDStretch::newInstance()\r
+{\r
+    uint uExtensions;\r
+\r
+    uExtensions = detectCPUextensions();\r
+\r
+    // Check if MMX/SSE instruction set extensions supported by CPU\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_MMX\r
+    // MMX routines available only with integer sample types\r
+    if (uExtensions & SUPPORT_MMX)\r
+    {\r
+        return ::new TDStretchMMX;\r
+    }\r
+    else\r
+#endif // SOUNDTOUCH_ALLOW_MMX\r
+\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_SSE\r
+    if (uExtensions & SUPPORT_SSE)\r
+    {\r
+        // SSE support\r
+        return ::new TDStretchSSE;\r
+    }\r
+    else\r
+#endif // SOUNDTOUCH_ALLOW_SSE\r
+\r
+    {\r
+        // ISA optimizations not supported, use plain C version\r
+        return ::new TDStretch;\r
+    }\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Integer arithmetic specific algorithm implementations.\r
+//\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+\r
+// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Stereo' \r
+// version of the routine.\r
+void TDStretch::overlapStereo(short *poutput, const short *input) const\r
+{\r
+    int i;\r
+    short temp;\r
+    int cnt2;\r
+\r
+    for (i = 0; i < overlapLength ; i ++) \r
+    {\r
+        temp = (short)(overlapLength - i);\r
+        cnt2 = 2 * i;\r
+        poutput[cnt2] = (input[cnt2] * i + pMidBuffer[cnt2] * temp )  / overlapLength;\r
+        poutput[cnt2 + 1] = (input[cnt2 + 1] * i + pMidBuffer[cnt2 + 1] * temp ) / overlapLength;\r
+    }\r
+}\r
+\r
+\r
+// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Multi'\r
+// version of the routine.\r
+void TDStretch::overlapMulti(SAMPLETYPE *poutput, const SAMPLETYPE *input) const\r
+{\r
+    SAMPLETYPE m1=(SAMPLETYPE)0;\r
+    SAMPLETYPE m2;\r
+    int i=0;\r
+\r
+    for (m2 = (SAMPLETYPE)overlapLength; m2; m2 --)\r
+    {\r
+        for (int c = 0; c < channels; c ++)\r
+        {\r
+            poutput[i] = (input[i] * m1 + pMidBuffer[i] * m2)  / overlapLength;\r
+            i++;\r
+        }\r
+\r
+        m1++;\r
+    }\r
+}\r
+\r
+// Calculates the x having the closest 2^x value for the given value\r
+static int _getClosest2Power(double value)\r
+{\r
+    return (int)(log(value) / log(2.0) + 0.5);\r
+}\r
+\r
+\r
+/// Calculates overlap period length in samples.\r
+/// Integer version rounds overlap length to closest power of 2\r
+/// for a divide scaling operation.\r
+void TDStretch::calculateOverlapLength(int aoverlapMs)\r
+{\r
+    int newOvl;\r
+\r
+    assert(aoverlapMs >= 0);\r
+\r
+    // calculate overlap length so that it's power of 2 - thus it's easy to do\r
+    // integer division by right-shifting. Term "-1" at end is to account for \r
+    // the extra most significatnt bit left unused in result by signed multiplication \r
+    overlapDividerBitsPure = _getClosest2Power((sampleRate * aoverlapMs) / 1000.0) - 1;\r
+    if (overlapDividerBitsPure > 9) overlapDividerBitsPure = 9;\r
+    if (overlapDividerBitsPure < 3) overlapDividerBitsPure = 3;\r
+    newOvl = (int)pow(2.0, (int)overlapDividerBitsPure + 1);    // +1 => account for -1 above\r
+\r
+    acceptNewOverlapLength(newOvl);\r
+\r
+    overlapDividerBitsNorm = overlapDividerBitsPure;\r
+\r
+    // calculate sloping divider so that crosscorrelation operation won't \r
+    // overflow 32-bit register. Max. sum of the crosscorrelation sum without \r
+    // divider would be 2^30*(N^3-N)/3, where N = overlap length\r
+    slopingDivider = (newOvl * newOvl - 1) / 3;\r
+}\r
+\r
+\r
+double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, double &norm)\r
+{\r
+    long corr;\r
+    unsigned long lnorm;\r
+    int i;\r
+\r
+    corr = lnorm = 0;\r
+    // Same routine for stereo and mono. For stereo, unroll loop for better\r
+    // efficiency and gives slightly better resolution against rounding. \r
+    // For mono it same routine, just  unrolls loop by factor of 4\r
+    for (i = 0; i < channels * overlapLength; i += 4) \r
+    {\r
+        corr += (mixingPos[i] * compare[i] + \r
+                 mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;  // notice: do intermediate division here to avoid integer overflow\r
+        corr += (mixingPos[i + 2] * compare[i + 2] + \r
+                mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBitsNorm;\r
+        lnorm += (mixingPos[i] * mixingPos[i] + \r
+                mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm; // notice: do intermediate division here to avoid integer overflow\r
+        lnorm += (mixingPos[i + 2] * mixingPos[i + 2] + \r
+                mixingPos[i + 3] * mixingPos[i + 3]) >> overlapDividerBitsNorm;\r
+    }\r
+\r
+    if (lnorm > maxnorm)\r
+    {\r
+        // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode\r
+        #pragma omp critical\r
+        if (lnorm > maxnorm)\r
+        {\r
+            maxnorm = lnorm;\r
+        }\r
+    }\r
+    // Normalize result by dividing by sqrt(norm) - this step is easiest \r
+    // done using floating point operation\r
+    norm = (double)lnorm;\r
+    return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm);\r
+}\r
+\r
+\r
+/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value\r
+double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm)\r
+{\r
+    long corr;\r
+    unsigned long lnorm;\r
+    int i;\r
+\r
+    // cancel first normalizer tap from previous round\r
+    lnorm = 0;\r
+    for (i = 1; i <= channels; i ++)\r
+    {\r
+        lnorm -= (mixingPos[-i] * mixingPos[-i]) >> overlapDividerBitsNorm;\r
+    }\r
+\r
+    corr = 0;\r
+    // Same routine for stereo and mono. For stereo, unroll loop for better\r
+    // efficiency and gives slightly better resolution against rounding. \r
+    // For mono it same routine, just  unrolls loop by factor of 4\r
+    for (i = 0; i < channels * overlapLength; i += 4) \r
+    {\r
+        corr += (mixingPos[i] * compare[i] + \r
+                 mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;  // notice: do intermediate division here to avoid integer overflow\r
+        corr += (mixingPos[i + 2] * compare[i + 2] + \r
+                 mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBitsNorm;\r
+    }\r
+\r
+    // update normalizer with last samples of this round\r
+    for (int j = 0; j < channels; j ++)\r
+    {\r
+        i --;\r
+        lnorm += (mixingPos[i] * mixingPos[i]) >> overlapDividerBitsNorm;\r
+    }\r
+\r
+    norm += (double)lnorm;\r
+    if (norm > maxnorm)\r
+    {\r
+        maxnorm = (unsigned long)norm;\r
+    }\r
+\r
+    // Normalize result by dividing by sqrt(norm) - this step is easiest \r
+    // done using floating point operation\r
+    return (double)corr / sqrt((norm < 1e-9) ? 1.0 : norm);\r
+}\r
+\r
+#endif // SOUNDTOUCH_INTEGER_SAMPLES\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Floating point arithmetic specific algorithm implementations.\r
+//\r
+\r
+#ifdef SOUNDTOUCH_FLOAT_SAMPLES\r
+\r
+// Overlaps samples in 'midBuffer' with the samples in 'pInput'\r
+void TDStretch::overlapStereo(float *pOutput, const float *pInput) const\r
+{\r
+    int i;\r
+    float fScale;\r
+    float f1;\r
+    float f2;\r
+\r
+    fScale = 1.0f / (float)overlapLength;\r
+\r
+    f1 = 0;\r
+    f2 = 1.0f;\r
+\r
+    for (i = 0; i < 2 * (int)overlapLength ; i += 2) \r
+    {\r
+        pOutput[i + 0] = pInput[i + 0] * f1 + pMidBuffer[i + 0] * f2;\r
+        pOutput[i + 1] = pInput[i + 1] * f1 + pMidBuffer[i + 1] * f2;\r
+\r
+        f1 += fScale;\r
+        f2 -= fScale;\r
+    }\r
+}\r
+\r
+\r
+// Overlaps samples in 'midBuffer' with the samples in 'input'. \r
+void TDStretch::overlapMulti(float *pOutput, const float *pInput) const\r
+{\r
+    int i;\r
+    float fScale;\r
+    float f1;\r
+    float f2;\r
+\r
+    fScale = 1.0f / (float)overlapLength;\r
+\r
+    f1 = 0;\r
+    f2 = 1.0f;\r
+\r
+    i=0;\r
+    for (int i2 = 0; i2 < overlapLength; i2 ++)\r
+    {\r
+        // note: Could optimize this slightly by taking into account that always channels > 2\r
+        for (int c = 0; c < channels; c ++)\r
+        {\r
+            pOutput[i] = pInput[i] * f1 + pMidBuffer[i] * f2;\r
+            i++;\r
+        }\r
+        f1 += fScale;\r
+        f2 -= fScale;\r
+    }\r
+}\r
+\r
+\r
+/// Calculates overlapInMsec period length in samples.\r
+void TDStretch::calculateOverlapLength(int overlapInMsec)\r
+{\r
+    int newOvl;\r
+\r
+    assert(overlapInMsec >= 0);\r
+    newOvl = (sampleRate * overlapInMsec) / 1000;\r
+    if (newOvl < 16) newOvl = 16;\r
+\r
+    // must be divisible by 8\r
+    newOvl -= newOvl % 8;\r
+\r
+    acceptNewOverlapLength(newOvl);\r
+}\r
+\r
+\r
+/// Calculate cross-correlation\r
+double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, double &anorm)\r
+{\r
+    double corr;\r
+    double norm;\r
+    int i;\r
+\r
+    corr = norm = 0;\r
+    // Same routine for stereo and mono. For Stereo, unroll by factor of 2.\r
+    // For mono it's same routine yet unrollsd by factor of 4.\r
+    for (i = 0; i < channels * overlapLength; i += 4) \r
+    {\r
+        corr += mixingPos[i] * compare[i] +\r
+                mixingPos[i + 1] * compare[i + 1];\r
+\r
+        norm += mixingPos[i] * mixingPos[i] + \r
+                mixingPos[i + 1] * mixingPos[i + 1];\r
+\r
+        // unroll the loop for better CPU efficiency:\r
+        corr += mixingPos[i + 2] * compare[i + 2] +\r
+                mixingPos[i + 3] * compare[i + 3];\r
+\r
+        norm += mixingPos[i + 2] * mixingPos[i + 2] +\r
+                mixingPos[i + 3] * mixingPos[i + 3];\r
+    }\r
+\r
+    anorm = norm;\r
+    return corr / sqrt((norm < 1e-9 ? 1.0 : norm));\r
+}\r
+\r
+\r
+/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value\r
+double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm)\r
+{\r
+    double corr;\r
+    int i;\r
+\r
+    corr = 0;\r
+\r
+    // cancel first normalizer tap from previous round\r
+    for (i = 1; i <= channels; i ++)\r
+    {\r
+        norm -= mixingPos[-i] * mixingPos[-i];\r
+    }\r
+\r
+    // Same routine for stereo and mono. For Stereo, unroll by factor of 2.\r
+    // For mono it's same routine yet unrollsd by factor of 4.\r
+    for (i = 0; i < channels * overlapLength; i += 4) \r
+    {\r
+        corr += mixingPos[i] * compare[i] +\r
+                mixingPos[i + 1] * compare[i + 1] +\r
+                mixingPos[i + 2] * compare[i + 2] +\r
+                mixingPos[i + 3] * compare[i + 3];\r
+    }\r
+\r
+    // update normalizer with last samples of this round\r
+    for (int j = 0; j < channels; j ++)\r
+    {\r
+        i --;\r
+        norm += mixingPos[i] * mixingPos[i];\r
+    }\r
+\r
+    return corr / sqrt((norm < 1e-9 ? 1.0 : norm));\r
+}\r
+\r
+\r
+#endif // SOUNDTOUCH_FLOAT_SAMPLES\r
diff --git a/source/SoundTouch/TDStretch.h b/source/SoundTouch/TDStretch.h
new file mode 100644 (file)
index 0000000..4118f9f
--- /dev/null
@@ -0,0 +1,279 @@
+////////////////////////////////////////////////////////////////////////////////\r
+/// \r
+/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo \r
+/// while maintaining the original pitch by using a time domain WSOLA-like method \r
+/// with several performance-increasing tweaks.\r
+///\r
+/// Note : MMX/SSE optimized functions reside in separate, platform-specific files \r
+/// 'mmx_optimized.cpp' and 'sse_optimized.cpp'\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef TDStretch_H\r
+#define TDStretch_H\r
+\r
+#include <stddef.h>\r
+#include "STTypes.h"\r
+#include "RateTransposer.h"\r
+#include "FIFOSamplePipe.h"\r
+\r
+namespace soundtouch\r
+{\r
+\r
+/// Default values for sound processing parameters:\r
+/// Notice that the default parameters are tuned for contemporary popular music \r
+/// processing. For speech processing applications these parameters suit better:\r
+///     #define DEFAULT_SEQUENCE_MS     40\r
+///     #define DEFAULT_SEEKWINDOW_MS   15\r
+///     #define DEFAULT_OVERLAP_MS      8\r
+///\r
+\r
+/// Default length of a single processing sequence, in milliseconds. This determines to how \r
+/// long sequences the original sound is chopped in the time-stretch algorithm.\r
+///\r
+/// The larger this value is, the lesser sequences are used in processing. In principle\r
+/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo\r
+/// and vice versa.\r
+///\r
+/// Increasing this value reduces computational burden & vice versa.\r
+//#define DEFAULT_SEQUENCE_MS         40\r
+#define DEFAULT_SEQUENCE_MS         USE_AUTO_SEQUENCE_LEN\r
+\r
+/// Giving this value for the sequence length sets automatic parameter value\r
+/// according to tempo setting (recommended)\r
+#define USE_AUTO_SEQUENCE_LEN       0\r
+\r
+/// Seeking window default length in milliseconds for algorithm that finds the best possible \r
+/// overlapping location. This determines from how wide window the algorithm may look for an \r
+/// optimal joining location when mixing the sound sequences back together. \r
+///\r
+/// The bigger this window setting is, the higher the possibility to find a better mixing\r
+/// position will become, but at the same time large values may cause a "drifting" artifact\r
+/// because consequent sequences will be taken at more uneven intervals.\r
+///\r
+/// If there's a disturbing artifact that sounds as if a constant frequency was drifting \r
+/// around, try reducing this setting.\r
+///\r
+/// Increasing this value increases computational burden & vice versa.\r
+//#define DEFAULT_SEEKWINDOW_MS       15\r
+#define DEFAULT_SEEKWINDOW_MS       USE_AUTO_SEEKWINDOW_LEN\r
+\r
+/// Giving this value for the seek window length sets automatic parameter value\r
+/// according to tempo setting (recommended)\r
+#define USE_AUTO_SEEKWINDOW_LEN     0\r
+\r
+/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together, \r
+/// to form a continuous sound stream, this parameter defines over how long period the two \r
+/// consecutive sequences are let to overlap each other. \r
+///\r
+/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting \r
+/// by a large amount, you might wish to try a smaller value on this.\r
+///\r
+/// Increasing this value increases computational burden & vice versa.\r
+#define DEFAULT_OVERLAP_MS      8\r
+\r
+\r
+/// Class that does the time-stretch (tempo change) effect for the processed\r
+/// sound.\r
+class TDStretch : public FIFOProcessor\r
+{\r
+protected:\r
+    int channels;\r
+    int sampleReq;\r
+\r
+    int overlapLength;\r
+    int seekLength;\r
+    int seekWindowLength;\r
+    int overlapDividerBitsNorm;\r
+    int overlapDividerBitsPure;\r
+    int slopingDivider;\r
+    int sampleRate;\r
+    int sequenceMs;\r
+    int seekWindowMs;\r
+    int overlapMs;\r
+\r
+    unsigned long maxnorm;\r
+    float maxnormf;\r
+\r
+    double tempo;\r
+    double nominalSkip;\r
+    double skipFract;\r
+\r
+    bool bQuickSeek;\r
+    bool bAutoSeqSetting;\r
+    bool bAutoSeekSetting;\r
+    bool isBeginning;\r
+\r
+    SAMPLETYPE *pMidBuffer;\r
+    SAMPLETYPE *pMidBufferUnaligned;\r
+\r
+    FIFOSampleBuffer outputBuffer;\r
+    FIFOSampleBuffer inputBuffer;\r
+\r
+    void acceptNewOverlapLength(int newOverlapLength);\r
+\r
+    virtual void clearCrossCorrState();\r
+    void calculateOverlapLength(int overlapMs);\r
+\r
+    virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);\r
+    virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);\r
+\r
+    virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos);\r
+    virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos);\r
+    virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos);\r
+\r
+    virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;\r
+    virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;\r
+    virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const;\r
+\r
+    void clearMidBuffer();\r
+    void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;\r
+\r
+    void calcSeqParameters();\r
+    void adaptNormalizer();\r
+\r
+    /// Changes the tempo of the given sound samples.\r
+    /// Returns amount of samples returned in the "output" buffer.\r
+    /// The maximum amount of samples that can be returned at a time is set by\r
+    /// the 'set_returnBuffer_size' function.\r
+    void processSamples();\r
+    \r
+public:\r
+    TDStretch();\r
+    virtual ~TDStretch();\r
+\r
+    /// Operator 'new' is overloaded so that it automatically creates a suitable instance \r
+    /// depending on if we've a MMX/SSE/etc-capable CPU available or not.\r
+    static void *operator new(size_t s);\r
+\r
+    /// Use this function instead of "new" operator to create a new instance of this class. \r
+    /// This function automatically chooses a correct feature set depending on if the CPU\r
+    /// supports MMX/SSE/etc extensions.\r
+    static TDStretch *newInstance();\r
+    \r
+    /// Returns the output buffer object\r
+    FIFOSamplePipe *getOutput() { return &outputBuffer; };\r
+\r
+    /// Returns the input buffer object\r
+    FIFOSamplePipe *getInput() { return &inputBuffer; };\r
+\r
+    /// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower \r
+    /// tempo, larger faster tempo.\r
+    void setTempo(double newTempo);\r
+\r
+    /// Returns nonzero if there aren't any samples available for outputting.\r
+    virtual void clear();\r
+\r
+    /// Clears the input buffer\r
+    void clearInput();\r
+\r
+    /// Sets the number of channels, 1 = mono, 2 = stereo\r
+    void setChannels(int numChannels);\r
+\r
+    /// Enables/disables the quick position seeking algorithm. Zero to disable, \r
+    /// nonzero to enable\r
+    void enableQuickSeek(bool enable);\r
+\r
+    /// Returns nonzero if the quick seeking algorithm is enabled.\r
+    bool isQuickSeekEnabled() const;\r
+\r
+    /// Sets routine control parameters. These control are certain time constants\r
+    /// defining how the sound is stretched to the desired duration.\r
+    //\r
+    /// 'sampleRate' = sample rate of the sound\r
+    /// 'sequenceMS' = one processing sequence length in milliseconds\r
+    /// 'seekwindowMS' = seeking window length for scanning the best overlapping \r
+    ///      position\r
+    /// 'overlapMS' = overlapping length\r
+    void setParameters(int sampleRate,          ///< Samplerate of sound being processed (Hz)\r
+                       int sequenceMS = -1,     ///< Single processing sequence length (ms)\r
+                       int seekwindowMS = -1,   ///< Offset seeking window length (ms)\r
+                       int overlapMS = -1       ///< Sequence overlapping length (ms)\r
+                       );\r
+\r
+    /// Get routine control parameters, see setParameters() function.\r
+    /// Any of the parameters to this function can be NULL, in such case corresponding parameter\r
+    /// value isn't returned.\r
+    void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;\r
+\r
+    /// Adds 'numsamples' pcs of samples from the 'samples' memory position into\r
+    /// the input of the object.\r
+    virtual void putSamples(\r
+            const SAMPLETYPE *samples,  ///< Input sample data\r
+            uint numSamples                         ///< Number of samples in 'samples' so that one sample\r
+                                                    ///< contains both channels if stereo\r
+            );\r
+\r
+    /// return nominal input sample requirement for triggering a processing batch\r
+    int getInputSampleReq() const\r
+    {\r
+        return (int)(nominalSkip + 0.5);\r
+    }\r
+\r
+    /// return nominal output sample amount when running a processing batch\r
+    int getOutputBatchSize() const\r
+    {\r
+        return seekWindowLength - overlapLength;\r
+    }\r
+\r
+       /// return approximate initial input-output latency\r
+       int getLatency() const\r
+       {\r
+               return sampleReq;\r
+       }\r
+};\r
+\r
+\r
+// Implementation-specific class declarations:\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_MMX\r
+    /// Class that implements MMX optimized routines for 16bit integer samples type.\r
+    class TDStretchMMX : public TDStretch\r
+    {\r
+    protected:\r
+        double calcCrossCorr(const short *mixingPos, const short *compare, double &norm);\r
+        double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm);\r
+        virtual void overlapStereo(short *output, const short *input) const;\r
+        virtual void clearCrossCorrState();\r
+    };\r
+#endif /// SOUNDTOUCH_ALLOW_MMX\r
+\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_SSE\r
+    /// Class that implements SSE optimized routines for floating point samples type.\r
+    class TDStretchSSE : public TDStretch\r
+    {\r
+    protected:\r
+        double calcCrossCorr(const float *mixingPos, const float *compare, double &norm);\r
+        double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm);\r
+    };\r
+\r
+#endif /// SOUNDTOUCH_ALLOW_SSE\r
+\r
+}\r
+#endif  /// TDStretch_H\r
diff --git a/source/SoundTouch/cpu_detect.h b/source/SoundTouch/cpu_detect.h
new file mode 100644 (file)
index 0000000..0cdc223
--- /dev/null
@@ -0,0 +1,55 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// A header file for detecting the Intel MMX instructions set extension.\r
+///\r
+/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the \r
+/// routine implementations for x86 Windows, x86 gnu version and non-x86 \r
+/// platforms, respectively.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _CPU_DETECT_H_\r
+#define _CPU_DETECT_H_\r
+\r
+#include "STTypes.h"\r
+\r
+#define SUPPORT_MMX         0x0001\r
+#define SUPPORT_3DNOW       0x0002\r
+#define SUPPORT_ALTIVEC     0x0004\r
+#define SUPPORT_SSE         0x0008\r
+#define SUPPORT_SSE2        0x0010\r
+\r
+/// Checks which instruction set extensions are supported by the CPU.\r
+///\r
+/// \return A bitmask of supported extensions, see SUPPORT_... defines.\r
+uint detectCPUextensions(void);\r
+\r
+/// Disables given set of instruction extensions. See SUPPORT_... defines.\r
+void disableExtensions(uint wDisableMask);\r
+\r
+#endif  // _CPU_DETECT_H_\r
diff --git a/source/SoundTouch/cpu_detect_x86.cpp b/source/SoundTouch/cpu_detect_x86.cpp
new file mode 100644 (file)
index 0000000..b128610
--- /dev/null
@@ -0,0 +1,130 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// Generic version of the x86 CPU extension detection routine.\r
+///\r
+/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp' \r
+/// for the Microsoft compiler version.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "cpu_detect.h"\r
+#include "STTypes.h"\r
+\r
+\r
+#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)\r
+\r
+   #if defined(__GNUC__) && defined(__i386__)\r
+       // gcc\r
+       #include "cpuid.h"\r
+   #elif defined(_M_IX86)\r
+       // windows non-gcc\r
+       #include <intrin.h>\r
+   #endif\r
+\r
+   #define bit_MMX     (1 << 23)\r
+   #define bit_SSE     (1 << 25)\r
+   #define bit_SSE2    (1 << 26)\r
+#endif\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// processor instructions extension detection routines\r
+//\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+// Flag variable indicating whick ISA extensions are disabled (for debugging)\r
+static uint _dwDisabledISA = 0x00;      // 0xffffffff; //<- use this to disable all extensions\r
+\r
+// Disables given set of instruction extensions. See SUPPORT_... defines.\r
+void disableExtensions(uint dwDisableMask)\r
+{\r
+    _dwDisabledISA = dwDisableMask;\r
+}\r
+\r
+\r
+/// Checks which instruction set extensions are supported by the CPU.\r
+uint detectCPUextensions(void)\r
+{\r
+/// If building for a 64bit system (no Itanium) and the user wants optimizations.\r
+/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19.\r
+/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).\r
+#if ((defined(__GNUC__) && defined(__x86_64__)) \\r
+    || defined(_M_X64))  \\r
+    && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)\r
+    return 0x19 & ~_dwDisabledISA;\r
+\r
+/// If building for a 32bit system and the user wants optimizations.\r
+/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).\r
+#elif ((defined(__GNUC__) && defined(__i386__)) \\r
+    || defined(_M_IX86))  \\r
+    && defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)\r
+\r
+    if (_dwDisabledISA == 0xffffffff) return 0;\r
\r
+    uint res = 0;\r
\r
+#if defined(__GNUC__)\r
+    // GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support.\r
+    uint eax, ebx, ecx, edx;  // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable.\r
+\r
+    // Check if no cpuid support.\r
+    if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions.\r
+\r
+    if (edx & bit_MMX)  res = res | SUPPORT_MMX;\r
+    if (edx & bit_SSE)  res = res | SUPPORT_SSE;\r
+    if (edx & bit_SSE2) res = res | SUPPORT_SSE2;\r
+\r
+#else\r
+    // Window / VS version of cpuid. Notice that Visual Studio 2005 or later required \r
+    // for __cpuid intrinsic support.\r
+    int reg[4] = {-1};\r
+\r
+    // Check if no cpuid support.\r
+    __cpuid(reg,0);\r
+    if ((unsigned int)reg[0] == 0) return 0; // always disable extensions.\r
+\r
+    __cpuid(reg,1);\r
+    if ((unsigned int)reg[3] & bit_MMX)  res = res | SUPPORT_MMX;\r
+    if ((unsigned int)reg[3] & bit_SSE)  res = res | SUPPORT_SSE;\r
+    if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2;\r
+\r
+#endif\r
+\r
+    return res & ~_dwDisabledISA;\r
+\r
+#else\r
+\r
+/// One of these is true:\r
+/// 1) We don't want optimizations.\r
+/// 2) Using an unsupported compiler.\r
+/// 3) Running on a non-x86 platform.\r
+    return 0;\r
+\r
+#endif\r
+}\r
diff --git a/source/SoundTouch/mmx_optimized.cpp b/source/SoundTouch/mmx_optimized.cpp
new file mode 100644 (file)
index 0000000..741ba4f
--- /dev/null
@@ -0,0 +1,396 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// MMX optimized routines. All MMX optimized functions have been gathered into \r
+/// this single source code file, regardless to their class or original source \r
+/// code file, in order to ease porting the library to other compiler and \r
+/// processor platforms.\r
+///\r
+/// The MMX-optimizations are programmed using MMX compiler intrinsics that\r
+/// are supported both by Microsoft Visual C++ and GCC compilers, so this file\r
+/// should compile with both toolsets.\r
+///\r
+/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ \r
+/// 6.0 processor pack" update to support compiler intrinsic syntax. The update\r
+/// is available for download at Microsoft Developers Network, see here:\r
+/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "STTypes.h"\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_MMX\r
+// MMX routines available only with integer sample type\r
+\r
+using namespace soundtouch;\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// implementation of MMX optimized functions of class 'TDStretchMMX'\r
+//\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "TDStretch.h"\r
+#include <mmintrin.h>\r
+#include <limits.h>\r
+#include <math.h>\r
+\r
+\r
+// Calculates cross correlation of two buffers\r
+double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm)\r
+{\r
+    const __m64 *pVec1, *pVec2;\r
+    __m64 shifter;\r
+    __m64 accu, normaccu;\r
+    long corr, norm;\r
+    int i;\r
+   \r
+    pVec1 = (__m64*)pV1;\r
+    pVec2 = (__m64*)pV2;\r
+\r
+    shifter = _m_from_int(overlapDividerBitsNorm);\r
+    normaccu = accu = _mm_setzero_si64();\r
+\r
+    // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples \r
+    // during each round for improved CPU-level parallellization.\r
+    for (i = 0; i < channels * overlapLength / 16; i ++)\r
+    {\r
+        __m64 temp, temp2;\r
+\r
+        // dictionary of instructions:\r
+        // _m_pmaddwd   : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]\r
+        // _mm_add_pi32 : 2*32bit add\r
+        // _m_psrad     : 32bit right-shift\r
+\r
+        temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter),\r
+                            _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter));\r
+        temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), shifter),\r
+                            _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec1[1]), shifter));\r
+        accu = _mm_add_pi32(accu, temp);\r
+        normaccu = _mm_add_pi32(normaccu, temp2);\r
+\r
+        temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter),\r
+                            _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter));\r
+        temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), shifter),\r
+                            _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec1[3]), shifter));\r
+        accu = _mm_add_pi32(accu, temp);\r
+        normaccu = _mm_add_pi32(normaccu, temp2);\r
+\r
+        pVec1 += 4;\r
+        pVec2 += 4;\r
+    }\r
+\r
+    // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1\r
+    // and finally store the result into the variable "corr"\r
+\r
+    accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));\r
+    corr = _m_to_int(accu);\r
+\r
+    normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32));\r
+    norm = _m_to_int(normaccu);\r
+\r
+    // Clear MMS state\r
+    _m_empty();\r
+\r
+    if (norm > (long)maxnorm)\r
+    {\r
+        // modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode\r
+        #pragma omp critical\r
+        if (norm > (long)maxnorm)\r
+        {\r
+            maxnorm = norm;\r
+        }\r
+    }\r
+\r
+    // Normalize result by dividing by sqrt(norm) - this step is easiest \r
+    // done using floating point operation\r
+    dnorm = (double)norm;\r
+\r
+    return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm);\r
+    // Note: Warning about the missing EMMS instruction is harmless\r
+    // as it'll be called elsewhere.\r
+}\r
+\r
+\r
+/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value\r
+double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm)\r
+{\r
+    const __m64 *pVec1, *pVec2;\r
+    __m64 shifter;\r
+    __m64 accu;\r
+    long corr, lnorm;\r
+    int i;\r
+   \r
+    // cancel first normalizer tap from previous round\r
+    lnorm = 0;\r
+    for (i = 1; i <= channels; i ++)\r
+    {\r
+        lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBitsNorm;\r
+    }\r
+\r
+    pVec1 = (__m64*)pV1;\r
+    pVec2 = (__m64*)pV2;\r
+\r
+    shifter = _m_from_int(overlapDividerBitsNorm);\r
+    accu = _mm_setzero_si64();\r
+\r
+    // Process 4 parallel sets of 2 * stereo samples or 4 * mono samples \r
+    // during each round for improved CPU-level parallellization.\r
+    for (i = 0; i < channels * overlapLength / 16; i ++)\r
+    {\r
+        __m64 temp;\r
+\r
+        // dictionary of instructions:\r
+        // _m_pmaddwd   : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]\r
+        // _mm_add_pi32 : 2*32bit add\r
+        // _m_psrad     : 32bit right-shift\r
+\r
+        temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter),\r
+                            _mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter));\r
+        accu = _mm_add_pi32(accu, temp);\r
+\r
+        temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter),\r
+                            _mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter));\r
+        accu = _mm_add_pi32(accu, temp);\r
+\r
+        pVec1 += 4;\r
+        pVec2 += 4;\r
+    }\r
+\r
+    // copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1\r
+    // and finally store the result into the variable "corr"\r
+\r
+    accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));\r
+    corr = _m_to_int(accu);\r
+\r
+    // Clear MMS state\r
+    _m_empty();\r
+\r
+    // update normalizer with last samples of this round\r
+    pV1 = (short *)pVec1;\r
+    for (int j = 1; j <= channels; j ++)\r
+    {\r
+        lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBitsNorm;\r
+    }\r
+    dnorm += (double)lnorm;\r
+\r
+    if (lnorm > (long)maxnorm)\r
+    {\r
+        maxnorm = lnorm;\r
+    }\r
+\r
+    // Normalize result by dividing by sqrt(norm) - this step is easiest \r
+    // done using floating point operation\r
+    return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm);\r
+}\r
+\r
+\r
+void TDStretchMMX::clearCrossCorrState()\r
+{\r
+    // Clear MMS state\r
+    _m_empty();\r
+    //_asm EMMS;\r
+}\r
+\r
+\r
+// MMX-optimized version of the function overlapStereo\r
+void TDStretchMMX::overlapStereo(short *output, const short *input) const\r
+{\r
+    const __m64 *pVinput, *pVMidBuf;\r
+    __m64 *pVdest;\r
+    __m64 mix1, mix2, adder, shifter;\r
+    int i;\r
+\r
+    pVinput  = (const __m64*)input;\r
+    pVMidBuf = (const __m64*)pMidBuffer;\r
+    pVdest   = (__m64*)output;\r
+\r
+    // mix1  = mixer values for 1st stereo sample\r
+    // mix1  = mixer values for 2nd stereo sample\r
+    // adder = adder for updating mixer values after each round\r
+    \r
+    mix1  = _mm_set_pi16(0, overlapLength,   0, overlapLength);\r
+    adder = _mm_set_pi16(1, -1, 1, -1);\r
+    mix2  = _mm_add_pi16(mix1, adder);\r
+    adder = _mm_add_pi16(adder, adder);\r
+\r
+    // Overlaplength-division by shifter. "+1" is to account for "-1" deduced in\r
+    // overlapDividerBits calculation earlier.\r
+    shifter = _m_from_int(overlapDividerBitsPure + 1);\r
+\r
+    for (i = 0; i < overlapLength / 4; i ++)\r
+    {\r
+        __m64 temp1, temp2;\r
+                \r
+        // load & shuffle data so that input & mixbuffer data samples are paired\r
+        temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]);     // = i0l m0l i0r m0r\r
+        temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]);     // = i1l m1l i1r m1r\r
+\r
+        // temp = (temp .* mix) >> shifter\r
+        temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);\r
+        temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);\r
+        pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit\r
+\r
+        // update mix += adder\r
+        mix1 = _mm_add_pi16(mix1, adder);\r
+        mix2 = _mm_add_pi16(mix2, adder);\r
+\r
+        // --- second round begins here ---\r
+\r
+        // load & shuffle data so that input & mixbuffer data samples are paired\r
+        temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]);       // = i2l m2l i2r m2r\r
+        temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]);       // = i3l m3l i3r m3r\r
+\r
+        // temp = (temp .* mix) >> shifter\r
+        temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);\r
+        temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);\r
+        pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit\r
+\r
+        // update mix += adder\r
+        mix1 = _mm_add_pi16(mix1, adder);\r
+        mix2 = _mm_add_pi16(mix2, adder);\r
+\r
+        pVinput  += 2;\r
+        pVMidBuf += 2;\r
+        pVdest   += 2;\r
+    }\r
+\r
+    _m_empty(); // clear MMS state\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// implementation of MMX optimized functions of class 'FIRFilter'\r
+//\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "FIRFilter.h"\r
+\r
+\r
+FIRFilterMMX::FIRFilterMMX() : FIRFilter()\r
+{\r
+    filterCoeffsAlign = NULL;\r
+    filterCoeffsUnalign = NULL;\r
+}\r
+\r
+\r
+FIRFilterMMX::~FIRFilterMMX()\r
+{\r
+    delete[] filterCoeffsUnalign;\r
+}\r
+\r
+\r
+// (overloaded) Calculates filter coefficients for MMX routine\r
+void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)\r
+{\r
+    uint i;\r
+    FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);\r
+\r
+    // Ensure that filter coeffs array is aligned to 16-byte boundary\r
+    delete[] filterCoeffsUnalign;\r
+    filterCoeffsUnalign = new short[2 * newLength + 8];\r
+    filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);\r
+\r
+    // rearrange the filter coefficients for mmx routines \r
+    for (i = 0;i < length; i += 4) \r
+    {\r
+        filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];\r
+        filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];\r
+        filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];\r
+        filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];\r
+\r
+        filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];\r
+        filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];\r
+        filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];\r
+        filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];\r
+    }\r
+}\r
+\r
+\r
+// mmx-optimized version of the filter routine for stereo sound\r
+uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const\r
+{\r
+    // Create stack copies of the needed member variables for asm routines :\r
+    uint i, j;\r
+    __m64 *pVdest = (__m64*)dest;\r
+\r
+    if (length < 2) return 0;\r
+\r
+    for (i = 0; i < (numSamples - length) / 2; i ++)\r
+    {\r
+        __m64 accu1;\r
+        __m64 accu2;\r
+        const __m64 *pVsrc = (const __m64*)src;\r
+        const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;\r
+\r
+        accu1 = accu2 = _mm_setzero_si64();\r
+        for (j = 0; j < lengthDiv8 * 2; j ++)\r
+        {\r
+            __m64 temp1, temp2;\r
+\r
+            temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]);  // = l2 l0 r2 r0\r
+            temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]);  // = l3 l1 r3 r1\r
+\r
+            accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0]));  // += l2*f2+l0*f0 r2*f2+r0*f0\r
+            accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1]));  // += l3*f3+l1*f1 r3*f3+r1*f1\r
+\r
+            temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]);  // = l4 l2 r4 r2\r
+\r
+            accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0]));  // += l3*f2+l1*f0 r3*f2+r1*f0\r
+            accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1]));  // += l4*f3+l2*f1 r4*f3+r2*f1\r
+\r
+            // accu1 += l2*f2+l0*f0 r2*f2+r0*f0\r
+            //       += l3*f3+l1*f1 r3*f3+r1*f1\r
+\r
+            // accu2 += l3*f2+l1*f0 r3*f2+r1*f0\r
+            //          l4*f3+l2*f1 r4*f3+r2*f1\r
+\r
+            pVfilter += 2;\r
+            pVsrc += 2;\r
+        }\r
+        // accu >>= resultDivFactor\r
+        accu1 = _mm_srai_pi32(accu1, resultDivFactor);\r
+        accu2 = _mm_srai_pi32(accu2, resultDivFactor);\r
+\r
+        // pack 2*2*32bits => 4*16 bits\r
+        pVdest[0] = _mm_packs_pi32(accu1, accu2);\r
+        src += 4;\r
+        pVdest ++;\r
+    }\r
+\r
+   _m_empty();  // clear emms state\r
+\r
+    return (numSamples & 0xfffffffe) - length;\r
+}\r
+\r
+#else\r
+\r
+// workaround to not complain about empty module\r
+bool _dontcomplain_mmx_empty;\r
+\r
+#endif  // SOUNDTOUCH_ALLOW_MMX\r
diff --git a/source/SoundTouch/sse_optimized.cpp b/source/SoundTouch/sse_optimized.cpp
new file mode 100644 (file)
index 0000000..0dc6370
--- /dev/null
@@ -0,0 +1,365 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE \r
+/// optimized functions have been gathered into this single source \r
+/// code file, regardless to their class or original source code file, in order \r
+/// to ease porting the library to other compiler and processor platforms.\r
+///\r
+/// The SSE-optimizations are programmed using SSE compiler intrinsics that\r
+/// are supported both by Microsoft Visual C++ and GCC compilers, so this file\r
+/// should compile with both toolsets.\r
+///\r
+/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++ \r
+/// 6.0 processor pack" update to support SSE instruction set. The update is \r
+/// available for download at Microsoft Developers Network, see here:\r
+/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx\r
+///\r
+/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and \r
+/// perform a search with keywords "processor pack".\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "cpu_detect.h"\r
+#include "STTypes.h"\r
+\r
+using namespace soundtouch;\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_SSE\r
+\r
+// SSE routines available only with float sample type    \r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// implementation of SSE optimized functions of class 'TDStretchSSE'\r
+//\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "TDStretch.h"\r
+#include <xmmintrin.h>\r
+#include <math.h>\r
+\r
+// Calculates cross correlation of two buffers\r
+double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm)\r
+{\r
+    int i;\r
+    const float *pVec1;\r
+    const __m128 *pVec2;\r
+    __m128 vSum, vNorm;\r
+\r
+    // Note. It means a major slow-down if the routine needs to tolerate \r
+    // unaligned __m128 memory accesses. It's way faster if we can skip \r
+    // unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.\r
+    // This can mean up to ~ 10-fold difference (incl. part of which is\r
+    // due to skipping every second round for stereo sound though).\r
+    //\r
+    // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided\r
+    // for choosing if this little cheating is allowed.\r
+\r
+#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION\r
+    // Little cheating allowed, return valid correlation only for \r
+    // aligned locations, meaning every second round for stereo sound.\r
+\r
+    #define _MM_LOAD    _mm_load_ps\r
+\r
+    if (((ulongptr)pV1) & 15) return -1e50;    // skip unaligned locations\r
+\r
+#else\r
+    // No cheating allowed, use unaligned load & take the resulting\r
+    // performance hit.\r
+    #define _MM_LOAD    _mm_loadu_ps\r
+#endif \r
+\r
+    // ensure overlapLength is divisible by 8\r
+    assert((overlapLength % 8) == 0);\r
+\r
+    // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors\r
+    // Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.\r
+    pVec1 = (const float*)pV1;\r
+    pVec2 = (const __m128*)pV2;\r
+    vSum = vNorm = _mm_setzero_ps();\r
+\r
+    // Unroll the loop by factor of 4 * 4 operations. Use same routine for\r
+    // stereo & mono, for mono it just means twice the amount of unrolling.\r
+    for (i = 0; i < channels * overlapLength / 16; i ++) \r
+    {\r
+        __m128 vTemp;\r
+        // vSum += pV1[0..3] * pV2[0..3]\r
+        vTemp = _MM_LOAD(pVec1);\r
+        vSum  = _mm_add_ps(vSum,  _mm_mul_ps(vTemp ,pVec2[0]));\r
+        vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));\r
+\r
+        // vSum += pV1[4..7] * pV2[4..7]\r
+        vTemp = _MM_LOAD(pVec1 + 4);\r
+        vSum  = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1]));\r
+        vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));\r
+\r
+        // vSum += pV1[8..11] * pV2[8..11]\r
+        vTemp = _MM_LOAD(pVec1 + 8);\r
+        vSum  = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2]));\r
+        vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));\r
+\r
+        // vSum += pV1[12..15] * pV2[12..15]\r
+        vTemp = _MM_LOAD(pVec1 + 12);\r
+        vSum  = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3]));\r
+        vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));\r
+\r
+        pVec1 += 16;\r
+        pVec2 += 4;\r
+    }\r
+\r
+    // return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]\r
+    float *pvNorm = (float*)&vNorm;\r
+    float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]);\r
+    anorm = norm;\r
+\r
+    float *pvSum = (float*)&vSum;\r
+    return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm);\r
+\r
+    /* This is approximately corresponding routine in C-language yet without normalization:\r
+    double corr, norm;\r
+    uint i;\r
+\r
+    // Calculates the cross-correlation value between 'pV1' and 'pV2' vectors\r
+    corr = norm = 0.0;\r
+    for (i = 0; i < channels * overlapLength / 16; i ++) \r
+    {\r
+        corr += pV1[0] * pV2[0] +\r
+                pV1[1] * pV2[1] +\r
+                pV1[2] * pV2[2] +\r
+                pV1[3] * pV2[3] +\r
+                pV1[4] * pV2[4] +\r
+                pV1[5] * pV2[5] +\r
+                pV1[6] * pV2[6] +\r
+                pV1[7] * pV2[7] +\r
+                pV1[8] * pV2[8] +\r
+                pV1[9] * pV2[9] +\r
+                pV1[10] * pV2[10] +\r
+                pV1[11] * pV2[11] +\r
+                pV1[12] * pV2[12] +\r
+                pV1[13] * pV2[13] +\r
+                pV1[14] * pV2[14] +\r
+                pV1[15] * pV2[15];\r
+\r
+    for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j];\r
+\r
+        pV1 += 16;\r
+        pV2 += 16;\r
+    }\r
+    return corr / sqrt(norm);\r
+    */\r
+}\r
+\r
+\r
+\r
+double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm)\r
+{\r
+    // call usual calcCrossCorr function because SSE does not show big benefit of \r
+    // accumulating "norm" value, and also the "norm" rolling algorithm would get \r
+    // complicated due to SSE-specific alignment-vs-nonexact correlation rules.\r
+    return calcCrossCorr(pV1, pV2, norm);\r
+}\r
+\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// implementation of SSE optimized functions of class 'FIRFilter'\r
+//\r
+//////////////////////////////////////////////////////////////////////////////\r
+\r
+#include "FIRFilter.h"\r
+\r
+FIRFilterSSE::FIRFilterSSE() : FIRFilter()\r
+{\r
+    filterCoeffsAlign = NULL;\r
+    filterCoeffsUnalign = NULL;\r
+}\r
+\r
+\r
+FIRFilterSSE::~FIRFilterSSE()\r
+{\r
+    delete[] filterCoeffsUnalign;\r
+    filterCoeffsAlign = NULL;\r
+    filterCoeffsUnalign = NULL;\r
+}\r
+\r
+\r
+// (overloaded) Calculates filter coefficients for SSE routine\r
+void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)\r
+{\r
+    uint i;\r
+    float fDivider;\r
+\r
+    FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);\r
+\r
+    // Scale the filter coefficients so that it won't be necessary to scale the filtering result\r
+    // also rearrange coefficients suitably for SSE\r
+    // Ensure that filter coeffs array is aligned to 16-byte boundary\r
+    delete[] filterCoeffsUnalign;\r
+    filterCoeffsUnalign = new float[2 * newLength + 4];\r
+    filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);\r
+\r
+    fDivider = (float)resultDivider;\r
+\r
+    // rearrange the filter coefficients for mmx routines \r
+    for (i = 0; i < newLength; i ++)\r
+    {\r
+        filterCoeffsAlign[2 * i + 0] =\r
+        filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;\r
+    }\r
+}\r
+\r
+\r
+\r
+// SSE-optimized version of the filter routine for stereo sound\r
+uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const\r
+{\r
+    int count = (int)((numSamples - length) & (uint)-2);\r
+    int j;\r
+\r
+    assert(count % 2 == 0);\r
+\r
+    if (count < 2) return 0;\r
+\r
+    assert(source != NULL);\r
+    assert(dest != NULL);\r
+    assert((length % 8) == 0);\r
+    assert(filterCoeffsAlign != NULL);\r
+    assert(((ulongptr)filterCoeffsAlign) % 16 == 0);\r
+\r
+    // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'\r
+    #pragma omp parallel for\r
+    for (j = 0; j < count; j += 2)\r
+    {\r
+        const float *pSrc;\r
+        float *pDest;\r
+        const __m128 *pFil;\r
+        __m128 sum1, sum2;\r
+        uint i;\r
+\r
+        pSrc = (const float*)source + j * 2;      // source audio data\r
+        pDest = dest + j * 2;                     // destination audio data\r
+        pFil = (const __m128*)filterCoeffsAlign;  // filter coefficients. NOTE: Assumes coefficients \r
+                                                  // are aligned to 16-byte boundary\r
+        sum1 = sum2 = _mm_setzero_ps();\r
+\r
+        for (i = 0; i < length / 8; i ++) \r
+        {\r
+            // Unroll loop for efficiency & calculate filter for 2*2 stereo samples \r
+            // at each pass\r
+\r
+            // sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset\r
+            // sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.\r
+\r
+            sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc)    , pFil[0]));\r
+            sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));\r
+\r
+            sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));\r
+            sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));\r
+\r
+            sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) ,  pFil[2]));\r
+            sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));\r
+\r
+            sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));\r
+            sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));\r
+\r
+            pSrc += 16;\r
+            pFil += 4;\r
+        }\r
+\r
+        // Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need\r
+        // to sum the two hi- and lo-floats of these registers together.\r
+\r
+        // post-shuffle & add the filtered values and store to dest.\r
+        _mm_storeu_ps(pDest, _mm_add_ps(\r
+                    _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)),   // s2_1 s2_0 s1_3 s1_2\r
+                    _mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0))    // s2_3 s2_2 s1_1 s1_0\r
+                    ));\r
+    }\r
+\r
+    // Ideas for further improvement:\r
+    // 1. If it could be guaranteed that 'source' were always aligned to 16-byte \r
+    //    boundary, a faster aligned '_mm_load_ps' instruction could be used.\r
+    // 2. If it could be guaranteed that 'dest' were always aligned to 16-byte \r
+    //    boundary, a faster '_mm_store_ps' instruction could be used.\r
+\r
+    return (uint)count;\r
+\r
+    /* original routine in C-language. please notice the C-version has differently \r
+       organized coefficients though.\r
+    double suml1, suml2;\r
+    double sumr1, sumr2;\r
+    uint i, j;\r
+\r
+    for (j = 0; j < count; j += 2)\r
+    {\r
+        const float *ptr;\r
+        const float *pFil;\r
+\r
+        suml1 = sumr1 = 0.0;\r
+        suml2 = sumr2 = 0.0;\r
+        ptr = src;\r
+        pFil = filterCoeffs;\r
+        for (i = 0; i < lengthLocal; i ++) \r
+        {\r
+            // unroll loop for efficiency.\r
+\r
+            suml1 += ptr[0] * pFil[0] + \r
+                     ptr[2] * pFil[2] +\r
+                     ptr[4] * pFil[4] +\r
+                     ptr[6] * pFil[6];\r
+\r
+            sumr1 += ptr[1] * pFil[1] + \r
+                     ptr[3] * pFil[3] +\r
+                     ptr[5] * pFil[5] +\r
+                     ptr[7] * pFil[7];\r
+\r
+            suml2 += ptr[8] * pFil[0] + \r
+                     ptr[10] * pFil[2] +\r
+                     ptr[12] * pFil[4] +\r
+                     ptr[14] * pFil[6];\r
+\r
+            sumr2 += ptr[9] * pFil[1] + \r
+                     ptr[11] * pFil[3] +\r
+                     ptr[13] * pFil[5] +\r
+                     ptr[15] * pFil[7];\r
+\r
+            ptr += 16;\r
+            pFil += 8;\r
+        }\r
+        dest[0] = (float)suml1;\r
+        dest[1] = (float)sumr1;\r
+        dest[2] = (float)suml2;\r
+        dest[3] = (float)sumr2;\r
+\r
+        src += 4;\r
+        dest += 4;\r
+    }\r
+    */\r
+}\r
+\r
+#endif  // SOUNDTOUCH_ALLOW_SSE\r
diff --git a/source/SoundTouchDLL/DllTest/DllTest.cpp b/source/SoundTouchDLL/DllTest/DllTest.cpp
new file mode 100644 (file)
index 0000000..666405d
--- /dev/null
@@ -0,0 +1,114 @@
+////////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// DllTest.cpp : This is small app main routine used for testing sound processing\r
+/// with SoundTouch.dll API\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#include <string>\r
+#include <iostream>\r
+#include <fstream>\r
+#include "../SoundTouchDLL.h"\r
+#include "../../SoundStretch/WavFile.h"\r
+\r
+using namespace std;\r
+\r
+// DllTest main\r
+int main(int argc, char *argv[])\r
+{\r
+    // Check program arguments\r
+    if (argc < 4)\r
+    {\r
+        cout << "Too few arguments. Usage: DllTest [infile.wav] [outfile.wav] [sampletype]" << endl;\r
+        return -1;\r
+    }\r
+\r
+    const char *inFileName = argv[1];\r
+    const char *outFileName = argv[2];\r
+    string str_sampleType = argv[3];\r
+\r
+    bool floatSample;\r
+    if (str_sampleType.compare("float") == 0)\r
+    {\r
+        floatSample = true;\r
+    }\r
+    else if (str_sampleType.compare("short") == 0)\r
+    {\r
+        floatSample = false;\r
+    }\r
+    else\r
+    { \r
+        cerr << "Missing or invalid sampletype '" << str_sampleType << "'. Expected either short or float" << endl;\r
+        return -1;\r
+    }\r
+\r
+    try\r
+    {\r
+        // Open input & output WAV files\r
+        WavInFile inFile(inFileName);\r
+        int numChannels = inFile.getNumChannels();\r
+        int sampleRate = inFile.getSampleRate();\r
+        WavOutFile outFile(outFileName, sampleRate, inFile.getNumBits(), numChannels);\r
+\r
+        // Create SoundTouch DLL instance\r
+        HANDLE st = soundtouch_createInstance();\r
+        soundtouch_setChannels(st, numChannels);\r
+        soundtouch_setSampleRate(st, sampleRate);\r
+        soundtouch_setPitchSemiTones(st, 2);\r
+\r
+        cout << "processing with soundtouch.dll routines";\r
+\r
+        if (floatSample)\r
+        {\r
+            // Process file with SoundTouch.DLL float sample (default) API\r
+            float fbuffer[2048];\r
+            int nmax = 2048 / numChannels;\r
+\r
+            cout << " using float api ..." << endl;\r
+            while (inFile.eof() == false)\r
+            {\r
+                int n = inFile.read(fbuffer, nmax * numChannels) / numChannels;\r
+                soundtouch_putSamples(st, fbuffer, n);\r
+                do\r
+                {\r
+                    n = soundtouch_receiveSamples(st, fbuffer, nmax);\r
+                    outFile.write(fbuffer, n * numChannels);\r
+                } while (n > 0);\r
+            }\r
+        }\r
+        else\r
+        {\r
+            // Process file with SoundTouch.DLL int16 (short) sample API.\r
+            // Notice that SoundTouch.dll does internally processing using floating\r
+            // point routines so the int16 API is not any faster, but provided for \r
+            // convenience.\r
+            short i16buffer[2048];\r
+            int nmax = 2048 / numChannels;\r
+\r
+            cout << " using i16 api ..." << endl;\r
+            while (inFile.eof() == false)\r
+            {\r
+                int n = inFile.read(i16buffer, nmax * numChannels) / numChannels;\r
+                soundtouch_putSamples_i16(st, i16buffer, n);\r
+                do\r
+                {\r
+                    n = soundtouch_receiveSamples_i16(st, i16buffer, nmax);\r
+                    outFile.write(i16buffer, n * numChannels);\r
+                } while (n > 0);\r
+            }\r
+        }\r
+\r
+        soundtouch_destroyInstance(st);\r
+        cout << "done." << endl;\r
+    }\r
+    catch (const runtime_error &e)\r
+    {\r
+        cerr << e.what() << endl;\r
+    }\r
+\r
+    return 0;\r
+}\r
diff --git a/source/SoundTouchDLL/DllTest/DllTest.vcxproj b/source/SoundTouchDLL/DllTest/DllTest.vcxproj
new file mode 100644 (file)
index 0000000..7b025fa
--- /dev/null
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|x64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|x64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{E3C0726F-28F4-4F0B-8183-B87CA60C063C}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>DllTest</RootNamespace>\r
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
+    <ConfigurationType>Application</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>Unicode</CharacterSet>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="Shared">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)D</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <TargetName>$(ProjectName)D_x64</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <TargetName>$(ProjectName)_x64</TargetName>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>\r
+      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalDependencies>..\..\..\lib\SoundTouchDllD.lib</AdditionalDependencies>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>\r
+      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalDependencies>..\..\..\lib\SoundTouchDllD_x64.lib</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>\r
+      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalDependencies>..\..\..\lib\SoundTouchDll.lib</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <ClCompile>\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <FunctionLevelLinking>true</FunctionLevelLinking>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>\r
+      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Console</SubSystem>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <AdditionalDependencies>..\..\..\lib\SoundTouchDll_x64.lib</AdditionalDependencies>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <Text Include="ReadMe.txt" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="stdafx.h" />\r
+    <ClInclude Include="targetver.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="..\..\SoundStretch\WavFile.cpp" />\r
+    <ClCompile Include="DllTest.cpp" />\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>
\ No newline at end of file
diff --git a/source/SoundTouchDLL/SoundTouchDLL.cpp b/source/SoundTouchDLL/SoundTouchDLL.cpp
new file mode 100644 (file)
index 0000000..6b5f4bb
--- /dev/null
@@ -0,0 +1,527 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// SoundTouch DLL wrapper - wraps SoundTouch routines into a Dynamic Load \r
+/// Library interface.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+#if defined(_WIN32) || defined(WIN32)\r
+    #include <windows.h>\r
+\r
+    // DLL main in Windows compilation\r
+    BOOL APIENTRY DllMain( HANDLE hModule,\r
+                           DWORD  ul_reason_for_call,\r
+                           LPVOID lpReserved\r
+                         )\r
+    {\r
+        switch (ul_reason_for_call)\r
+        {\r
+        case DLL_PROCESS_ATTACH:\r
+        case DLL_THREAD_ATTACH:\r
+        case DLL_THREAD_DETACH:\r
+        case DLL_PROCESS_DETACH:\r
+            break;\r
+        }\r
+        return TRUE;\r
+    }\r
+#endif\r
+\r
+#include <limits.h>\r
+#include <string.h>\r
+#include "SoundTouchDLL.h"\r
+#include "SoundTouch.h"\r
+#include "BPMDetect.h"\r
+\r
+using namespace soundtouch;\r
+\r
+#ifdef SOUNDTOUCH_INTEGER_SAMPLES\r
+    #error "error - compile the dll version with float samples"\r
+#endif // SOUNDTOUCH_INTEGER_SAMPLES\r
+\r
+//////////////\r
+\r
+typedef struct\r
+{\r
+    DWORD dwMagic;\r
+    SoundTouch *pst;\r
+} STHANDLE;\r
+\r
+typedef struct\r
+{\r
+    DWORD dwMagic;\r
+    BPMDetect *pbpm;\r
+    uint numChannels;\r
+} BPMHANDLE;\r
+\r
+#define STMAGIC  0x1770C001\r
+#define BPMMAGIC 0x1771C10a\r
+\r
+SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance()\r
+{\r
+    STHANDLE *tmp = new STHANDLE;\r
+\r
+    if (tmp)\r
+    {\r
+        tmp->dwMagic = STMAGIC;\r
+        tmp->pst = new SoundTouch();\r
+        if (tmp->pst == NULL)\r
+        {\r
+            delete tmp;\r
+            tmp = NULL;\r
+        }\r
+    }\r
+    return (HANDLE)tmp;\r
+}\r
+\r
+\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->dwMagic = 0;\r
+    if (sth->pst) delete sth->pst;\r
+    sth->pst = NULL;\r
+    delete sth;\r
+}\r
+\r
+\r
+/// Get SoundTouch library version string\r
+SOUNDTOUCHDLL_API const char *__cdecl soundtouch_getVersionString()\r
+{\r
+    return SoundTouch::getVersionString();\r
+}\r
+\r
+\r
+/// Get SoundTouch library version string - alternative function for \r
+/// environments that can't properly handle character string as return value\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_getVersionString2(char* versionString, int bufferSize)\r
+{\r
+    strncpy(versionString, SoundTouch::getVersionString(), bufferSize - 1);\r
+    versionString[bufferSize - 1] = 0;\r
+}\r
+\r
+\r
+/// Get SoundTouch library version Id\r
+SOUNDTOUCHDLL_API uint __cdecl soundtouch_getVersionId()\r
+{\r
+    return SoundTouch::getVersionId();\r
+}\r
+\r
+/// Sets new rate control value. Normal rate = 1.0, smaller values\r
+/// represent slower rate, larger faster rates.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setRate(HANDLE h, float newRate)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setRate(newRate);\r
+}\r
+\r
+\r
+/// Sets new tempo control value. Normal tempo = 1.0, smaller values\r
+/// represent slower tempo, larger faster tempo.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempo(HANDLE h, float newTempo)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setTempo(newTempo);\r
+}\r
+\r
+/// Sets new rate control value as a difference in percents compared\r
+/// to the original rate (-50 .. +100 %)\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setRateChange(HANDLE h, float newRate)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setRateChange(newRate);\r
+}\r
+\r
+/// Sets new tempo control value as a difference in percents compared\r
+/// to the original tempo (-50 .. +100 %)\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempoChange(HANDLE h, float newTempo)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setTempoChange(newTempo);\r
+}\r
+\r
+/// Sets new pitch control value. Original pitch = 1.0, smaller values\r
+/// represent lower pitches, larger values higher pitch.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitch(HANDLE h, float newPitch)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setPitch(newPitch);\r
+}\r
+\r
+/// Sets pitch change in octaves compared to the original pitch  \r
+/// (-1.00 .. +1.00)\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchOctaves(HANDLE h, float newPitch)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setPitchOctaves(newPitch);\r
+}\r
+\r
+/// Sets pitch change in semi-tones compared to the original pitch\r
+/// (-12 .. +12)\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newPitch)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setPitchSemiTones(newPitch);\r
+}\r
+\r
+\r
+/// Sets the number of channels, 1 = mono, 2 = stereo\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setChannels(HANDLE h, uint numChannels)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setChannels(numChannels);\r
+}\r
+\r
+/// Sets sample rate.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, uint srate)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->setSampleRate(srate);\r
+}\r
+\r
+/// Flushes the last samples from the processing pipeline to the output.\r
+/// Clears also the internal processing buffers.\r
+//\r
+/// Note: This function is meant for extracting the last samples of a sound\r
+/// stream. This function may introduce additional blank samples in the end\r
+/// of the sound stream, and thus it's not recommended to call this function\r
+/// in the middle of a sound stream.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_flush(HANDLE h)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->flush();\r
+}\r
+\r
+/// Adds 'numSamples' pcs of samples from the 'samples' memory position into\r
+/// the input of the object. Notice that sample rate _has_to_ be set before\r
+/// calling this function, otherwise throws a runtime_error exception.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h, \r
+        const SAMPLETYPE *samples,      ///< Pointer to sample buffer.\r
+        unsigned int numSamples         ///< Number of samples in buffer. Notice\r
+                                        ///< that in case of stereo-sound a single sample\r
+                                        ///< contains data for both channels.\r
+        )\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->putSamples(samples, numSamples);\r
+}\r
+\r
+/// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data\r
+/// and internally converts it to float format before processing\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples_i16(HANDLE h,\r
+        const short *samples,       ///< Pointer to sample buffer.\r
+        unsigned int numSamples     ///< Number of sample frames in buffer. Notice\r
+                                    ///< that in case of multi-channel sound a single sample\r
+                                    ///< contains data for all channels.\r
+        )\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    uint numChannels = sth->pst->numChannels();\r
+\r
+    // iterate until all samples converted & put to SoundTouch object\r
+    while (numSamples > 0)\r
+    {\r
+        float convert[8192];    // allocate temporary conversion buffer from stack\r
+\r
+        // how many multichannel samples fit into 'convert' buffer:\r
+        uint convSamples = 8192 / numChannels;\r
+\r
+        // convert max 'nround' values at a time to guarantee that these fit in the 'convert' buffer\r
+        uint n = (numSamples > convSamples) ? convSamples : numSamples;\r
+        for (uint i = 0; i < n * numChannels; i++)\r
+        {\r
+            convert[i] = samples[i];\r
+        }\r
+        // put the converted samples into SoundTouch\r
+        sth->pst->putSamples(convert, n);\r
+\r
+        numSamples -= n;\r
+        samples += n * numChannels;\r
+    }\r
+}\r
+\r
+/// Clears all the samples in the object's output and internal processing\r
+/// buffers.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_clear(HANDLE h)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return;\r
+\r
+    sth->pst->clear();\r
+}\r
+\r
+/// Changes a setting controlling the processing system behaviour. See the\r
+/// 'SETTING_...' defines for available setting ID's.\r
+/// \r
+/// \return 'nonzero' if the setting was successfully changed\r
+SOUNDTOUCHDLL_API int __cdecl soundtouch_setSetting(HANDLE h, \r
+        int settingId,   ///< Setting ID number. see SETTING_... defines.\r
+        int value        ///< New setting value.\r
+        )\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return FALSE;\r
+\r
+    return sth->pst->setSetting(settingId, value);\r
+}\r
+\r
+/// Reads a setting controlling the processing system behaviour. See the\r
+/// 'SETTING_...' defines for available setting ID's.\r
+///\r
+/// \return the setting value.\r
+SOUNDTOUCHDLL_API int __cdecl soundtouch_getSetting(HANDLE h, \r
+        int settingId    ///< Setting ID number, see SETTING_... defines.\r
+        )\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return -1;\r
+\r
+    return sth->pst->getSetting(settingId);\r
+}\r
+\r
+\r
+/// Returns number of samples currently unprocessed.\r
+SOUNDTOUCHDLL_API uint __cdecl soundtouch_numUnprocessedSamples(HANDLE h)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return 0;\r
+\r
+    return sth->pst->numUnprocessedSamples();\r
+}\r
+\r
+\r
+/// Adjusts book-keeping so that given number of samples are removed from beginning of the \r
+/// sample buffer without copying them anywhere. \r
+///\r
+/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+/// with 'ptrBegin' function.\r
+SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples(HANDLE h, \r
+        SAMPLETYPE *outBuffer,      ///< Buffer where to copy output samples.\r
+        unsigned int maxSamples     ///< How many samples to receive at max.\r
+        )\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return 0;\r
+\r
+    if (outBuffer)\r
+    {\r
+        return sth->pst->receiveSamples(outBuffer, maxSamples);\r
+    }\r
+    else\r
+    {\r
+        return sth->pst->receiveSamples(maxSamples);\r
+    }\r
+}\r
+\r
+\r
+/// int16 version of soundtouch_receiveSamples(): This converts internal float samples\r
+/// into int16 (short) return data type\r
+SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples_i16(HANDLE h,\r
+        short *outBuffer,           ///< Buffer where to copy output samples.\r
+        unsigned int maxSamples     ///< How many samples to receive at max.\r
+        )\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return 0;\r
+    uint outTotal = 0;\r
+\r
+    if (outBuffer == NULL)\r
+    {\r
+        // only reduce sample count, not receive samples\r
+        return sth->pst->receiveSamples(maxSamples);\r
+    }\r
+\r
+    uint numChannels = sth->pst->numChannels();\r
+\r
+    // iterate until all samples converted & put to SoundTouch object\r
+    while (maxSamples > 0)\r
+    {\r
+        float convert[8192];    // allocate temporary conversion buffer from stack\r
+\r
+        // how many multichannel samples fit into 'convert' buffer:\r
+        uint convSamples = 8192 / numChannels;\r
+\r
+        // request max 'nround' values at a time to guarantee that these fit in the 'convert' buffer\r
+        uint n = (maxSamples > convSamples) ? convSamples : maxSamples;\r
+\r
+        uint out = sth->pst->receiveSamples(convert, n);\r
+\r
+        // convert & saturate received samples to int16\r
+        for (uint i = 0; i < out * numChannels; i++)\r
+        {\r
+            // first convert value to int32, then saturate to int16 min/max limits\r
+            int value = (int)convert[i];\r
+            value = (value < SHRT_MIN) ? SHRT_MIN : (value > SHRT_MAX) ? SHRT_MAX : value;\r
+            outBuffer[i] = (short)value;\r
+        }\r
+        outTotal += out;\r
+        if (out < n) break;  // didn't get as many as asked => no more samples available => break here\r
+\r
+        maxSamples -= n;\r
+        outBuffer += out * numChannels;\r
+    }\r
+\r
+    // return number of processed samples\r
+    return outTotal;\r
+}\r
+\r
+\r
+/// Returns number of samples currently available.\r
+SOUNDTOUCHDLL_API uint __cdecl soundtouch_numSamples(HANDLE h)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return 0;\r
+\r
+    return sth->pst->numSamples();\r
+}\r
+\r
+\r
+/// Returns nonzero if there aren't any samples available for outputting.\r
+SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h)\r
+{\r
+    STHANDLE *sth = (STHANDLE*)h;\r
+    if (sth->dwMagic != STMAGIC) return -1;\r
+\r
+    return sth->pst->isEmpty();\r
+}\r
+\r
+\r
+SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate)\r
+{\r
+    BPMHANDLE *tmp = new BPMHANDLE;\r
+\r
+    if (tmp)\r
+    {\r
+        tmp->dwMagic = BPMMAGIC;\r
+        tmp->pbpm = new BPMDetect(numChannels, sampleRate);\r
+        if (tmp->pbpm == NULL)\r
+        {\r
+            delete tmp;\r
+            tmp = NULL;\r
+        }\r
+    }\r
+    return (HANDLE)tmp;\r
+}\r
+\r
+\r
+SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h)\r
+{\r
+    BPMHANDLE *sth = (BPMHANDLE*)h;\r
+    if (sth->dwMagic != BPMMAGIC) return;\r
+\r
+    sth->dwMagic = 0;\r
+    if (sth->pbpm) delete sth->pbpm;\r
+    sth->pbpm = NULL;\r
+    delete sth;\r
+}\r
+\r
+\r
+/// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler\r
+SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h, \r
+        const float *samples,\r
+        unsigned int numSamples)\r
+{\r
+    BPMHANDLE *bpmh = (BPMHANDLE*)h;\r
+    if (bpmh->dwMagic != BPMMAGIC) return;\r
+\r
+    bpmh->pbpm->inputSamples(samples, numSamples);\r
+}\r
+\r
+\r
+/// Feed 'numSamples' sample frames from 'samples' into the BPM detection handler.\r
+/// 16bit int sample format version.\r
+SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h, \r
+        const short *samples,\r
+        unsigned int numSamples)\r
+{\r
+    BPMHANDLE *bpmh = (BPMHANDLE*)h;\r
+    if (bpmh->dwMagic != BPMMAGIC) return;\r
+\r
+    uint numChannels = bpmh->numChannels;\r
+\r
+    // iterate until all samples converted & put to SoundTouch object\r
+    while (numSamples > 0)\r
+    {\r
+        float convert[8192];    // allocate temporary conversion buffer from stack\r
+\r
+        // how many multichannel samples fit into 'convert' buffer:\r
+        uint convSamples = 8192 / numChannels;\r
+\r
+        // convert max 'nround' values at a time to guarantee that these fit in the 'convert' buffer\r
+        uint n = (numSamples > convSamples) ? convSamples : numSamples;\r
+        for (uint i = 0; i < n * numChannels; i++)\r
+        {\r
+            convert[i] = samples[i];\r
+        }\r
+        // put the converted samples into SoundTouch\r
+        bpmh->pbpm->inputSamples(convert, n);\r
+\r
+        numSamples -= n;\r
+        samples += n * numChannels;\r
+    }\r
+}\r
+\r
+\r
+/// Analyzes the results and returns the BPM rate. Use this function to read result\r
+/// after whole song data has been input to the class by consecutive calls of\r
+/// 'inputSamples' function.\r
+///\r
+/// \return Beats-per-minute rate, or zero if detection failed.\r
+SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h)\r
+{\r
+    BPMHANDLE *bpmh = (BPMHANDLE*)h;\r
+    if (bpmh->dwMagic != BPMMAGIC) return 0;\r
+\r
+    return bpmh->pbpm->getBpm();\r
+}\r
diff --git a/source/SoundTouchDLL/SoundTouchDLL.h b/source/SoundTouchDLL/SoundTouchDLL.h
new file mode 100644 (file)
index 0000000..5932dc8
--- /dev/null
@@ -0,0 +1,229 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// SoundTouch DLL wrapper - wraps SoundTouch routines into a Dynamic Load \r
+/// Library interface.\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifndef _SoundTouchDLL_h_\r
+#define _SoundTouchDLL_h_\r
+\r
+#if defined(_WIN32) || defined(WIN32)\r
+    // Windows\r
+    #ifndef __cplusplus\r
+        #error "Expected g++"\r
+    #endif\r
+\r
+    #ifdef DLL_EXPORTS\r
+        #define SOUNDTOUCHDLL_API extern "C" __declspec(dllexport)\r
+    #else\r
+        #define SOUNDTOUCHDLL_API extern "C" __declspec(dllimport)\r
+    #endif\r
+\r
+#else\r
+    // GNU version\r
+\r
+    #ifdef DLL_EXPORTS\r
+        // GCC declaration for exporting functions\r
+        #define SOUNDTOUCHDLL_API extern "C" __attribute__((__visibility__("default")))\r
+    #else\r
+        // GCC doesn't require DLL imports\r
+        #define SOUNDTOUCHDLL_API\r
+    #endif\r
+\r
+    // Linux-replacements for Windows declarations:\r
+    #define __cdecl\r
+    typedef unsigned int DWORD;\r
+    #define FALSE    0\r
+    #define TRUE    1\r
+\r
+#endif\r
+\r
+typedef void * HANDLE;\r
+\r
+/// Create a new instance of SoundTouch processor.\r
+SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance();\r
+\r
+/// Destroys a SoundTouch processor instance.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h);\r
+\r
+/// Get SoundTouch library version string\r
+SOUNDTOUCHDLL_API const char *__cdecl soundtouch_getVersionString();\r
+\r
+/// Get SoundTouch library version string - alternative function for \r
+/// environments that can't properly handle character string as return value\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_getVersionString2(char* versionString, int bufferSize);\r
+\r
+/// Get SoundTouch library version Id\r
+SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_getVersionId();\r
+\r
+/// Sets new rate control value. Normal rate = 1.0, smaller values\r
+/// represent slower rate, larger faster rates.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setRate(HANDLE h, float newRate);\r
+\r
+/// Sets new tempo control value. Normal tempo = 1.0, smaller values\r
+/// represent slower tempo, larger faster tempo.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempo(HANDLE h, float newTempo);\r
+\r
+/// Sets new rate control value as a difference in percents compared\r
+/// to the original rate (-50 .. +100 %);\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setRateChange(HANDLE h, float newRate);\r
+\r
+/// Sets new tempo control value as a difference in percents compared\r
+/// to the original tempo (-50 .. +100 %);\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setTempoChange(HANDLE h, float newTempo);\r
+\r
+/// Sets new pitch control value. Original pitch = 1.0, smaller values\r
+/// represent lower pitches, larger values higher pitch.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitch(HANDLE h, float newPitch);\r
+\r
+/// Sets pitch change in octaves compared to the original pitch  \r
+/// (-1.00 .. +1.00);\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchOctaves(HANDLE h, float newPitch);\r
+\r
+/// Sets pitch change in semi-tones compared to the original pitch\r
+/// (-12 .. +12);\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newPitch);\r
+\r
+\r
+/// Sets the number of channels, 1 = mono, 2 = stereo, n = multichannel\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setChannels(HANDLE h, unsigned int numChannels);\r
+\r
+/// Sets sample rate.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, unsigned int srate);\r
+\r
+/// Flushes the last samples from the processing pipeline to the output.\r
+/// Clears also the internal processing buffers.\r
+//\r
+/// Note: This function is meant for extracting the last samples of a sound\r
+/// stream. This function may introduce additional blank samples in the end\r
+/// of the sound stream, and thus it's not recommended to call this function\r
+/// in the middle of a sound stream.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_flush(HANDLE h);\r
+\r
+/// Adds 'numSamples' pcs of samples from the 'samples' memory position into\r
+/// the input of the object. Notice that sample rate _has_to_ be set before\r
+/// calling this function, otherwise throws a runtime_error exception.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h, \r
+        const float *samples,       ///< Pointer to sample buffer.\r
+        unsigned int numSamples     ///< Number of sample frames in buffer. Notice\r
+                                    ///< that in case of multi-channel sound a single \r
+                                    ///< sample frame contains data for all channels.\r
+);\r
+\r
+/// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data\r
+/// and internally converts it to float format before processing\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples_i16(HANDLE h,\r
+        const short *samples,       ///< Pointer to sample buffer.\r
+        unsigned int numSamples     ///< Number of sample frames in buffer. Notice\r
+                                    ///< that in case of multi-channel sound a single \r
+                                    ///< sample frame contains data for all channels.\r
+);\r
+\r
+\r
+/// Clears all the samples in the object's output and internal processing\r
+/// buffers.\r
+SOUNDTOUCHDLL_API void __cdecl soundtouch_clear(HANDLE h);\r
+\r
+/// Changes a setting controlling the processing system behaviour. See the\r
+/// 'SETTING_...' defines for available setting ID's.\r
+/// \r
+/// \return 'nonzero' if the setting was successfully changed, otherwise zero\r
+SOUNDTOUCHDLL_API int __cdecl soundtouch_setSetting(HANDLE h, \r
+        int settingId,   ///< Setting ID number. see SETTING_... defines.\r
+        int value        ///< New setting value.\r
+);\r
+\r
+/// Reads a setting controlling the processing system behaviour. See the\r
+/// 'SETTING_...' defines for available setting ID's.\r
+///\r
+/// \return the setting value.\r
+SOUNDTOUCHDLL_API int __cdecl soundtouch_getSetting(HANDLE h, \r
+        int settingId    ///< Setting ID number, see SETTING_... defines.\r
+);\r
+\r
+\r
+/// Returns number of samples currently unprocessed.\r
+SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numUnprocessedSamples(HANDLE h);\r
+\r
+/// Adjusts book-keeping so that given number of samples are removed from beginning of the \r
+/// sample buffer without copying them anywhere. \r
+///\r
+/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+/// with 'ptrBegin' function.\r
+SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples(HANDLE h, \r
+        float *outBuffer,           ///< Buffer where to copy output samples.\r
+        unsigned int maxSamples     ///< How many samples to receive at max.\r
+);\r
+\r
+\r
+/// int16 version of soundtouch_receiveSamples(): This converts internal float samples\r
+/// into int16 (short) return data type\r
+SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_receiveSamples_i16(HANDLE h,\r
+        short *outBuffer,           ///< Buffer where to copy output samples.\r
+        unsigned int maxSamples     ///< How many samples to receive at max.\r
+);\r
+\r
+/// Returns number of samples currently available.\r
+SOUNDTOUCHDLL_API unsigned int __cdecl soundtouch_numSamples(HANDLE h);\r
+\r
+/// Returns nonzero if there aren't any samples available for outputting.\r
+SOUNDTOUCHDLL_API int __cdecl soundtouch_isEmpty(HANDLE h);\r
+\r
+/// Create a new instance of BPM detector\r
+SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleRate);\r
+\r
+/// Destroys a BPM detector instance.\r
+SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h);\r
+\r
+/// Feed 'numSamples' sample frames from 'samples' into the BPM detector.\r
+SOUNDTOUCHDLL_API void __cdecl bpm_putSamples(HANDLE h, \r
+        const float *samples,           ///< Pointer to sample buffer.\r
+        unsigned int numSamples         ///< Number of samples in buffer. Notice\r
+                                        ///< that in case of stereo-sound a single sample\r
+                                        ///< contains data for both channels.\r
+        );\r
+\r
+/// Feed 'numSamples' sample frames from 'samples' into the BPM detector.\r
+/// 16bit int sample format version.\r
+SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h, \r
+        const short *samples,           ///< Pointer to sample buffer.\r
+        unsigned int numSamples         ///< Number of samples in buffer. Notice\r
+                                        ///< that in case of stereo-sound a single sample\r
+                                        ///< contains data for both channels.\r
+        );\r
+\r
+/// Analyzes the results and returns the BPM rate. Use this function to read result\r
+/// after whole song data has been input to the class by consecutive calls of\r
+/// 'inputSamples' function.\r
+///\r
+/// \return Beats-per-minute rate, or zero if detection failed.\r
+SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h);\r
+\r
+#endif  // _SoundTouchDLL_h_\r
+\r
diff --git a/source/SoundTouchDLL/SoundTouchDLL.pas b/source/SoundTouchDLL/SoundTouchDLL.pas
new file mode 100644 (file)
index 0000000..48e6251
--- /dev/null
@@ -0,0 +1,482 @@
+unit SoundTouchDLL;\r
+\r
+//////////////////////////////////////////////////////////////////////////////\r
+//\r
+// SoundTouch.dll wrapper for accessing SoundTouch routines from Delphi/Pascal\r
+//\r
+//  Module Author : Christian Budde\r
+//\r
+//  2014-01-12 fixes by Sandro Cumerlato <sandro.cumerlato 'at' gmail.com>\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+interface\r
+\r
+uses\r
+  Windows;\r
+\r
+type\r
+  TSoundTouchHandle = THandle;\r
+\r
+  // Create a new instance of SoundTouch processor.\r
+  TSoundTouchCreateInstance = function : TSoundTouchHandle; cdecl;\r
+\r
+  // Destroys a SoundTouch processor instance.\r
+  TSoundTouchDestroyInstance = procedure (Handle: TSoundTouchHandle); cdecl;\r
+\r
+  // Get SoundTouch library version string\r
+  TSoundTouchGetVersionString = function : PAnsiChar; cdecl;\r
+\r
+  // Get SoundTouch library version string 2\r
+  TSoundTouchGetVersionString2 = procedure(VersionString : PAnsiChar; BufferSize : Integer); cdecl;\r
+  \r
+  // Get SoundTouch library version Id\r
+  TSoundTouchGetVersionId = function : Cardinal; cdecl;\r
+\r
+  // Sets new rate control value. Normal rate = 1.0, smaller values\r
+  // represent slower rate, larger faster rates.\r
+  TSoundTouchSetRate = procedure (Handle: TSoundTouchHandle; NewRate: Single); cdecl;\r
+\r
+  // Sets new tempo control value. Normal tempo = 1.0, smaller values\r
+  // represent slower tempo, larger faster tempo.\r
+  TSoundTouchSetTempo = procedure (Handle: TSoundTouchHandle; NewTempo: Single); cdecl;\r
+\r
+  // Sets new rate control value as a difference in percents compared\r
+  // to the original rate (-50 .. +100 %);\r
+  TSoundTouchSetRateChange = procedure (Handle: TSoundTouchHandle; NewRate: Single); cdecl;\r
+\r
+  // Sets new tempo control value as a difference in percents compared\r
+  // to the original tempo (-50 .. +100 %);\r
+  TSoundTouchSetTempoChange = procedure (Handle: TSoundTouchHandle; NewTempo: Single); cdecl;\r
+\r
+  // Sets new pitch control value. Original pitch = 1.0, smaller values\r
+  // represent lower pitches, larger values higher pitch.\r
+  TSoundTouchSetPitch = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;\r
+\r
+  // Sets pitch change in octaves compared to the original pitch\r
+  // (-1.00 .. +1.00);\r
+  TSoundTouchSetPitchOctaves = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;\r
+\r
+  // Sets pitch change in semi-tones compared to the original pitch\r
+  // (-12 .. +12);\r
+  TSoundTouchSetPitchSemiTones = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;\r
+\r
+  // Sets the number of channels, 1 = mono, 2 = stereo\r
+  TSoundTouchSetChannels = procedure (Handle: TSoundTouchHandle; NumChannels: Cardinal); cdecl;\r
+\r
+  // Sets sample rate.\r
+  TSoundTouchSetSampleRate = procedure (Handle: TSoundTouchHandle; SampleRate: Cardinal); cdecl;\r
+\r
+  // Flushes the last samples from the processing pipeline to the output.\r
+  // Clears also the internal processing buffers.\r
+  //\r
+  // Note: This function is meant for extracting the last samples of a sound\r
+  // stream. This function may introduce additional blank samples in the end\r
+  // of the sound stream, and thus it\r
+  // in the middle of a sound stream.\r
+  TSoundTouchFlush = procedure (Handle: TSoundTouchHandle); cdecl;\r
+\r
+  // Adds 'numSamples' pcs of samples from the 'samples' memory position into\r
+  // the input of the object. Notice that sample rate _has_to_ be set before\r
+  // calling this function, otherwise throws a runtime_error exception.\r
+  TSoundTouchPutSamples = procedure (Handle: TSoundTouchHandle;\r
+                                     const Samples: PSingle; //< Pointer to sample buffer.\r
+                                     NumSamples: Cardinal    //< Number of samples in buffer. Notice\r
+                                                             //< that in case of stereo-sound a single sample\r
+                                                             //< contains data for both channels.\r
+                                    ); cdecl;\r
+\r
+  // Clears all the samples in the object's output and internal processing\r
+  // buffers.\r
+  TSoundTouchClear = procedure (Handle: TSoundTouchHandle); cdecl;\r
+\r
+  // Changes a setting controlling the processing system behaviour. See the\r
+  // 'SETTING_...' defines for available setting ID's.\r
+  //\r
+  // \return 'TRUE' if the setting was successfully changed\r
+  TSoundTouchSetSetting = function (Handle: TSoundTouchHandle;\r
+                                 SettingId: Integer;   //< Setting ID number. see SETTING_... defines.\r
+                                 Value: Integer        //< New setting value.\r
+                                ): Boolean; cdecl;\r
+\r
+  // Reads a setting controlling the processing system behaviour. See the\r
+  // 'SETTING_...' defines for available setting ID's.\r
+  //\r
+  // \return the setting value.\r
+  TSoundTouchGetSetting = function (Handle: TSoundTouchHandle;\r
+                                 SettingId: Integer     //< Setting ID number, see SETTING_... defines.\r
+                                ): Integer; cdecl;\r
+\r
+  // Returns number of samples currently unprocessed.\r
+  TSoundTouchNumUnprocessedSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;\r
+\r
+  // Adjusts book-keeping so that given number of samples are removed from beginning of the\r
+  // sample buffer without copying them anywhere.\r
+  //\r
+  // Used to reduce the number of samples in the buffer when accessing the sample buffer directly\r
+  // with 'ptrBegin' function.\r
+  TSoundTouchReceiveSamples = function (Handle: TSoundTouchHandle;\r
+                                     OutBuffer: PSingle;           //< Buffer where to copy output samples.\r
+                                     MaxSamples: Integer      //< How many samples to receive at max.\r
+                                    ): Cardinal; cdecl;\r
+\r
+  // Returns number of samples currently available.\r
+  TSoundTouchNumSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;\r
+\r
+  // Returns nonzero if there aren't any samples available for outputting.\r
+  TSoundTouchIsEmpty = function (Handle: TSoundTouchHandle): Integer; cdecl;\r
+\r
+var\r
+  SoundTouchCreateInstance        : TSoundTouchCreateInstance;\r
+  SoundTouchDestroyInstance       : TSoundTouchDestroyInstance;\r
+  SoundTouchGetVersionString      : TSoundTouchGetVersionString;\r
+  SoundTouchGetVersionString2     : TSoundTouchGetVersionString2;\r
+  SoundTouchGetVersionId          : TSoundTouchGetVersionId;\r
+  SoundTouchSetRate               : TSoundTouchSetRate;\r
+  SoundTouchSetTempo              : TSoundTouchSetTempo;\r
+  SoundTouchSetRateChange         : TSoundTouchSetRateChange;\r
+  SoundTouchSetTempoChange        : TSoundTouchSetTempoChange;\r
+  SoundTouchSetPitch              : TSoundTouchSetPitch;\r
+  SoundTouchSetPitchOctaves       : TSoundTouchSetPitchOctaves;\r
+  SoundTouchSetPitchSemiTones     : TSoundTouchSetPitchSemiTones;\r
+  SoundTouchSetChannels           : TSoundTouchSetChannels;\r
+  SoundTouchSetSampleRate         : TSoundTouchSetSampleRate;\r
+  SoundTouchFlush                 : TSoundTouchFlush;\r
+  SoundTouchPutSamples            : TSoundTouchPutSamples;\r
+  SoundTouchPutSamplesI16         : TSoundTouchPutSamplesI16;\r
+  SoundTouchClear                 : TSoundTouchClear;\r
+  SoundTouchSetSetting            : TSoundTouchSetSetting;\r
+  SoundTouchGetSetting            : TSoundTouchGetSetting;\r
+  SoundTouchNumUnprocessedSamples : TSoundTouchNumUnprocessedSamples;\r
+  SoundTouchReceiveSamples        : TSoundTouchReceiveSamples;\r
+  SoundTouchNumSamples            : TSoundTouchNumSamples;\r
+  SoundTouchIsEmpty               : TSoundTouchIsEmpty;\r
+\r
+type\r
+  TSoundTouch = class\r
+  private\r
+    FHandle     : TSoundTouchHandle;\r
+    FRate       : Single;\r
+    FPitch      : Single;\r
+    FTempo      : Single;\r
+    FSampleRate : Single;\r
+    FChannels   : Cardinal;\r
+    function GetNumSamples: Cardinal;\r
+    function GetNumUnprocessedSamples: Cardinal;\r
+    function GetIsEmpty: Integer;\r
+    function GetPitchChange: Single;\r
+    function GetRateChange: Single;\r
+    function GetTempoChange: Single;\r
+    procedure SetRate(const Value: Single);\r
+    procedure SetPitch(const Value: Single);\r
+    procedure SetTempo(const Value: Single);\r
+    procedure SetPitchChange(const Value: Single);\r
+    procedure SetRateChange(const Value: Single);\r
+    procedure SetTempoChange(const Value: Single);\r
+    procedure SetChannels(const Value: Cardinal);\r
+    procedure SetSampleRate(const Value: Single);\r
+  protected\r
+    procedure SamplerateChanged; virtual;\r
+    procedure ChannelsChanged; virtual;\r
+    procedure PitchChanged; virtual;\r
+    procedure TempoChanged; virtual;\r
+    procedure RateChanged; virtual;\r
+  public\r
+    class function GetVersionString: string;\r
+    class function GetVersionId: Cardinal;\r
+    constructor Create; virtual;\r
+    destructor Destroy; override;\r
+    procedure Flush; virtual;\r
+    procedure Clear; virtual;\r
+\r
+    procedure PutSamples(const Samples: PSingle; const NumSamples: Cardinal);\r
+    function ReceiveSamples(const OutBuffer: PSingle; const MaxSamples: Integer): Cardinal;\r
+\r
+    function SetSetting(const SettingId: Integer; const Value: Integer): Boolean;\r
+    function GetSetting(const SettingId: Integer): Integer;\r
+\r
+    property VersionString: string read GetVersionString;\r
+    property VersionID: Cardinal read GetVersionId;\r
+    property Channels: Cardinal read FChannels write SetChannels;\r
+    property Rate: Single read FRate write SetRate;\r
+    property RateChange: Single read GetRateChange write SetRateChange;\r
+    property Tempo: Single read FTempo write SetTempo;\r
+    property TempoChange: Single read GetTempoChange write SetTempoChange;\r
+    property Pitch: Single read FPitch write SetPitch;\r
+    property PitchChange: Single read GetPitchChange write SetPitchChange;\r
+    property SampleRate: Single read FSampleRate write SetSampleRate;\r
+\r
+    property NumSamples: Cardinal read GetNumSamples;\r
+    property NumUnprocessedSamples: Cardinal read GetNumUnprocessedSamples;\r
+    property IsEmpty: Integer read GetIsEmpty;\r
+  end;\r
+\r
+implementation\r
+\r
+{ TSoundTouch }\r
+\r
+constructor TSoundTouch.Create;\r
+begin\r
+  inherited;\r
+  FHandle := SoundTouchCreateInstance();\r
+  FRate := 1;\r
+  FTempo := 1;\r
+  FPitch := 1;\r
+  FChannels := 1;\r
+  FSampleRate := 44100;\r
+  SamplerateChanged;\r
+  ChannelsChanged;\r
+end;\r
+\r
+destructor TSoundTouch.Destroy;\r
+begin\r
+  SoundTouchDestroyInstance(FHandle);\r
+  inherited;\r
+end;\r
+\r
+procedure TSoundTouch.Flush;\r
+begin\r
+  SoundTouchFlush(FHandle);\r
+end;\r
+\r
+procedure TSoundTouch.Clear;\r
+begin\r
+  SoundTouchClear(FHandle);\r
+end;\r
+\r
+function TSoundTouch.GetIsEmpty: Integer;\r
+begin\r
+  result := SoundTouchIsEmpty(FHandle);\r
+end;\r
+\r
+function TSoundTouch.GetNumSamples: Cardinal;\r
+begin\r
+  result := SoundTouchNumSamples(FHandle);\r
+end;\r
+\r
+function TSoundTouch.GetNumUnprocessedSamples: Cardinal;\r
+begin\r
+  result := SoundTouchNumUnprocessedSamples(FHandle);\r
+end;\r
+\r
+function TSoundTouch.GetPitchChange: Single;\r
+begin\r
+  result := 100 * (FPitch - 1.0);\r
+end;\r
+\r
+function TSoundTouch.GetRateChange: Single;\r
+begin\r
+  result := 100 * (FRate - 1.0);\r
+end;\r
+\r
+function TSoundTouch.GetTempoChange: Single;\r
+begin\r
+  result := 100 * (FTempo - 1.0);\r
+end;\r
+\r
+class function TSoundTouch.GetVersionId: Cardinal;\r
+begin\r
+  result := SoundTouchGetVersionId();\r
+end;\r
+\r
+class function TSoundTouch.GetVersionString: string;\r
+begin\r
+  result := StrPas(SoundTouchGetVersionString());\r
+end;\r
+\r
+procedure TSoundTouch.SetChannels(const Value: Cardinal);\r
+begin\r
+  if FChannels <> Value then\r
+  begin\r
+    FChannels := Value;\r
+    ChannelsChanged;\r
+  end;\r
+end;\r
+\r
+procedure TSoundTouch.ChannelsChanged;\r
+begin\r
+  assert(FChannels in [1, 2]);\r
+  SoundTouchSetChannels(FHandle, FChannels);\r
+end;\r
+\r
+procedure TSoundTouch.SetPitch(const Value: Single);\r
+begin\r
+  if FPitch <> Value then\r
+  begin\r
+    FPitch := Value;\r
+    PitchChanged;\r
+  end;\r
+end;\r
+\r
+procedure TSoundTouch.PitchChanged;\r
+begin\r
+  SoundTouchSetPitch(FHandle, FPitch);\r
+end;\r
+\r
+procedure TSoundTouch.putSamples(const Samples: PSingle;\r
+  const NumSamples: Cardinal);\r
+begin\r
+  SoundTouchPutSamples(FHandle, Samples, NumSamples);\r
+end;\r
+\r
+procedure TSoundTouch.RateChanged;\r
+begin\r
+  SoundTouchSetRate(FHandle, FRate);\r
+end;\r
+\r
+function TSoundTouch.ReceiveSamples(const OutBuffer: PSingle;\r
+  const MaxSamples: Integer): Cardinal;\r
+begin\r
+  result := SoundTouchReceiveSamples(FHandle, OutBuffer, MaxSamples);\r
+end;\r
+\r
+procedure TSoundTouch.SetPitchChange(const Value: Single);\r
+begin\r
+  Pitch := 1.0 + 0.01 * Value;\r
+end;\r
+\r
+procedure TSoundTouch.SetRate(const Value: Single);\r
+begin\r
+  if FRate <> Value then\r
+  begin\r
+    FRate := Value;\r
+    RateChanged;\r
+  end;\r
+end;\r
+\r
+procedure TSoundTouch.SetRateChange(const Value: Single);\r
+begin\r
+  Rate := 1.0 + 0.01 * Value;\r
+end;\r
+\r
+procedure TSoundTouch.SetSampleRate(const Value: Single);\r
+begin\r
+  if FSampleRate <> Value then\r
+  begin\r
+    FSampleRate := Value;\r
+    SamplerateChanged;\r
+  end;\r
+end;\r
+\r
+procedure TSoundTouch.SamplerateChanged;\r
+begin\r
+  assert(FSampleRate > 0);\r
+  SoundTouchsetSampleRate(FHandle, round(FSampleRate));\r
+end;\r
+\r
+procedure TSoundTouch.SetTempo(const Value: Single);\r
+begin\r
+ if FTempo <> Value then\r
+  begin\r
+    FTempo := Value;\r
+    TempoChanged;\r
+  end;\r
+end;\r
+\r
+procedure TSoundTouch.SetTempoChange(const Value: Single);\r
+begin\r
+  Tempo := 1.0 + 0.01 * Value;\r
+end;\r
+\r
+function TSoundTouch.GetSetting(const SettingId: Integer): Integer;\r
+begin\r
+  result := SoundTouchGetSetting(FHandle, SettingId);\r
+end;\r
+\r
+function TSoundTouch.SetSetting(const SettingId: Integer;\r
+  const Value: Integer): Boolean;\r
+begin\r
+  result := SoundTouchSetSetting(FHandle, SettingId, Value);\r
+end;\r
+\r
+procedure TSoundTouch.TempoChanged;\r
+begin\r
+  SoundTouchsetTempo(FHandle, FTempo);\r
+end;\r
+\r
+var\r
+  SoundTouchLibHandle: HINST;\r
+  SoundTouchDLLFile: PAnsiChar = 'SoundTouch.dll';\r
+\r
+  // bpm detect functions. untested -- if these don't work then remove:\r
+  bpm_createInstance: function(chan: CInt32; sampleRate : CInt32): THandle; cdecl;\r
+  bpm_destroyInstance: procedure(h: THandle); cdecl;\r
+  bpm_getBpm: function(h: THandle): cfloat; cdecl;\r
+  bpm_putSamples: procedure(h: THandle; const samples: pcfloat;\r
+  numSamples: cardinal); cdecl;\r
+\r
+procedure InitDLL;\r
+begin\r
+  SoundTouchLibHandle := LoadLibrary(SoundTouchDLLFile);\r
+  if SoundTouchLibHandle <> 0 then\r
+  try\r
+    Pointer(SoundTouchCreateInstance)        := GetProcAddress(SoundTouchLibHandle, 'soundtouch_createInstance');\r
+    Pointer(SoundTouchDestroyInstance)       := GetProcAddress(SoundTouchLibHandle, 'soundtouch_destroyInstance');\r
+    Pointer(SoundTouchGetVersionString)      := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionString');\r
+    Pointer(SoundTouchGetVersionString2)     := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionString2');\r
+    Pointer(SoundTouchGetVersionId)          := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionId');\r
+    Pointer(SoundTouchSetRate)               := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setRate');\r
+    Pointer(SoundTouchSetTempo)              := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setTempo');\r
+    Pointer(SoundTouchSetRateChange)         := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setRateChange');\r
+    Pointer(SoundTouchSetTempoChange)        := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setTempoChange');\r
+    Pointer(SoundTouchSetPitch)              := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitch');\r
+    Pointer(SoundTouchSetPitchOctaves)       := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitchOctaves');\r
+    Pointer(SoundTouchSetPitchSemiTones)     := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitchSemiTones');\r
+    Pointer(SoundTouchSetChannels)           := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setChannels');\r
+    Pointer(SoundTouchSetSampleRate)         := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setSampleRate');\r
+    Pointer(SoundTouchFlush)                 := GetProcAddress(SoundTouchLibHandle, 'soundtouch_flush');\r
+    Pointer(SoundTouchPutSamples)            := GetProcAddress(SoundTouchLibHandle, 'soundtouch_putSamples');\r
+    Pointer(SoundTouchPutSamplesI16)         := GetProcAddress(SoundTouchLibHandle, 'soundtouch_putSamples_i16');\r
+    Pointer(SoundTouchClear)                 := GetProcAddress(SoundTouchLibHandle, 'soundtouch_clear');\r
+    Pointer(SoundTouchSetSetting)            := GetProcAddress(SoundTouchLibHandle, 'soundtouch_SetSetting');\r
+    Pointer(SoundTouchGetSetting)            := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setSetting');\r
+    Pointer(SoundTouchNumUnprocessedSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_numUnprocessedSamples');\r
+    Pointer(SoundTouchReceiveSamples)        := GetProcAddress(SoundTouchLibHandle, 'soundtouch_receiveSamples');\r
+    Pointer(SoundTouchReceiveSamplesI16)     := GetProcAddress(SoundTouchLibHandle, 'soundtouch_receiveSamples_i16');\r
+    Pointer(SoundTouchNumSamples)            := GetProcAddress(SoundTouchLibHandle, 'soundtouch_numSamples');\r
+    Pointer(SoundTouchIsEmpty)               := GetProcAddress(SoundTouchLibHandle, 'soundtouch_isEmpty');\r
+\r
+    Pointer(bpm_createInstance)             :=GetProcAddress(SoundTouchLibHandle, 'bpm_createInstance');\r
+    Pointer(bpm_destroyInstance)            :=GetProcAddress(SoundTouchLibHandle, 'bpm_destroyInstance');\r
+    Pointer(bpm_getBpm)                     :=GetProcAddress(SoundTouchLibHandle, 'bpm_getBpm');\r
+    Pointer(bpm_putSamples)                 :=GetProcAddress(SoundTouchLibHandle, 'bpm_putSamples');\r
+        \r
+  except\r
+    FreeLibrary(SoundTouchLibHandle);\r
+    SoundTouchLibHandle := 0;\r
+  end;\r
+end;\r
+\r
+procedure FreeDLL;\r
+begin\r
+  if SoundTouchLibHandle <> 0 then FreeLibrary(SoundTouchLibHandle);\r
+end;\r
+\r
+initialization\r
+  InitDLL;\r
+\r
+finalization\r
+  FreeDLL;\r
+\r
+end.\r
diff --git a/source/SoundTouchDLL/SoundTouchDLL.rc b/source/SoundTouchDLL/SoundTouchDLL.rc
new file mode 100644 (file)
index 0000000..cc6a408
--- /dev/null
@@ -0,0 +1,100 @@
+// Microsoft Visual C++ generated resource script.\r
+//\r
+#include "resource.h"\r
+\r
+#define APSTUDIO_READONLY_SYMBOLS\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 2 resource.\r
+//\r
+#include "afxres.h"\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#undef APSTUDIO_READONLY_SYMBOLS\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+// English (United States) resources\r
+\r
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+#pragma code_page(1252)\r
+\r
+#ifdef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// TEXTINCLUDE\r
+//\r
+\r
+1 TEXTINCLUDE \r
+BEGIN\r
+    "resource.h\0"\r
+END\r
+\r
+2 TEXTINCLUDE \r
+BEGIN\r
+    "#include ""afxres.h""\r\n"\r
+    "\0"\r
+END\r
+\r
+3 TEXTINCLUDE \r
+BEGIN\r
+    "\r\n"\r
+    "\0"\r
+END\r
+\r
+#endif    // APSTUDIO_INVOKED\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Version\r
+//\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+ FILEVERSION 2,1,0,0\r
+ PRODUCTVERSION 2,1,0,0\r
+ FILEFLAGSMASK 0x17L\r
+#ifdef _DEBUG\r
+ FILEFLAGS 0x1L\r
+#else\r
+ FILEFLAGS 0x0L\r
+#endif\r
+ FILEOS 0x4L\r
+ FILETYPE 0x2L\r
+ FILESUBTYPE 0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "000004b0"\r
+        BEGIN\r
+            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."\r
+            VALUE "FileDescription", "SoundTouch Dynamic Link Library"\r
+            VALUE "FileVersion", "2.1.0.0"\r
+            VALUE "InternalName", "SoundTouch"\r
+            VALUE "LegalCopyright", "Copyright (C) Olli Parviainen 2018"\r
+            VALUE "OriginalFilename", "SoundTouch.dll"\r
+            VALUE "ProductName", " SoundTouch Dynamic Link Library"\r
+            VALUE "ProductVersion", "2.1.0.0"\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x0, 1200\r
+    END\r
+END\r
+\r
+#endif    // English (United States) resources\r
+/////////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+\r
+#ifndef APSTUDIO_INVOKED\r
+/////////////////////////////////////////////////////////////////////////////\r
+//\r
+// Generated from the TEXTINCLUDE 3 resource.\r
+//\r
+\r
+\r
+/////////////////////////////////////////////////////////////////////////////\r
+#endif    // not APSTUDIO_INVOKED\r
+\r
diff --git a/source/SoundTouchDLL/SoundTouchDLL.sln b/source/SoundTouchDLL/SoundTouchDLL.sln
new file mode 100644 (file)
index 0000000..3542f7e
--- /dev/null
@@ -0,0 +1,50 @@
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 14\r
+VisualStudioVersion = 14.0.23107.0\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouchDLL", "SoundTouchDLL.vcxproj", "{164DE61D-6391-4265-8273-30740117D356}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "..\SoundTouch\SoundTouch.vcxproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"\r
+EndProject\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DllTest", "DllTest\DllTest.vcxproj", "{E3C0726F-28F4-4F0B-8183-B87CA60C063C}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+               {164DE61D-6391-4265-8273-30740117D356} = {164DE61D-6391-4265-8273-30740117D356}\r
+       EndProjectSection\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Win32 = Debug|Win32\r
+               Debug|x64 = Debug|x64\r
+               Release|Win32 = Release|Win32\r
+               Release|x64 = Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {164DE61D-6391-4265-8273-30740117D356}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {164DE61D-6391-4265-8273-30740117D356}.Debug|Win32.Build.0 = Debug|Win32\r
+               {164DE61D-6391-4265-8273-30740117D356}.Debug|x64.ActiveCfg = Debug|x64\r
+               {164DE61D-6391-4265-8273-30740117D356}.Debug|x64.Build.0 = Debug|x64\r
+               {164DE61D-6391-4265-8273-30740117D356}.Release|Win32.ActiveCfg = Release|Win32\r
+               {164DE61D-6391-4265-8273-30740117D356}.Release|Win32.Build.0 = Release|Win32\r
+               {164DE61D-6391-4265-8273-30740117D356}.Release|x64.ActiveCfg = Release|x64\r
+               {164DE61D-6391-4265-8273-30740117D356}.Release|x64.Build.0 = Release|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.Build.0 = Debug|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.ActiveCfg = Debug|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.Build.0 = Debug|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.ActiveCfg = Release|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.Build.0 = Release|Win32\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.ActiveCfg = Release|x64\r
+               {68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.Build.0 = Release|x64\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Debug|Win32.ActiveCfg = Debug|Win32\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Debug|Win32.Build.0 = Debug|Win32\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Debug|x64.ActiveCfg = Debug|x64\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Debug|x64.Build.0 = Debug|x64\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Release|Win32.ActiveCfg = Release|Win32\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Release|Win32.Build.0 = Release|Win32\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Release|x64.ActiveCfg = Release|x64\r
+               {E3C0726F-28F4-4F0B-8183-B87CA60C063C}.Release|x64.Build.0 = Release|x64\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/source/SoundTouchDLL/SoundTouchDLL.vcxproj b/source/SoundTouchDLL/SoundTouchDLL.vcxproj
new file mode 100644 (file)
index 0000000..cc73378
--- /dev/null
@@ -0,0 +1,269 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|x64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|x64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{164DE61D-6391-4265-8273-30740117D356}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
+    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
+    <PlatformToolset>v140</PlatformToolset>\r
+    <CharacterSet>MultiByte</CharacterSet>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup>\r
+    <_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <TargetName>$(ProjectName)D</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <TargetName>$(ProjectName)D_x64</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>false</LinkIncremental>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <OutDir>$(Platform)\$(Configuration)\</OutDir>\r
+    <IntDir>$(Platform)\$(Configuration)\</IntDir>\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <TargetName>$(ProjectName)_x64</TargetName>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <ClCompile>\r
+      <Optimization>Disabled</Optimization>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <MinimalRebuild>true</MinimalRebuild>\r
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
+      <PrecompiledHeader />\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\r
+    </ClCompile>\r
+    <Link>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <IgnoreSpecificDefaultLibraries>libcd;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <ProgramDatabaseFile>$(OutDir)SoundTouchD.pdb</ProgramDatabaseFile>\r
+      <SubSystem>Windows</SubSystem>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>\r
+      <TargetMachine>MachineX86</TargetMachine>\r
+      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib\r
+copy $(OutDir)$(TargetName).lib ..\..\lib\r
+</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Disabled</Optimization>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <MinimalRebuild>true</MinimalRebuild>\r
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
+      <PrecompiledHeader />\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+    </ClCompile>\r
+    <Link>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <IgnoreSpecificDefaultLibraries>libcd;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <ProgramDatabaseFile>$(OutDir)SoundTouchD.pdb</ProgramDatabaseFile>\r
+      <SubSystem>Windows</SubSystem>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>\r
+      <TargetMachine>MachineX64</TargetMachine>\r
+      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib\r
+copy $(OutDir)$(TargetName).lib ..\..\lib\r
+</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <ClCompile>\r
+      <Optimization>Full</Optimization>\r
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <OmitFramePointers>false</OmitFramePointers>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+      <PrecompiledHeader />\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <DebugInformationFormat />\r
+      <CallingConvention>Cdecl</CallingConvention>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+      <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>\r
+    </ClCompile>\r
+    <Link>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
+      <GenerateDebugInformation>false</GenerateDebugInformation>\r
+      <GenerateMapFile>true</GenerateMapFile>\r
+      <SubSystem>Windows</SubSystem>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>\r
+      <TargetMachine>MachineX86</TargetMachine>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib\r
+copy $(OutDir)$(TargetName).lib ..\..\lib\r
+</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <Midl>\r
+      <TargetEnvironment>X64</TargetEnvironment>\r
+    </Midl>\r
+    <ClCompile>\r
+      <Optimization>Full</Optimization>\r
+      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <OmitFramePointers>false</OmitFramePointers>\r
+      <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+      <PrecompiledHeader />\r
+      <WarningLevel>Level3</WarningLevel>\r
+      <DebugInformationFormat />\r
+      <CallingConvention>Cdecl</CallingConvention>\r
+      <PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>\r
+      <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>\r
+      <ObjectFileName>$(OutDir)</ObjectFileName>\r
+      <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>\r
+    </ClCompile>\r
+    <Link>\r
+      <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>\r
+      <IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
+      <GenerateDebugInformation>false</GenerateDebugInformation>\r
+      <GenerateMapFile>true</GenerateMapFile>\r
+      <SubSystem>Windows</SubSystem>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <RandomizedBaseAddress>false</RandomizedBaseAddress>\r
+      <DataExecutionPrevention />\r
+      <ImportLibrary>$(OutDir)$(TargetName).lib</ImportLibrary>\r
+      <TargetMachine>MachineX64</TargetMachine>\r
+    </Link>\r
+    <PostBuildEvent>\r
+      <Command>if not exist ..\..\lib mkdir ..\..\lib\r
+copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib\r
+copy $(OutDir)$(TargetName).lib ..\..\lib\r
+</Command>\r
+    </PostBuildEvent>\r
+  </ItemDefinitionGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="SoundTouchDLL.cpp" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClInclude Include="resource.h" />\r
+    <ClInclude Include="SoundTouchDLL.h" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ResourceCompile Include="SoundTouchDLL.rc" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Text Include="ReadMe.txt" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\SoundTouch\SoundTouch.vcxproj">\r
+      <Project>{68a5dd20-7057-448b-8fe0-b6ac8d205509}</Project>\r
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
+    </ProjectReference>\r
+  </ItemGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>
\ No newline at end of file
diff --git a/source/SoundTouchDLL/make-gnu-dll.sh b/source/SoundTouchDLL/make-gnu-dll.sh
new file mode 100755 (executable)
index 0000000..b38c643
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# This script compiles SoundTouch dynamic-link library for GNU environment 
+# with wrapper functions that are easier to import to Java / Mono / etc
+#
+
+arch=$(uname -m)
+flags=""
+
+if [[ $arch == *"86"* ]]; then
+    # Intel x86/x64 architecture
+    flags="$flags -mstackrealign -msse"
+
+    if [[ $arch == *"_64" ]]; then     
+        flags="$flags -fPIC"
+    fi
+fi
+
+echo "Building SoundTouchDLL for $arch with flags:$flags"
+
+g++ -O3 -shared $flags -DDLL_EXPORTS -fvisibility=hidden -I../../include \
+    -I../SoundTouch -o SoundTouchDll.so SoundTouchDLL.cpp ../SoundTouch/*.cpp
diff --git a/source/SoundTouchDLL/resource.h b/source/SoundTouchDLL/resource.h
new file mode 100644 (file)
index 0000000..a061ba4
--- /dev/null
@@ -0,0 +1,15 @@
+//{{NO_DEPENDENCIES}}\r
+// Microsoft Visual C++ generated include file.\r
+// Used by SoundTouchDLL.rc\r
+//\r
+\r
+// Next default values for new objects\r
+// \r
+#ifdef APSTUDIO_INVOKED\r
+#ifndef APSTUDIO_READONLY_SYMBOLS\r
+#define _APS_NEXT_RESOURCE_VALUE        101\r
+#define _APS_NEXT_COMMAND_VALUE         40001\r
+#define _APS_NEXT_CONTROL_VALUE         1000\r
+#define _APS_NEXT_SYMED_VALUE           101\r
+#endif\r
+#endif\r
diff --git a/source/csharp-example/App.config b/source/csharp-example/App.config
new file mode 100644 (file)
index 0000000..d740e88
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>\r
+<configuration>\r
+    <startup> \r
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />\r
+    </startup>\r
+</configuration>
\ No newline at end of file
diff --git a/source/csharp-example/App.xaml b/source/csharp-example/App.xaml
new file mode 100644 (file)
index 0000000..0a81ea8
--- /dev/null
@@ -0,0 +1,9 @@
+<Application x:Class="csharp_example.App"\r
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\r
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\r
+             xmlns:local="clr-namespace:csharp_example"\r
+             StartupUri="MainWindow.xaml">\r
+    <Application.Resources>\r
+         \r
+    </Application.Resources>\r
+</Application>\r
diff --git a/source/csharp-example/App.xaml.cs b/source/csharp-example/App.xaml.cs
new file mode 100644 (file)
index 0000000..4320d37
--- /dev/null
@@ -0,0 +1,25 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// C# example that manipulates mp3 audio files with SoundTouch library.\r
+/// \r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License for this source code file: Microsoft Public License(Ms-PL)\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+using System.Windows;\r
+\r
+namespace csharp_example\r
+{\r
+    /// <summary>\r
+    /// Interaction logic for App.xaml\r
+    /// </summary>\r
+    public partial class App : Application\r
+    {\r
+    }\r
+}\r
diff --git a/source/csharp-example/MainWindow.xaml b/source/csharp-example/MainWindow.xaml
new file mode 100644 (file)
index 0000000..1cad298
--- /dev/null
@@ -0,0 +1,31 @@
+<Window x:Class="csharp_example.MainWindow"\r
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\r
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\r
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\r
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\r
+        xmlns:local="clr-namespace:csharp_example"\r
+        mc:Ignorable="d"\r
+        Title="C# SoundTouch example" Height="250" Width="400" AllowDrop="True" Drop="Window_Drop">\r
+    <Grid Margin="0,0,0,-3">\r
+        <TextBlock HorizontalAlignment="Left" Margin="10,21,0,0" Text="Input audio file:" VerticalAlignment="Top"/>\r
+        <TextBox x:Name="textBox_filename" Height="23" Margin="107,20,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" Width="180" IsEnabled="False"/>\r
+        <Button x:Name="button_browse" Content="_Browse" HorizontalAlignment="Left" Margin="292,19,0,0" VerticalAlignment="Top" Width="75" Height="24" Click="button_browse_Click"/>\r
+        <TextBlock HorizontalAlignment="Left" Margin="54,55,0,0" Text="Tempo:" VerticalAlignment="Top" TextAlignment="Right"/>\r
+        <TextBox x:Name="textBox_tempo" HorizontalAlignment="Left" Height="23" Margin="107,55,0,0" Text="0" VerticalAlignment="Top" Width="75" TextAlignment="Center" LostFocus="textBox_tempo_LostFocus" KeyDown="textBox_tempo_KeyDown"/>\r
+        <TextBlock HorizontalAlignment="Left" Margin="185,55,0,0" Text="%" VerticalAlignment="Top" TextAlignment="Right"/>\r
+        \r
+        <TextBlock HorizontalAlignment="Left" Margin="64,85,0,0" Text="Pitch:" VerticalAlignment="Top" TextAlignment="Right"/>\r
+        <TextBox x:Name="textBox_pitch" HorizontalAlignment="Left" Height="23" Margin="107,85,0,0" Text="0" VerticalAlignment="Top" Width="75" TextAlignment="Center" LostFocus="textBox_pitch_LostFocus" KeyDown="textBox_pitch_KeyDown"/>\r
+        <TextBlock HorizontalAlignment="Left" Margin="185,85,0,0" Text="semitones" VerticalAlignment="Top" TextAlignment="Right"/>\r
+\r
+        <TextBlock HorizontalAlignment="Left" Margin="66,116,0,0" Text="Rate:" VerticalAlignment="Top" TextAlignment="Right"/>\r
+        <TextBox x:Name="textBox_rate" HorizontalAlignment="Left" Height="23" Margin="107,116,0,0" Text="0" VerticalAlignment="Top" Width="75" TextAlignment="Center" LostFocus="textBox_rate_LostFocus" KeyDown="textBox_rate_KeyDown"/>\r
+        <TextBlock HorizontalAlignment="Left" Margin="185,116,0,0" Text="%" VerticalAlignment="Top" TextAlignment="Right"/>\r
+\r
+        <Button x:Name="button_play" Content="_Play" Margin="107,150,0,0" VerticalAlignment="Top" Height="24" HorizontalAlignment="Left" Width="75" Click="button_play_Click" IsEnabled="False"/>\r
+        <Button x:Name="button_stop" Content="_Stop" Margin="200,150,0,0" VerticalAlignment="Top" Height="24" HorizontalAlignment="Left" Width="75" Click="button_stop_Click" IsEnabled="False"/>\r
+        <StatusBar VerticalAlignment="Bottom">\r
+            <TextBlock x:Name="text_status" HorizontalAlignment="Left" Margin="2,0,0,2"/>\r
+        </StatusBar>\r
+    </Grid>\r
+</Window>\r
diff --git a/source/csharp-example/MainWindow.xaml.cs b/source/csharp-example/MainWindow.xaml.cs
new file mode 100644 (file)
index 0000000..74df8d7
--- /dev/null
@@ -0,0 +1,258 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// C# example that manipulates mp3 audio files with SoundTouch library.\r
+/// \r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License for this source code file: Microsoft Public License(Ms-PL)\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+using soundtouch;\r
+using System;\r
+using System.IO;\r
+using System.Windows;\r
+using System.Windows.Controls;\r
+using System.Windows.Input;\r
+\r
+namespace csharp_example\r
+{\r
+    /// <summary>\r
+    /// Interaction logic for MainWindow.xaml\r
+    /// </summary>\r
+    public partial class MainWindow : Window\r
+    {\r
+        protected SoundProcessor processor = new SoundProcessor();\r
+\r
+        public MainWindow()\r
+        {\r
+            InitializeComponent();\r
+\r
+            StatusMessage.statusEvent += StatusEventHandler;\r
+            processor.PlaybackStopped += EventHandler_playbackStopped;\r
+            DisplaySoundTouchVersion();\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Display SoundTouch library version string in status bar. This also indicates whether the DLL was loaded successfully or not ...\r
+        /// </summary>\r
+        private void DisplaySoundTouchVersion()\r
+        {\r
+            string status;\r
+            try\r
+            {\r
+                status = String.Format("SoundTouch version: {0}", SoundTouch.Version);\r
+            }\r
+            catch (Exception exp)\r
+            {\r
+                status = exp.Message;\r
+            }\r
+            text_status.Text = status;\r
+        }\r
+\r
+\r
+        private void StatusEventHandler(object sender, string msg)\r
+        {\r
+            text_status.Text = msg;\r
+        }\r
+\r
+\r
+        // Open mp3 file for playback\r
+        private void OpenFile(string fileName)\r
+        {\r
+            Stop();\r
+            if (processor.OpenMp3File(fileName) == true)\r
+            {\r
+                textBox_filename.Text = fileName;\r
+                button_play.IsEnabled = true;\r
+                button_stop.IsEnabled = true;\r
+\r
+                // Parse adjustment settings\r
+                ParseTempoTextBox();\r
+                ParsePitchTextBox();\r
+                ParseRateTextBox();\r
+            }\r
+            else\r
+            {\r
+                textBox_filename.Text = "";\r
+                button_play.IsEnabled = false;\r
+                button_stop.IsEnabled = false;\r
+                MessageBox.Show("Coudln't open audio file " + fileName);\r
+            }\r
+        }\r
+\r
+\r
+        private void button_browse_Click(object sender, RoutedEventArgs e)\r
+        {\r
+            // Show file selection dialog\r
+            Microsoft.Win32.OpenFileDialog openDialog = new Microsoft.Win32.OpenFileDialog();\r
+            if (string.IsNullOrEmpty(textBox_filename.Text) == false)\r
+            {\r
+                // if an audio file is open, set directory to same as with the file\r
+                openDialog.InitialDirectory = Path.GetDirectoryName(textBox_filename.Text);\r
+            }\r
+            openDialog.Filter = "MP3 files (*.mp3)|*.mp3";\r
+            if (openDialog.ShowDialog() == true)\r
+            {\r
+                OpenFile(openDialog.FileName);\r
+            }\r
+        }\r
+\r
+\r
+        private void setPlayButtonMode(bool play)\r
+        {\r
+            button_play.Content = play ? "_Play" : "_Pause";\r
+        }\r
+\r
+\r
+        private void EventHandler_playbackStopped(object sender, bool hasReachedEnd)\r
+        {\r
+            if (hasReachedEnd)\r
+            {\r
+                text_status.Text = "Stopped";\r
+            }   // otherwise paused\r
+\r
+            setPlayButtonMode(true);\r
+        }\r
+\r
+\r
+        private void button_play_Click(object sender, RoutedEventArgs e)\r
+        {\r
+            if ((string)button_play.Content == "_Pause")\r
+            {\r
+                // Pause\r
+                if (processor.Pause())\r
+                {\r
+                    text_status.Text = "Paused";\r
+                }\r
+                setPlayButtonMode(true);\r
+            }\r
+            else\r
+            {\r
+                // Play\r
+                if (processor.Play())\r
+                {\r
+                    text_status.Text = "Playing";\r
+                    setPlayButtonMode(false);\r
+                }\r
+            }\r
+        }\r
+\r
+\r
+        private void Stop()\r
+        {\r
+            if (processor.Stop())\r
+            {\r
+                text_status.Text = "Stopped";\r
+            }\r
+            setPlayButtonMode(true);\r
+        }\r
+\r
+\r
+        private void button_stop_Click(object sender, RoutedEventArgs e)\r
+        {\r
+            Stop();\r
+        }\r
+\r
+\r
+        private bool parse_percentValue(TextBox box, out double value)\r
+        {\r
+            if (double.TryParse(box.Text, out value) == false) return false;\r
+            if (value < -99.0) value = -99.0;   // don't allow more than -100% slowdown ... :)\r
+            box.Text = value.ToString();\r
+            return true;\r
+        }\r
+\r
+\r
+        private void ParsePitchTextBox()\r
+        {\r
+            double pitchValue;\r
+            if (double.TryParse(textBox_pitch.Text, out pitchValue))\r
+            {\r
+                if (processor.streamProcessor != null) processor.streamProcessor.st.PitchSemiTones = (float)pitchValue;\r
+            }\r
+        }\r
+\r
+\r
+        private void ParseTempoTextBox()\r
+        {\r
+            double tempoValue;\r
+            if (parse_percentValue(textBox_tempo, out tempoValue))\r
+            {\r
+                if (processor.streamProcessor != null) processor.streamProcessor.st.TempoChange = (float)tempoValue;\r
+            }\r
+        }\r
+\r
+\r
+        private void ParseRateTextBox()\r
+        {\r
+            double rateValue;\r
+            if (parse_percentValue(textBox_rate, out rateValue))\r
+            {\r
+                if (processor.streamProcessor != null) processor.streamProcessor.st.RateChange = (float)rateValue;\r
+            }\r
+        }\r
+\r
+\r
+        private void textBox_tempo_LostFocus(object sender, RoutedEventArgs e)\r
+        {\r
+            ParseTempoTextBox();\r
+        }\r
+\r
+\r
+        private void textBox_tempo_KeyDown(object sender, KeyEventArgs e)\r
+        {\r
+            if (e.Key == Key.Enter)\r
+            {\r
+                // enter pressed -- parse value\r
+                ParseTempoTextBox();\r
+            }\r
+        }\r
+\r
+\r
+        private void textBox_pitch_LostFocus(object sender, RoutedEventArgs e)\r
+        {\r
+            ParsePitchTextBox();\r
+        }\r
+\r
+\r
+        private void textBox_pitch_KeyDown(object sender, KeyEventArgs e)\r
+        {\r
+            if (e.Key == Key.Enter)\r
+            {\r
+                // enter pressed -- parse value\r
+                ParsePitchTextBox();\r
+            }\r
+        }\r
+\r
+\r
+        private void textBox_rate_LostFocus(object sender, RoutedEventArgs e)\r
+        {\r
+            ParseRateTextBox();\r
+        }\r
+\r
+\r
+        private void textBox_rate_KeyDown(object sender, KeyEventArgs e)\r
+        {\r
+            if (e.Key == Key.Enter)\r
+            {\r
+                // enter pressed -- parse value\r
+                ParseRateTextBox();\r
+            }\r
+        }\r
+\r
+\r
+        //  Handler for file drag & drop over the window\r
+        private void Window_Drop(object sender, DragEventArgs e)\r
+        {\r
+            string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);\r
+            // open 1st of the chosen files\r
+            OpenFile(files[0]);\r
+        }\r
+    }\r
+}\r
diff --git a/source/csharp-example/NAudio-license.txt b/source/csharp-example/NAudio-license.txt
new file mode 100644 (file)
index 0000000..737c8d5
--- /dev/null
@@ -0,0 +1,31 @@
+Microsoft Public License (Ms-PL)\r
+\r
+This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software.\r
+\r
+1. Definitions\r
+\r
+The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law.\r
+\r
+A "contribution" is the original software, or any additions or changes to the software.\r
+\r
+A "contributor" is any person that distributes its contribution under this license.\r
+\r
+"Licensed patents" are a contributor's patent claims that read directly on its contribution.\r
+\r
+2. Grant of Rights\r
+\r
+(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.\r
+\r
+(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.\r
+\r
+3. Conditions and Limitations\r
+\r
+(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.\r
+\r
+(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.\r
+\r
+(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.\r
+\r
+(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.\r
+\r
+(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 
\ No newline at end of file
diff --git a/source/csharp-example/NAudio-readme.txt b/source/csharp-example/NAudio-readme.txt
new file mode 100644 (file)
index 0000000..a120799
--- /dev/null
@@ -0,0 +1,92 @@
+NAudio is an open source .NET audio library written by Mark Heath (mark.heath@gmail.com)\r
+For more information, visit http://naudio.codeplex.com\r
+NAudio is now being hosted on GitHub http://github.com/naudio/NAudio\r
+\r
+THANKS\r
+======\r
+The following list includes some of the people who have contributed in various ways to NAudio, such as code contributions,\r
+bug fixes, documentation, helping out on the forums and even donations. I haven't finished compiling this list yet, so\r
+if your name should be on it but isn't please let me know and I will include it. Also, some people I only know by their forum\r
+id, so if you want me to put your full name here, please also get in touch.\r
+\r
+in alphabetical order:\r
+Alan Jordan\r
+Alexandre Mutel\r
+Alexander Binkert\r
+AmandaTarafaMas\r
+balistof\r
+biermeester\r
+borman11\r
+bradb\r
+Brandon Hansen (kg6ypi)\r
+csechet\r
+ChunkWare Music Software\r
+CKing\r
+DaMacc\r
+Dirk Eckhardt\r
+Du10\r
+eejake52\r
+Florian Rosmann (filoe)\r
+Freefall\r
+Giawa\r
+Harald Petrovitsch\r
+Hfuy\r
+Iain McCowan\r
+Idael Cardaso \r
+ioctlLR\r
+Ivan Kochurkin (KvanTTT)\r
+Jamie Michael Ewins\r
+jannera\r
+jbaker8935\r
+jcameron23\r
+JoeGaggler\r
+jonahoffmann\r
+jontdelorme\r
+Jospin Software\r
+Justin Frankel\r
+K24A3\r
+Kamen Lichev\r
+Kassoul\r
+kevinxxx\r
+kzych\r
+LionCash\r
+Lustild\r
+Lucian Wischik (ljw1004)\r
+ManuN\r
+MeelMarcel\r
+Michael Chadwick\r
+Michael Feld \r
+Michael J\r
+Michael Lehenbauer\r
+milligan22963\r
+myrkle\r
+nelsonkidd\r
+Nigel Redmon\r
+Nikolaos Georgiou\r
+Owen Skriloff\r
+owoudenb\r
+painmailer\r
+PPavan\r
+Pygmy\r
+Ray Molenkamp\r
+Roadz\r
+Robert Bristow-Johnson\r
+Scott Fleischman \r
+Simon Clark\r
+Sirish Bajpai\r
+sporn\r
+Steve Underwood\r
+Ted Murphy\r
+Tiny Simple Tools\r
+Tobias Fleming\r
+TomBogle\r
+Tony Cabello\r
+Tony Sistemas\r
+TuneBlade\r
+topher3683\r
+volmart\r
+Vladimir Rokovanov\r
+Ville Koskinen\r
+Wyatt Rice\r
+Yuval Naveh\r
+Zsb\r
diff --git a/source/csharp-example/NAudio.dll b/source/csharp-example/NAudio.dll
new file mode 100644 (file)
index 0000000..553425e
Binary files /dev/null and b/source/csharp-example/NAudio.dll differ
diff --git a/source/csharp-example/Properties/AssemblyInfo.cs b/source/csharp-example/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..5074a34
--- /dev/null
@@ -0,0 +1,55 @@
+using System.Reflection;\r
+using System.Resources;\r
+using System.Runtime.CompilerServices;\r
+using System.Runtime.InteropServices;\r
+using System.Windows;\r
+\r
+// General Information about an assembly is controlled through the following \r
+// set of attributes. Change these attribute values to modify the information\r
+// associated with an assembly.\r
+[assembly: AssemblyTitle("csharp-example")]\r
+[assembly: AssemblyDescription("")]\r
+[assembly: AssemblyConfiguration("")]\r
+[assembly: AssemblyCompany("")]\r
+[assembly: AssemblyProduct("csharp-example")]\r
+[assembly: AssemblyCopyright("Copyright Olli Parviainen ©  2017")]\r
+[assembly: AssemblyTrademark("")]\r
+[assembly: AssemblyCulture("")]\r
+\r
+// Setting ComVisible to false makes the types in this assembly not visible \r
+// to COM components.  If you need to access a type in this assembly from \r
+// COM, set the ComVisible attribute to true on that type.\r
+[assembly: ComVisible(false)]\r
+\r
+//In order to begin building localizable applications, set \r
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file\r
+//inside a <PropertyGroup>.  For example, if you are using US english\r
+//in your source files, set the <UICulture> to en-US.  Then uncomment\r
+//the NeutralResourceLanguage attribute below.  Update the "en-US" in\r
+//the line below to match the UICulture setting in the project file.\r
+\r
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]\r
+\r
+\r
+[assembly: ThemeInfo(\r
+    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located\r
+                                     //(used if a resource is not found in the page, \r
+                                     // or application resource dictionaries)\r
+    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located\r
+                                              //(used if a resource is not found in the page, \r
+                                              // app, or any theme specific resource dictionaries)\r
+)]\r
+\r
+\r
+// Version information for an assembly consists of the following four values:\r
+//\r
+//      Major Version\r
+//      Minor Version \r
+//      Build Number\r
+//      Revision\r
+//\r
+// You can specify all the values or you can default the Build and Revision Numbers \r
+// by using the '*' as shown below:\r
+// [assembly: AssemblyVersion("1.0.*")]\r
+[assembly: AssemblyVersion("1.0.0.0")]\r
+[assembly: AssemblyFileVersion("1.0.0.0")]\r
diff --git a/source/csharp-example/Properties/Resources.Designer.cs b/source/csharp-example/Properties/Resources.Designer.cs
new file mode 100644 (file)
index 0000000..6b3a098
--- /dev/null
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------\r
+// <auto-generated>\r
+//     This code was generated by a tool.\r
+//     Runtime Version:4.0.30319.42000\r
+//\r
+//     Changes to this file may cause incorrect behavior and will be lost if\r
+//     the code is regenerated.\r
+// </auto-generated>\r
+//------------------------------------------------------------------------------\r
+\r
+namespace csharp_example.Properties\r
+{\r
+\r
+\r
+    /// <summary>\r
+    ///   A strongly-typed resource class, for looking up localized strings, etc.\r
+    /// </summary>\r
+    // This class was auto-generated by the StronglyTypedResourceBuilder\r
+    // class via a tool like ResGen or Visual Studio.\r
+    // To add or remove a member, edit your .ResX file then rerun ResGen\r
+    // with the /str option, or rebuild your VS project.\r
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]\r
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\r
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\r
+    internal class Resources\r
+    {\r
+\r
+        private static global::System.Resources.ResourceManager resourceMan;\r
+\r
+        private static global::System.Globalization.CultureInfo resourceCulture;\r
+\r
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]\r
+        internal Resources()\r
+        {\r
+        }\r
+\r
+        /// <summary>\r
+        ///   Returns the cached ResourceManager instance used by this class.\r
+        /// </summary>\r
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r
+        internal static global::System.Resources.ResourceManager ResourceManager\r
+        {\r
+            get\r
+            {\r
+                if ((resourceMan == null))\r
+                {\r
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("csharp_example.Properties.Resources", typeof(Resources).Assembly);\r
+                    resourceMan = temp;\r
+                }\r
+                return resourceMan;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        ///   Overrides the current thread's CurrentUICulture property for all\r
+        ///   resource lookups using this strongly typed resource class.\r
+        /// </summary>\r
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]\r
+        internal static global::System.Globalization.CultureInfo Culture\r
+        {\r
+            get\r
+            {\r
+                return resourceCulture;\r
+            }\r
+            set\r
+            {\r
+                resourceCulture = value;\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/source/csharp-example/Properties/Resources.resx b/source/csharp-example/Properties/Resources.resx
new file mode 100644 (file)
index 0000000..ffecec8
--- /dev/null
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<root>\r
+  <!-- \r
+    Microsoft ResX Schema \r
+    \r
+    Version 2.0\r
+    \r
+    The primary goals of this format is to allow a simple XML format \r
+    that is mostly human readable. The generation and parsing of the \r
+    various data types are done through the TypeConverter classes \r
+    associated with the data types.\r
+    \r
+    Example:\r
+    \r
+    ... ado.net/XML headers & schema ...\r
+    <resheader name="resmimetype">text/microsoft-resx</resheader>\r
+    <resheader name="version">2.0</resheader>\r
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>\r
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>\r
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>\r
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>\r
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">\r
+        <value>[base64 mime encoded serialized .NET Framework object]</value>\r
+    </data>\r
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">\r
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>\r
+        <comment>This is a comment</comment>\r
+    </data>\r
+                \r
+    There are any number of "resheader" rows that contain simple \r
+    name/value pairs.\r
+    \r
+    Each data row contains a name, and value. The row also contains a \r
+    type or mimetype. Type corresponds to a .NET class that support \r
+    text/value conversion through the TypeConverter architecture. \r
+    Classes that don't support this are serialized and stored with the \r
+    mimetype set.\r
+    \r
+    The mimetype is used for serialized objects, and tells the \r
+    ResXResourceReader how to depersist the object. This is currently not \r
+    extensible. For a given mimetype the value must be set accordingly:\r
+    \r
+    Note - application/x-microsoft.net.object.binary.base64 is the format \r
+    that the ResXResourceWriter will generate, however the reader can \r
+    read any of the formats listed below.\r
+    \r
+    mimetype: application/x-microsoft.net.object.binary.base64\r
+    value   : The object must be serialized with \r
+            : System.Serialization.Formatters.Binary.BinaryFormatter\r
+            : and then encoded with base64 encoding.\r
+    \r
+    mimetype: application/x-microsoft.net.object.soap.base64\r
+    value   : The object must be serialized with \r
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter\r
+            : and then encoded with base64 encoding.\r
+\r
+    mimetype: application/x-microsoft.net.object.bytearray.base64\r
+    value   : The object must be serialized into a byte array \r
+            : using a System.ComponentModel.TypeConverter\r
+            : and then encoded with base64 encoding.\r
+    -->\r
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">\r
+    <xsd:element name="root" msdata:IsDataSet="true">\r
+      <xsd:complexType>\r
+        <xsd:choice maxOccurs="unbounded">\r
+          <xsd:element name="metadata">\r
+            <xsd:complexType>\r
+              <xsd:sequence>\r
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />\r
+              </xsd:sequence>\r
+              <xsd:attribute name="name" type="xsd:string" />\r
+              <xsd:attribute name="type" type="xsd:string" />\r
+              <xsd:attribute name="mimetype" type="xsd:string" />\r
+            </xsd:complexType>\r
+          </xsd:element>\r
+          <xsd:element name="assembly">\r
+            <xsd:complexType>\r
+              <xsd:attribute name="alias" type="xsd:string" />\r
+              <xsd:attribute name="name" type="xsd:string" />\r
+            </xsd:complexType>\r
+          </xsd:element>\r
+          <xsd:element name="data">\r
+            <xsd:complexType>\r
+              <xsd:sequence>\r
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />\r
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />\r
+              </xsd:sequence>\r
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />\r
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />\r
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />\r
+            </xsd:complexType>\r
+          </xsd:element>\r
+          <xsd:element name="resheader">\r
+            <xsd:complexType>\r
+              <xsd:sequence>\r
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />\r
+              </xsd:sequence>\r
+              <xsd:attribute name="name" type="xsd:string" use="required" />\r
+            </xsd:complexType>\r
+          </xsd:element>\r
+        </xsd:choice>\r
+      </xsd:complexType>\r
+    </xsd:element>\r
+  </xsd:schema>\r
+  <resheader name="resmimetype">\r
+    <value>text/microsoft-resx</value>\r
+  </resheader>\r
+  <resheader name="version">\r
+    <value>2.0</value>\r
+  </resheader>\r
+  <resheader name="reader">\r
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r
+  </resheader>\r
+  <resheader name="writer">\r
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>\r
+  </resheader>\r
+</root>
\ No newline at end of file
diff --git a/source/csharp-example/Properties/Settings.Designer.cs b/source/csharp-example/Properties/Settings.Designer.cs
new file mode 100644 (file)
index 0000000..9408dff
--- /dev/null
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------\r
+// <auto-generated>\r
+//     This code was generated by a tool.\r
+//     Runtime Version:4.0.30319.42000\r
+//\r
+//     Changes to this file may cause incorrect behavior and will be lost if\r
+//     the code is regenerated.\r
+// </auto-generated>\r
+//------------------------------------------------------------------------------\r
+\r
+namespace csharp_example.Properties\r
+{\r
+\r
+\r
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]\r
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]\r
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase\r
+    {\r
+\r
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));\r
+\r
+        public static Settings Default\r
+        {\r
+            get\r
+            {\r
+                return defaultInstance;\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/source/csharp-example/Properties/Settings.settings b/source/csharp-example/Properties/Settings.settings
new file mode 100644 (file)
index 0000000..8f2fd95
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>\r
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">\r
+  <Profiles>\r
+    <Profile Name="(Default)" />\r
+  </Profiles>\r
+  <Settings />\r
+</SettingsFile>
\ No newline at end of file
diff --git a/source/csharp-example/README.txt b/source/csharp-example/README.txt
new file mode 100644 (file)
index 0000000..8094f50
--- /dev/null
@@ -0,0 +1,9 @@
+csharp-example\r
+==============\r
+Copyright (c) Olli Parviainen\r
+\r
+This is a C# example application that plays MP3 audio file and \r
+uses SoundTouch.dll library for adjusting the sound in real-time.\r
+\r
+The example uses NAudio library for MP3 file reading and audio playback. \r
+See NAudio-readme.txt and NAudio-license.txt for NAudio information.\r
diff --git a/source/csharp-example/SoundProcessor.cs b/source/csharp-example/SoundProcessor.cs
new file mode 100644 (file)
index 0000000..d8f4d42
--- /dev/null
@@ -0,0 +1,292 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// WaveStream processor class for manipulating audio stream in C# with \r
+/// SoundTouch library.\r
+/// \r
+/// This module uses NAudio library for C# audio file input / output\r
+/// \r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License for this source code file: Microsoft Public License(Ms-PL)\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+using NAudio.Wave;\r
+using soundtouch;\r
+using System;\r
+\r
+namespace csharp_example\r
+{\r
+    /// <summary>\r
+    /// Helper class that allow writing status texts to the host application\r
+    /// </summary>\r
+    public class StatusMessage\r
+    {\r
+        /// <summary>\r
+        /// Handler for status message events. Subscribe this from the host application\r
+        /// </summary>\r
+        public static event EventHandler<string> statusEvent;\r
+\r
+        /// <summary>\r
+        /// Pass a status message to the host application\r
+        /// </summary>\r
+        public static void Write(string msg)\r
+        {\r
+            if (statusEvent != null)\r
+            {\r
+                statusEvent(null, msg);\r
+            }\r
+        }\r
+    }\r
+\r
+    /// <summary>\r
+    /// NAudui WaveStream class for processing audio stream with SoundTouch effects\r
+    /// </summary>\r
+    public class WaveStreamProcessor : WaveStream\r
+    {\r
+        private WaveChannel32 inputStr;\r
+        public SoundTouch st;\r
+\r
+        private byte[] bytebuffer = new byte[4096];\r
+        private float[] floatbuffer = new float[1024];\r
+        bool endReached = false;\r
+\r
+\r
+        /// <summary>\r
+        /// Constructor\r
+        /// </summary>\r
+        /// <param name="input">WaveChannel32 stream used for processor stream input</param>\r
+        public WaveStreamProcessor(WaveChannel32 input)\r
+        {\r
+            inputStr = input;\r
+            st = new SoundTouch();\r
+            st.Channels = (uint)input.WaveFormat.Channels;\r
+            st.SampleRate = (uint)input.WaveFormat.SampleRate;\r
+        }\r
+\r
+        /// <summary>\r
+        /// True if end of stream reached\r
+        /// </summary>\r
+        public bool EndReached\r
+        {\r
+            get { return endReached; }\r
+        }\r
+\r
+\r
+        public override long Length\r
+        {\r
+            get\r
+            {\r
+                return inputStr.Length;\r
+            }\r
+        }\r
+\r
+\r
+        public override long Position\r
+        {\r
+            get\r
+            {\r
+                return inputStr.Position;\r
+            }\r
+\r
+            set\r
+            {\r
+                inputStr.Position = value;\r
+            }\r
+        }\r
+\r
+\r
+        public override WaveFormat WaveFormat\r
+        {\r
+            get\r
+            {\r
+                return inputStr.WaveFormat;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Overridden Read function that returns samples processed with SoundTouch. Returns data in same format as\r
+        /// WaveChannel32 i.e. stereo float samples.\r
+        /// </summary>\r
+        /// <param name="buffer">Buffer where to return sample data</param>\r
+        /// <param name="offset">Offset from beginning of the buffer</param>\r
+        /// <param name="count">Number of bytes to return</param>\r
+        /// <returns>Number of bytes copied to buffer</returns>\r
+        public override int Read(byte[] buffer, int offset, int count)\r
+        {\r
+            try\r
+            {\r
+                // Iterate until enough samples available for output:\r
+                // - read samples from input stream\r
+                // - put samples to SoundStretch processor\r
+                while (st.AvailableSampleCount < count)\r
+                {\r
+                    int nbytes = inputStr.Read(bytebuffer, 0, bytebuffer.Length);\r
+                    if (nbytes == 0)\r
+                    {\r
+                        // end of stream. flush final samples from SoundTouch buffers to output\r
+                        if (endReached == false)\r
+                        {\r
+                            endReached = true;  // do only once to avoid continuous flushing\r
+                            st.Flush();\r
+                        }\r
+                        break;\r
+                    }\r
+\r
+                    // binary copy data from "byte[]" to "float[]" buffer\r
+                    Buffer.BlockCopy(bytebuffer, 0, floatbuffer, 0, nbytes);\r
+                    st.PutSamples(floatbuffer, (uint)(nbytes / 8));\r
+                }\r
+\r
+                // ensure that buffer is large enough to receive desired amount of data out\r
+                if (floatbuffer.Length < count / 4)\r
+                {\r
+                    floatbuffer = new float[count / 4];\r
+                }\r
+                // get processed output samples from SoundTouch\r
+                int numsamples = (int)st.ReceiveSamples(floatbuffer, (uint)(count / 8));\r
+                // binary copy data from "float[]" to "byte[]" buffer\r
+                Buffer.BlockCopy(floatbuffer, 0, buffer, offset, numsamples * 8);\r
+                return numsamples * 8;  // number of bytes\r
+            }\r
+            catch (Exception exp)\r
+            {\r
+                StatusMessage.Write("exception in WaveStreamProcessor.Read: " + exp.Message);\r
+                return 0;\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Clear the internal processor buffers. Call this if seeking or rewinding to new position within the stream.\r
+        /// </summary>\r
+        public void Clear()\r
+        {\r
+            st.Clear();\r
+            endReached = false;\r
+        }\r
+    }\r
+\r
+\r
+    /// <summary>\r
+    /// Class that opens & plays MP3 file and allows real-time audio processing with SoundTouch\r
+    /// while playing\r
+    /// </summary>\r
+    public class SoundProcessor\r
+    {\r
+        Mp3FileReader mp3File;\r
+        WaveOut waveOut;\r
+        public WaveStreamProcessor streamProcessor;\r
+\r
+\r
+        /// <summary>\r
+        /// Start / resume playback\r
+        /// </summary>\r
+        /// <returns>true if successful, false if audio file not open</returns>\r
+        public bool Play()\r
+        {\r
+            if (waveOut == null) return false;\r
+\r
+            if (waveOut.PlaybackState != PlaybackState.Playing)\r
+            {\r
+                waveOut.Play();\r
+            }\r
+            return true;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Pause playback\r
+        /// </summary>\r
+        /// <returns>true if successful, false if audio not playing</returns>\r
+        public bool Pause()\r
+        {\r
+            if (waveOut == null) return false;\r
+\r
+            if (waveOut.PlaybackState == PlaybackState.Playing)\r
+            {\r
+                waveOut.Stop();\r
+                return true;\r
+            }\r
+            return false;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Stop playback\r
+        /// </summary>\r
+        /// <returns>true if successful, false if audio file not open</returns>\r
+        public bool Stop()\r
+        {\r
+            if (waveOut == null) return false;\r
+\r
+            waveOut.Stop();\r
+            mp3File.Position = 0;\r
+            streamProcessor.Clear();\r
+            return true;\r
+        }\r
+\r
+\r
+\r
+        /// <summary>\r
+        /// Event for "playback stopped" event. 'bool' argument is true if playback has reached end of stream.\r
+        /// </summary>\r
+        public event EventHandler<bool> PlaybackStopped;\r
+\r
+\r
+        /// <summary>\r
+        /// Proxy event handler for receiving playback stopped event from WaveOut\r
+        /// </summary>\r
+        protected void EventHandler_stopped(object sender, StoppedEventArgs args)\r
+        {\r
+            bool isEnd = streamProcessor.EndReached;\r
+            if (isEnd)\r
+            {\r
+                Stop();\r
+            }\r
+            if (PlaybackStopped != null)\r
+            {\r
+                PlaybackStopped(sender, isEnd);\r
+            }\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Open MP3 file\r
+        /// </summary>\r
+        /// <param name="filePath">Path to file to open</param>\r
+        /// <returns>true if successful</returns>\r
+        public bool OpenMp3File(string filePath)\r
+        {\r
+            try\r
+            {\r
+                mp3File = new Mp3FileReader(filePath);\r
+                WaveChannel32 inputStream = new WaveChannel32(mp3File);\r
+                inputStream.PadWithZeroes = false;  // don't pad, otherwise the stream never ends\r
+                streamProcessor = new WaveStreamProcessor(inputStream);\r
+\r
+                waveOut = new WaveOut()\r
+                {\r
+                    DesiredLatency = 100\r
+                };\r
+\r
+                waveOut.Init(streamProcessor);  // inputStream);\r
+                waveOut.PlaybackStopped += EventHandler_stopped;\r
+\r
+                StatusMessage.Write("Opened file " + filePath);\r
+                return true;\r
+            }\r
+            catch (Exception exp)\r
+            {\r
+                // Error in opening file\r
+                waveOut = null;\r
+                StatusMessage.Write("Can't open file: " + exp.Message);\r
+                return false;\r
+            }\r
+\r
+        }\r
+    }\r
+}\r
diff --git a/source/csharp-example/SoundTouch.cs b/source/csharp-example/SoundTouch.cs
new file mode 100644 (file)
index 0000000..d68df6a
--- /dev/null
@@ -0,0 +1,681 @@
+//////////////////////////////////////////////////////////////////////////////\r
+///\r
+/// C# wrapper to access SoundTouch APIs from an external SoundTouch.dll library\r
+///\r
+/// Author        : Copyright (c) Olli Parviainen\r
+/// Author e-mail : oparviai 'at' iki.fi\r
+/// SoundTouch WWW: http://www.surina.net/soundtouch\r
+///\r
+/// The C# wrapper improved by Mario Di Vece\r
+///\r
+////////////////////////////////////////////////////////////////////////////////\r
+//\r
+// License :\r
+//\r
+//  SoundTouch audio processing library\r
+//  Copyright (c) Olli Parviainen\r
+//\r
+//  This library is free software; you can redistribute it and/or\r
+//  modify it under the terms of the GNU Lesser General Public\r
+//  License as published by the Free Software Foundation; either\r
+//  version 2.1 of the License, or (at your option) any later version.\r
+//\r
+//  This library is distributed in the hope that it will be useful,\r
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+//  Lesser General Public License for more details.\r
+//\r
+//  You should have received a copy of the GNU Lesser General Public\r
+//  License along with this library; if not, write to the Free Software\r
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+//\r
+////////////////////////////////////////////////////////////////////////////////\r
+\r
+using System;\r
+using System.Runtime.InteropServices;\r
+\r
+namespace soundtouch\r
+{\r
+    public sealed class SoundTouch : IDisposable\r
+    {\r
+        #region Internal Members\r
+        internal const string SoundTouchLibrary = "SoundTouch.dll";\r
+        #endregion\r
+\r
+        #region Private Members // hahaha what a curious region\r
+\r
+        private readonly object SyncRoot = new object();\r
+        private bool IsDisposed = false;\r
+        private IntPtr handle;\r
+\r
+        #endregion\r
+\r
+        #region Constructor\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the <see cref="SoundTouch"/> class.\r
+        /// </summary>\r
+        public SoundTouch()\r
+        {\r
+            handle = NativeMethods.CreateInstance();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Finalizes an instance of the <see cref="SoundTouch"/> class.\r
+        /// </summary>\r
+        ~SoundTouch()\r
+        {\r
+            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.\r
+            Dispose(false);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Settings as defined in SoundTouch.h\r
+        /// </summary>\r
+        public enum Setting\r
+        {\r
+            /// <summary>\r
+            /// Enable/disable anti-alias filter in pitch transposer (0 = disable)\r
+            /// </summary>\r
+            UseAntiAliasFilter = 0,\r
+\r
+            /// <summary>\r
+            /// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)\r
+            /// </summary>\r
+            AntiAliasFilterLength = 1,\r
+\r
+            /// <summary>\r
+            /// Enable/disable quick seeking algorithm in tempo changer routine\r
+            /// (enabling quick seeking lowers CPU utilization but causes a minor sound\r
+            ///  quality compromising)\r
+            /// </summary>\r
+            UseQuickSeek = 2,\r
+\r
+            /// <summary>\r
+            /// Time-stretch algorithm single processing sequence length in milliseconds. This determines \r
+            /// to how long sequences the original sound is chopped in the time-stretch algorithm. \r
+            /// See "STTypes.h" or README for more information.\r
+            /// </summary>\r
+            SequenceMilliseconds = 3,\r
+\r
+            /// <summary>\r
+            /// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the \r
+            /// best possible overlapping location. This determines from how wide window the algorithm \r
+            /// may look for an optimal joining location when mixing the sound sequences back together. \r
+            /// See "STTypes.h" or README for more information.\r
+            /// </summary>\r
+            SeekWindowMilliseconds = 4,\r
+\r
+            /// <summary>\r
+            /// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences \r
+            /// are mixed back together, to form a continuous sound stream, this parameter defines over \r
+            /// how long period the two consecutive sequences are let to overlap each other. \r
+            /// See "STTypes.h" or README for more information.\r
+            /// </summary>\r
+            OverlapMilliseconds = 5,\r
+\r
+            /// <summary>\r
+            /// Call "getSetting" with this ID to query processing sequence size in samples. \r
+            /// This value gives approximate value of how many input samples you'll need to \r
+            /// feed into SoundTouch after initial buffering to get out a new batch of\r
+            /// output samples. \r
+            ///\r
+            /// This value does not include initial buffering at beginning of a new processing \r
+            /// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size.\r
+            ///\r
+            /// Notices: \r
+            /// - This is read-only parameter, i.e. setSetting ignores this parameter\r
+            /// - This parameter value is not constant but change depending on \r
+            ///   tempo/pitch/rate/samplerate settings.\r
+            /// </summary>\r
+            NominalInputSequence = 6,\r
+\r
+            /// <summary>\r
+            /// Call "getSetting" with this ID to query nominal average processing output \r
+            /// size in samples. This value tells approcimate value how many output samples \r
+            /// SoundTouch outputs once it does DSP processing run for a batch of input samples.\r
+            ///\r
+            /// Notices: \r
+            /// - This is read-only parameter, i.e. setSetting ignores this parameter\r
+            /// - This parameter value is not constant but change depending on \r
+            ///   tempo/pitch/rate/samplerate settings.\r
+            /// </summary>\r
+            NominalOutputSequence = 7,\r
+\r
+            /// <summary>\r
+            /// Call "getSetting" with this ID to query initial processing latency, i.e.\r
+            /// approx. how many samples you'll need to enter to SoundTouch pipeline before \r
+            /// you can expect to get first batch of ready output samples out. \r
+            ///\r
+            /// After the first output batch, you can then expect to get approx. \r
+            /// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every\r
+            /// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch.\r
+            ///\r
+            /// Example:\r
+            ///     processing with parameter -tempo=5\r
+            ///     => initial latency = 5509 samples\r
+            ///        input sequence  = 4167 samples\r
+            ///        output sequence = 3969 samples\r
+            ///\r
+            /// Accordingly, you can expect to feed in approx. 5509 samples at beginning of \r
+            /// the stream, and then you'll get out the first 3969 samples. After that, for \r
+            /// every approx. 4167 samples that you'll put in, you'll receive again approx. \r
+            /// 3969 samples out.\r
+            ///\r
+            /// This also means that average latency during stream processing is \r
+            /// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2 \r
+            /// = 3524 samples\r
+            /// \r
+            /// Notices: \r
+            /// - This is read-only parameter, i.e. setSetting ignores this parameter\r
+            /// - This parameter value is not constant but change depending on \r
+            ///   tempo/pitch/rate/samplerate settings.\r
+            /// </summary>\r
+            InitialLatency = 8,\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Get SoundTouch version string\r
+        /// </summary>\r
+        public static string Version\r
+        {\r
+            get\r
+            {\r
+                // convert "char *" data to c# string\r
+                return Marshal.PtrToStringAnsi(NativeMethods.GetVersionString());\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Gets a value indicating whether the SoundTouch Library (dll) is available\r
+        /// </summary>\r
+        public static bool IsAvailable\r
+        {\r
+            get\r
+            {\r
+                try\r
+                {\r
+                    var versionId = NativeMethods.GetVersionId();\r
+                    return versionId != 0;\r
+                }\r
+                catch\r
+                {\r
+                    return false;\r
+                }\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Returns number of processed samples currently available in SoundTouch for immediate output.\r
+        /// </summary>\r
+        public uint AvailableSampleCount\r
+        {\r
+            get { lock (SyncRoot) { return NativeMethods.NumSamples(handle); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Returns number of samples currently unprocessed in SoundTouch internal buffer\r
+        /// </summary>\r
+        /// <returns>Number of sample frames</returns>\r
+        public uint UnprocessedSampleCount\r
+        {\r
+            get { lock (SyncRoot) { return NativeMethods.NumUnprocessedSamples(handle); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Check if there aren't any samples available for outputting.\r
+        /// </summary>\r
+        /// <returns>nonzero if there aren't any samples available for outputting</returns>\r
+        public int IsEmpty\r
+        {\r
+            get { lock (SyncRoot) { return NativeMethods.IsEmpty(handle); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets the number of channels\r
+        /// \r
+        /// Value: 1 = mono, 2 = stereo, n = multichannel\r
+        /// </summary>\r
+        public uint Channels\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetChannels(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets sample rate.\r
+        /// Value: Sample rate, e.g. 44100\r
+        /// </summary>\r
+        public uint SampleRate\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetSampleRate(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets new tempo control value. \r
+        /// \r
+        /// Value: Tempo setting. Normal tempo = 1.0, smaller values\r
+        /// represent slower tempo, larger faster tempo.\r
+        /// </summary>\r
+        public float Tempo\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetTempo(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets new tempo control value as a difference in percents compared\r
+        /// to the original tempo (-50 .. +100 %);\r
+        /// </summary>\r
+        public float TempoChange\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetTempoChange(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets new rate control value. \r
+        /// Rate setting. Normal rate = 1.0, smaller values\r
+        /// represent slower rate, larger faster rate.\r
+        /// </summary>\r
+        public float Rate\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetTempo(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets new rate control value as a difference in percents compared\r
+        /// to the original rate (-50 .. +100 %);\r
+        /// \r
+        /// Value: Rate setting is in %\r
+        /// </summary>\r
+        public float RateChange\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetRateChange(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets new pitch control value. \r
+        /// \r
+        /// Value: Pitch setting. Original pitch = 1.0, smaller values\r
+        /// represent lower pitches, larger values higher pitch.\r
+        /// </summary>\r
+        public float Pitch\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetPitch(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets pitch change in octaves compared to the original pitch  \r
+        /// (-1.00 .. +1.00 for +- one octave);\r
+        /// \r
+        /// Value: Pitch setting in octaves\r
+        /// </summary>\r
+        public float PitchOctaves\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetPitchOctaves(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Sets pitch change in semi-tones compared to the original pitch\r
+        /// (-12 .. +12 for +- one octave);\r
+        /// \r
+        /// Value: Pitch setting in semitones\r
+        /// </summary>\r
+        public float PitchSemiTones\r
+        {\r
+            set { lock (SyncRoot) { NativeMethods.SetPitchSemiTones(handle, value); } }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Changes or gets a setting controlling the processing system behaviour. See the\r
+        /// 'SETTING_...' defines for available setting ID's.\r
+        /// </summary>\r
+        /// <value>\r
+        /// The <see cref="System.Int32"/>.\r
+        /// </value>\r
+        /// <param name="settingId">The setting identifier.</param>\r
+        /// <returns>The value of the setting</returns>\r
+        public int this[Setting settingId]\r
+        {\r
+            get\r
+            {\r
+                lock (SyncRoot) { return NativeMethods.GetSetting(handle, (int)settingId); }\r
+            }\r
+            set\r
+            {\r
+                lock (SyncRoot) { NativeMethods.SetSetting(handle, (int)settingId, value); }\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Sample Stream Methods\r
+\r
+        /// <summary>\r
+        /// Flushes the last samples from the processing pipeline to the output.\r
+        /// Clears also the internal processing buffers.\r
+        /// \r
+        /// Note: This function is meant for extracting the last samples of a sound\r
+        /// stream. This function may introduce additional blank samples in the end\r
+        /// of the sound stream, and thus it's not recommended to call this function\r
+        /// in the middle of a sound stream.\r
+        /// </summary>\r
+        public void Flush()\r
+        {\r
+            lock (SyncRoot) { NativeMethods.Flush(handle); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Clears all the samples in the object's output and internal processing\r
+        /// buffers.\r
+        /// </summary>\r
+        public void Clear()\r
+        {\r
+            lock (SyncRoot) { NativeMethods.Clear(handle); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Adds 'numSamples' pcs of samples from the 'samples' memory position into\r
+        /// the input of the object. Notice that sample rate _has_to_ be set before\r
+        /// calling this function, otherwise throws a runtime_error exception.\r
+        /// </summary>\r
+        /// <param name="samples">Sample buffer to input</param>\r
+        /// <param name="numSamples">Number of sample frames in buffer. Notice\r
+        /// that in case of multi-channel sound a single sample frame contains \r
+        /// data for all channels</param>\r
+        public void PutSamples(float[] samples, uint numSamples)\r
+        {\r
+            lock (SyncRoot) { NativeMethods.PutSamples(handle, samples, numSamples); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// int16 version of putSamples(): This accept int16 (short) sample data\r
+        /// and internally converts it to float format before processing\r
+        /// </summary>\r
+        /// <param name="samples">Sample input buffer.</param>\r
+        /// <param name="numSamples">Number of sample frames in buffer. Notice\r
+        /// that in case of multi-channel sound a single \r
+        /// sample frame contains data for all channels.</param>\r
+        public void PutSamplesI16(short[] samples, uint numSamples)\r
+        {\r
+            lock (SyncRoot) { NativeMethods.PutSamples_i16(handle, samples, numSamples); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Receive processed samples from the processor.\r
+        /// </summary>\r
+        /// <param name="outBuffer">Buffer where to copy output samples</param>\r
+        /// <param name="maxSamples">Max number of sample frames to receive</param>\r
+        /// <returns>The number of samples received</returns>\r
+        public uint ReceiveSamples(float[] outBuffer, uint maxSamples)\r
+        {\r
+            lock (SyncRoot) { return NativeMethods.ReceiveSamples(handle, outBuffer, maxSamples); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// int16 version of receiveSamples(): This converts internal float samples\r
+        /// into int16 (short) return data type\r
+        /// </summary>\r
+        /// <param name="outBuffer">Buffer where to copy output samples.</param>\r
+        /// <param name="maxSamples">How many samples to receive at max.</param>\r
+        /// <returns>Number of received sample frames</returns>\r
+        public uint ReceiveSamplesI16(short[] outBuffer, uint maxSamples)\r
+        {\r
+            lock (SyncRoot) { return NativeMethods.ReceiveSamples_i16(handle, outBuffer, maxSamples); }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IDisposable Support\r
+\r
+        /// <summary>\r
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\r
+        /// </summary>\r
+        public void Dispose()\r
+        {\r
+            Dispose(true);\r
+            GC.SuppressFinalize(this);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Releases unmanaged and - optionally - managed resources.\r
+        /// </summary>\r
+        /// <param name="alsoManaged"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>\r
+        private void Dispose(bool alsoManaged)\r
+        {\r
+            if (!IsDisposed)\r
+            {\r
+                if (alsoManaged)\r
+                {\r
+                    // NOTE: Placeholder, dispose managed state (managed objects).\r
+                    // At this point, nothing managed to dispose\r
+                }\r
+\r
+                NativeMethods.DestroyInstance(handle);\r
+                handle = IntPtr.Zero;\r
+\r
+                IsDisposed = true;\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Native Methods\r
+\r
+        /// <summary>\r
+        /// Provides direct access to mapped DLL methods\r
+        /// </summary>\r
+        private static class NativeMethods\r
+        {\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_getVersionId")]\r
+            public static extern int GetVersionId();\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_createInstance")]\r
+            public static extern IntPtr CreateInstance();\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_destroyInstance")]\r
+            public static extern void DestroyInstance(IntPtr h);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_getVersionString")]\r
+            public static extern IntPtr GetVersionString();\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setRate")]\r
+            public static extern void SetRate(IntPtr h, float newRate);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setTempo")]\r
+            public static extern void SetTempo(IntPtr h, float newTempo);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setRateChange")]\r
+            public static extern void SetRateChange(IntPtr h, float newRate);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setTempoChange")]\r
+            public static extern void SetTempoChange(IntPtr h, float newTempo);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setPitch")]\r
+            public static extern void SetPitch(IntPtr h, float newPitch);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setPitchOctaves")]\r
+            public static extern void SetPitchOctaves(IntPtr h, float newPitch);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setPitchSemiTones")]\r
+            public static extern void SetPitchSemiTones(IntPtr h, float newPitch);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setChannels")]\r
+            public static extern void SetChannels(IntPtr h, uint numChannels);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setSampleRate")]\r
+            public static extern void SetSampleRate(IntPtr h, uint srate);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_flush")]\r
+            public static extern void Flush(IntPtr h);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_putSamples")]\r
+            public static extern void PutSamples(IntPtr h, float[] samples, uint numSamples);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_putSamples_i16")]\r
+            public static extern void PutSamples_i16(IntPtr h, short[] samples, uint numSamples);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_clear")]\r
+            public static extern void Clear(IntPtr h);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_setSetting")]\r
+            public static extern int SetSetting(IntPtr h, int settingId, int value);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_getSetting")]\r
+            public static extern int GetSetting(IntPtr h, int settingId);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_numUnprocessedSamples")]\r
+            public static extern uint NumUnprocessedSamples(IntPtr h);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_receiveSamples")]\r
+            public static extern uint ReceiveSamples(IntPtr h, float[] outBuffer, uint maxSamples);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_receiveSamples_i16")]\r
+            public static extern uint ReceiveSamples_i16(IntPtr h, short[] outBuffer, uint maxSamples);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_numSamples")]\r
+            public static extern uint NumSamples(IntPtr h);\r
+\r
+            [DllImport(SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "soundtouch_isEmpty")]\r
+            public static extern int IsEmpty(IntPtr h);\r
+        }\r
+\r
+        #endregion\r
+    }\r
+\r
+\r
+    public sealed class BPMDetect : IDisposable\r
+    {\r
+        #region Private Members\r
+\r
+        private readonly object SyncRoot = new object();\r
+        private bool IsDisposed = false;\r
+        private IntPtr handle;\r
+\r
+        #endregion\r
+\r
+        #region Constructor\r
+\r
+        /// <summary>\r
+        /// Initializes a new instance of the <see cref="BPMDetect"/> class.\r
+        /// </summary>\r
+        public BPMDetect(int numChannels, int sampleRate)\r
+        {\r
+            handle = NativeMethods.BpmCreateInstance(numChannels, sampleRate);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Finalizes an instance of the <see cref="BPMDetect"/> class.\r
+        /// </summary>\r
+        ~BPMDetect()\r
+        {\r
+            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.\r
+            Dispose(false);\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Properties\r
+\r
+        /// <summary>\r
+        /// Returns the analysed BPM rate.\r
+        /// </summary>\r
+        public float Bpm\r
+        {\r
+            get { lock (SyncRoot) { return NativeMethods.BpmGet(handle); } }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Sample Stream Methods\r
+\r
+        /// <summary>\r
+        /// Feed 'numSamples' sample into the BPM detector\r
+        /// </summary>\r
+        /// <param name="samples">Sample buffer to input</param>\r
+        /// <param name="numSamples">Number of sample frames in buffer. Notice\r
+        /// that in case of multi-channel sound a single sample frame contains \r
+        /// data for all channels</param>\r
+        public void PutSamples(float[] samples, uint numSamples)\r
+        {\r
+            lock (SyncRoot) { NativeMethods.BpmPutSamples(handle, samples, numSamples); }\r
+        }\r
+\r
+        /// <summary>\r
+        /// int16 version of putSamples(): This accept int16 (short) sample data\r
+        /// and internally converts it to float format before processing\r
+        /// </summary>\r
+        /// <param name="samples">Sample input buffer.</param>\r
+        /// <param name="numSamples">Number of sample frames in buffer. Notice\r
+        /// that in case of multi-channel sound a single \r
+        /// sample frame contains data for all channels.</param>\r
+        public void PutSamplesI16(short[] samples, uint numSamples)\r
+        {\r
+            lock (SyncRoot) { NativeMethods.BpmPutSamples_i16(handle, samples, numSamples); }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region IDisposable Support\r
+\r
+        /// <summary>\r
+        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\r
+        /// </summary>\r
+        public void Dispose()\r
+        {\r
+            Dispose(true);\r
+            GC.SuppressFinalize(this);\r
+        }\r
+\r
+        /// <summary>\r
+        /// Releases unmanaged and - optionally - managed resources.\r
+        /// </summary>\r
+        /// <param name="alsoManaged"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>\r
+        private void Dispose(bool alsoManaged)\r
+        {\r
+            if (!IsDisposed)\r
+            {\r
+                if (alsoManaged)\r
+                {\r
+                    // NOTE: Placeholder, dispose managed state (managed objects).\r
+                    // At this point, nothing managed to dispose\r
+                }\r
+\r
+                NativeMethods.BpmDestroyInstance(handle);\r
+                handle = IntPtr.Zero;\r
+\r
+                IsDisposed = true;\r
+            }\r
+        }\r
+\r
+        #endregion\r
+\r
+        #region Native Methods\r
+\r
+        /// <summary>\r
+        /// Provides direct access to mapped DLL methods\r
+        /// </summary>\r
+        private static class NativeMethods\r
+        {\r
+            [DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_createInstance")]\r
+            public static extern IntPtr BpmCreateInstance(int numChannels, int sampleRate);\r
+\r
+            [DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_destroyInstance")]\r
+            public static extern void BpmDestroyInstance(IntPtr h);\r
+\r
+            [DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_putSamples")]\r
+            public static extern void BpmPutSamples(IntPtr h, float[] samples, uint numSamples);\r
+\r
+            [DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_putSamples_i16")]\r
+            public static extern void BpmPutSamples_i16(IntPtr h, short[] samples, uint numSamples);\r
+\r
+            [DllImport(SoundTouch.SoundTouchLibrary, CallingConvention = CallingConvention.Cdecl, EntryPoint = "bpm_getBpm")]\r
+            public static extern float BpmGet(IntPtr h);\r
+        }\r
+\r
+        #endregion\r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/source/csharp-example/SoundTouch.dll b/source/csharp-example/SoundTouch.dll
new file mode 100644 (file)
index 0000000..4f9667b
Binary files /dev/null and b/source/csharp-example/SoundTouch.dll differ
diff --git a/source/csharp-example/csharp-example.csproj b/source/csharp-example/csharp-example.csproj
new file mode 100644 (file)
index 0000000..3ee81c3
--- /dev/null
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />\r
+  <PropertyGroup>\r
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
+    <ProjectGuid>{1BE6EF4F-6A62-447B-A863-E918D68BDAD7}</ProjectGuid>\r
+    <OutputType>WinExe</OutputType>\r
+    <AppDesignerFolder>Properties</AppDesignerFolder>\r
+    <RootNamespace>csharp_example</RootNamespace>\r
+    <AssemblyName>csharp-example</AssemblyName>\r
+    <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>\r
+    <FileAlignment>512</FileAlignment>\r
+    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>\r
+    <WarningLevel>4</WarningLevel>\r
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <PlatformTarget>AnyCPU</PlatformTarget>\r
+    <DebugSymbols>true</DebugSymbols>\r
+    <DebugType>full</DebugType>\r
+    <Optimize>false</Optimize>\r
+    <OutputPath>bin\Debug\</OutputPath>\r
+    <DefineConstants>DEBUG;TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <PlatformTarget>AnyCPU</PlatformTarget>\r
+    <DebugType>pdbonly</DebugType>\r
+    <Optimize>true</Optimize>\r
+    <OutputPath>bin\Release\</OutputPath>\r
+    <DefineConstants>TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <ItemGroup>\r
+    <Reference Include="NAudio, Version=1.8.0.0, Culture=neutral, processorArchitecture=MSIL">\r
+      <SpecificVersion>False</SpecificVersion>\r
+      <HintPath>lib\NAudio.dll</HintPath>\r
+    </Reference>\r
+    <Reference Include="System" />\r
+    <Reference Include="System.Data" />\r
+    <Reference Include="System.Xml" />\r
+    <Reference Include="Microsoft.CSharp" />\r
+    <Reference Include="System.Core" />\r
+    <Reference Include="System.Xml.Linq" />\r
+    <Reference Include="System.Data.DataSetExtensions" />\r
+    <Reference Include="System.Net.Http" />\r
+    <Reference Include="System.Xaml">\r
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>\r
+    </Reference>\r
+    <Reference Include="WindowsBase" />\r
+    <Reference Include="PresentationCore" />\r
+    <Reference Include="PresentationFramework" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ApplicationDefinition Include="App.xaml">\r
+      <Generator>MSBuild:Compile</Generator>\r
+      <SubType>Designer</SubType>\r
+    </ApplicationDefinition>\r
+    <Compile Include="SoundProcessor.cs" />\r
+    <Compile Include="SoundTouch.cs" />\r
+    <Page Include="MainWindow.xaml">\r
+      <Generator>MSBuild:Compile</Generator>\r
+      <SubType>Designer</SubType>\r
+    </Page>\r
+    <Compile Include="App.xaml.cs">\r
+      <DependentUpon>App.xaml</DependentUpon>\r
+      <SubType>Code</SubType>\r
+    </Compile>\r
+    <Compile Include="MainWindow.xaml.cs">\r
+      <DependentUpon>MainWindow.xaml</DependentUpon>\r
+      <SubType>Code</SubType>\r
+    </Compile>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Compile Include="Properties\AssemblyInfo.cs">\r
+      <SubType>Code</SubType>\r
+    </Compile>\r
+    <Compile Include="Properties\Resources.Designer.cs">\r
+      <AutoGen>True</AutoGen>\r
+      <DesignTime>True</DesignTime>\r
+      <DependentUpon>Resources.resx</DependentUpon>\r
+    </Compile>\r
+    <Compile Include="Properties\Settings.Designer.cs">\r
+      <AutoGen>True</AutoGen>\r
+      <DependentUpon>Settings.settings</DependentUpon>\r
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>\r
+    </Compile>\r
+    <EmbeddedResource Include="Properties\Resources.resx">\r
+      <Generator>ResXFileCodeGenerator</Generator>\r
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>\r
+    </EmbeddedResource>\r
+    <None Include="Properties\Settings.settings">\r
+      <Generator>SettingsSingleFileGenerator</Generator>\r
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>\r
+    </None>\r
+    <AppDesigner Include="Properties\" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <None Include="App.config" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Content Include="NAudio.dll">\r
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\r
+    </Content>\r
+    <Content Include="SoundTouch.dll">\r
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\r
+    </Content>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <WCFMetadata Include="Service References\" />\r
+  </ItemGroup>\r
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />\r
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
+       Other similar extension points exist, see Microsoft.Common.targets.\r
+  <Target Name="BeforeBuild">\r
+  </Target>\r
+  <Target Name="AfterBuild">\r
+  </Target>\r
+  -->\r
+</Project>
\ No newline at end of file
diff --git a/source/csharp-example/csharp-example.sln b/source/csharp-example/csharp-example.sln
new file mode 100644 (file)
index 0000000..9ec10ff
--- /dev/null
@@ -0,0 +1,22 @@
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 14\r
+VisualStudioVersion = 14.0.23107.0\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp-example", "csharp-example.csproj", "{1BE6EF4F-6A62-447B-A863-E918D68BDAD7}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Any CPU = Debug|Any CPU\r
+               Release|Any CPU = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {1BE6EF4F-6A62-447B-A863-E918D68BDAD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+               {1BE6EF4F-6A62-447B-A863-E918D68BDAD7}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+               {1BE6EF4F-6A62-447B-A863-E918D68BDAD7}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+               {1BE6EF4F-6A62-447B-A863-E918D68BDAD7}.Release|Any CPU.Build.0 = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r