Compare commits

...

262 Commits

Author SHA1 Message Date
Olli
9ef8458d85 cmake minimum version to 3.5 to avoid deprecation warning 2025-02-23 13:03:03 +02:00
Olli
16956b94b9 Replace '-Ofast', being deprecated in some compilers, with '-O3 -ffast-math' 2025-02-23 13:00:17 +02:00
Olli
5dede763ff Refactor pow() usage
Refactor pow() usage:
- use base of 0.5^k instead of 1/(2^k)
- skip pow if using INTEGER_SAMPLES
2025-02-23 12:54:41 +02:00
Olli Parviainen
e31e1715fb Merge pull request 'build: add install components for CMake targets' (#42) from aminya/soundtouch:component-names into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/42
2024-10-04 11:38:47 +00:00
Amin Yahyaabadi
bc2a2f73ff build: add install components for CMake targets 2024-10-03 21:47:17 -07:00
Olli
d3f7e2530b SoundStretch: parse command-line argument values with double precision 2024-09-21 09:41:37 +03:00
Olli
ddf28667c9 Increase max nr. of channels from 16 to 32 2024-09-17 19:26:14 +03:00
Olli Parviainen
7f35604eda Merge pull request 'Fix typo in README.html' (#39) from LeonC/soundtouch:fix-typo into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/39
2024-06-18 15:40:15 +00:00
Tianxiao Cao
4ae091f54f Fix typo in README.html 2024-06-18 11:36:56 +08:00
Olli
e83424d592 Update latest stable version to 2.3.3 2024-03-29 20:49:53 +02:00
Olli Parviainen
0095a3d933 soundstretch: Print hello text even if no switches were given 2024-03-29 20:33:00 +02:00
Olli Parviainen
077e73422f Win/VisualStudio: Change Win32 debug settings to avoid build warning 2024-03-29 20:25:20 +02:00
Olli
f0ef4cd853 automake: Build SoundTouchDLL only if FLOAT samples used 2024-03-29 20:03:34 +02:00
Olli
7dce7268cd Linux soundstretch: Fix unhandled exception error 2024-03-29 19:42:55 +02:00
Olli
63002027de dos2unix:ify line endings, source code formatter 2024-03-29 19:42:23 +02:00
Olli Parviainen
290b0b13e2 Merge pull request 'source/SoundTouchDLL: don't clobber CXXFLAGS, LDFLAGS' (#35) from thesamesam/soundtouch:no-clobber-flags into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/35
2024-03-24 13:58:14 +00:00
Olli Parviainen
2a24e3b454 Merge pull request 'configure.ac: fix bashism in CXXFLAGS assignment' (#34) from thesamesam/soundtouch:bashism into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/34
2024-03-24 13:52:31 +00:00
Sam James
02c22eceea
source/SoundTouchDLL: don't clobber CXXFLAGS, LDFLAGS
automake warns about this, telling us to set AM_CXXFLAGS and AM_LDFLAGS instead.

This fixes respecting LDFLAGS in particular (the CXXFLAGS one was harmless).

Signed-off-by: Sam James <sam@gentoo.org>
2024-03-24 07:41:49 +00:00
Sam James
ba1cb7727e configure.ac: fix bashism in CXXFLAGS assignment
configure scripts need to be runnable with a POSIX-compliant /bin/sh.

On many (but not all!) systems, /bin/sh is provided by Bash, so errors
like this aren't spotted. Notably Debian defaults to /bin/sh provided
by dash which doesn't tolerate such bashisms as '=='.

This retains compatibility with bash.

Fixes configure warnings/errors like:
```
checking whether make supports nested variables... (cached) yes
configure: 3698: CXXFLAGS+= -Ofast: not found
```

Signed-off-by: Sam James <sam@gentoo.org>
2024-03-24 07:34:48 +00:00
Olli Parviainen
17b63eeb3e Merge pull request 'Use -O3 instead of -Ofast when targeting Emscripten (WebAssembly)' (#29) from fwcd/soundtouch:fix-cmake-emscripten into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/29
2024-03-03 18:00:19 +00:00
Olli Parviainen
2e83c770b0 Merge pull request 'Set CMAKE_CXX_STANDARD to 17 in CMakeLists' (#30) from fwcd/soundtouch:cmake-cxx-standard-17 into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/30
2024-03-03 17:56:28 +00:00
fwcd
5e624fff73 Set CMAKE_CXX_STANDARD to 17 2024-03-02 23:21:39 +01:00
fwcd
1c6a90804b Use -O3 instead of -Ofast when targeting Emscripten (WASM) 2024-03-02 23:02:06 +01:00
Olli Parviainen
f921e5b586 Fix DLL function import clause for gnu platform 2024-03-02 19:11:43 +02:00
Olli Parviainen
6872a2b6d0 Add SS_CharTypes.h 2024-03-02 18:52:42 +02:00
Olli Parviainen
d90844f67d Add class="current" to latest entry in change history 2024-02-12 17:48:11 +02:00
Olli Parviainen
375e6ccfe9 Windows: SoundStretch to accept wide-character command line attributes to support asian/non-latin files names. 2024-02-11 17:52:48 +02:00
Olli Parviainen
74514f5597 C# example: Update to NET toolit v4.8.1, x64 by default, update SoundTouch.dll binary 2023-12-03 17:28:15 +02:00
Olli Parviainen
3781ff5d55 Merge pull request 'fix: fix the CMake config for SoundTouchDLL' (#24) from aminya/soundtouch:dll-cmake into master
Thanks for the MR.

Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/24
2023-12-03 11:24:27 +00:00
Amin Yahyaabadi
e56457728c fix: fix the CMake config for SoundTouchDLL 2023-12-03 11:24:27 +00:00
Olli Parviainen
c4c922c7b9 Merge pull request 'fix: fix uint conversion for number of samples' (#25) from aminya/soundtouch:conversions into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/25
2023-12-03 11:23:25 +00:00
Amin Yahyaabadi
28df544c48
fix: fix uint conversion for number of samples 2023-12-02 21:22:48 -08:00
Olli Parviainen
dd2252e9af Merge pull request 'Do not add -mfpu=neon flag under aarch64' (#15) from fundawang/soundtouch:master into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/15
2023-04-24 15:42:50 +00:00
fundawang
55bd933dba Do not add -mfpu=neon flag under aarch64 2023-04-23 22:26:37 +00:00
Olli Parviainen
8726394399 Merge pull request 'Fixed MSVC build errors' (#14) from oviano/soundtouch:fixed-msvc-build-error into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/14
2023-04-12 16:15:56 +00:00
Oliver Collyer
170349af69 Fixed MSVC build errors 2023-04-12 14:55:46 +01:00
Olli Parviainen
b477936716 Resolve gcc compiler warnings in ARM environment 2023-04-02 18:48:28 +03:00
Olli Parviainen
cc24adfc6d Merge pull request 'Expose BPM detector beat position and strength retrieval API via SoundTouchDLL.' (#11) from sagamusix/soundtouch:master into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/11
2023-03-26 17:03:37 +00:00
Johannes Schultz
808bf021e6 Expose BPM detector beat position and strength retrieval API via SoundTouchDLL. 2023-03-26 18:54:04 +02:00
Olli
63db6bf344 Add -Wextra -Wzero-as-null-pointer-constant to configure.ac
Signed-off-by: Olli <oparviai'at'iki.fi>
2023-03-25 11:49:10 +02:00
Olli Parviainen
05d2835f65 Merge pull request 'Increase warning settings' (#10) from Minty-Meeo/soundtouch:master into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/10
2023-03-25 09:44:23 +00:00
Minty-Meeo
1eda9c0b01 Resolve [-Wzero-as-null-pointer-constant] 2023-03-24 12:32:50 -05:00
Minty-Meeo
230ae2f9a9 Resolve [-Wextra]
[-Winconsistent-missing-override]
[-Wunused-const-variable]
[-Wunused-private-field]
[-Wunused-parameter]
2023-03-24 12:32:24 -05:00
Olli
a88c82d0ab Enable -Wall -Wno-unknown-pragmas compiler setting
Enable `-Wall -Wno-unknown-pragmas` compiler setting to show warnings
during build.

Supress "unknown-pragmas" warning though because it's legitimely used
for openmp support.

Signed-off-by: Olli <oparviai'at'iki.fi>
2023-03-19 17:06:47 +02:00
serge-sans-paille
82cb3f99bb Remove unused dScaler variable in FIRFilter.cpp
Code is guarded by SOUNDTOUCH_FLOAT_SAMPLES but never actually used. Get
rid of it as it triggers a warning under -Werror=unused-variable.
--
Cherry-picked from
https://gitlab.com/serge-sans-paille/soundtouch/-/tree/fix/remove-unused-float-scaler
2023-03-19 16:52:18 +02:00
serge-sans-paille
4070166f4a Avoid signed/unsigned comparison when possible
As reported by -Wall
--
Cherry-picked from
https://gitlab.com/serge-sans-paille/soundtouch/-/tree/fix/sign-issue
2023-03-19 16:50:59 +02:00
serge-sans-paille
4bcbb3556f Remove trivially unused variables, as pointed out by -Wunused-variable
cherry-picked from
https://gitlab.com/serge-sans-paille/soundtouch/-/tree/fix/remove-unused-variables
2023-03-19 16:50:56 +02:00
Olli
29fba832a7 Update version to 2.3.2
Signed-off-by: Olli <oparviai'at'iki.fi>
2022-11-08 18:02:17 +02:00
Olli Parviainen
9e798c0f7f Fix compiler flags in SoundTouchDLL/Makefile.am
Fix compiler flags in SoundTouchDLL/Makefile.am so that flags inherited
from master makefile get included.

Signed-off-by: Olli Parviainen <oparviai'at'iki.fi>
2022-11-02 19:55:10 +02:00
Olli Parviainen
ddc351bfb6 Merge remote-tracking branch 'origin/config-updates' 2022-11-02 19:43:23 +02:00
Olli
774257ab5f Small updates to dynamic-link libary build script & pascal example
Signed-off-by: Olli <oparviai'at'iki.fi>
2022-10-31 18:51:35 +02:00
Olli Parviainen
eaa9090f65 Merge pull request 'Migrate configuration file, add building of dynamic-link version to the master makefile' (#9) from config-updates into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/9
2022-10-30 17:19:16 +01:00
Olli
17925302ae Migrate configuration file, add building of dynamic-link version to the master makefile
- Migrate configuration.ac file to new autotools
- add building of also the dynamic-link version within
  'source/SoundTouchDLL' directory from the main-level makefile
- add a simple lazarus/pascal example project that uses the dynamic-link
  version of the SoundTouch library

Signed-off-by: Olli <oparviai'at'iki.fi>
2022-10-30 18:15:10 +02:00
Olli Parviainen
8562287944 Merge pull request 'Comment out _init_threading call in processFile function' (#1) from shwixel/soundtouch:master into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/1
2022-01-23 16:10:34 +01:00
Olli Parviainen
9f14bd8b6e Merge pull request 'Fix exception throwing across DLL boundary' (#2) from sagamusix/soundtouch:master into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/2
2022-01-23 16:08:35 +01:00
Olli Parviainen
64760eb34e Merge pull request 'Add 'override' keyword' (#3) from vestral/soundtouch:override into master
Reviewed-on: https://codeberg.org/soundtouch/soundtouch/pulls/3
2022-01-23 16:01:34 +01:00
Vestral
bb0434dd6e Add 'override' keyword 2022-01-22 09:22:02 +09:00
Johannes Schultz
1a07a649e4 C functions mustn't throw. Catch exceptions in SoundTouch DLL interface because the user cannot catch them. 2021-12-04 22:09:51 +01:00
Johannes Schultz
bdafd3b08c Ignore .vs folders created by Visual Studio 2021-12-04 22:02:06 +01:00
Daniil Zakharov
ab2b8ca91f Comment out _init_threading call in processFile function 2021-12-03 02:42:45 +03:00
Olli
9fedba866e synced gitlab+codeberg masters 2021-10-31 17:20:56 +02:00
Olli
0afe414a18 Merge remote-tracking branch 'gitlab/master' 2021-10-31 17:20:19 +02:00
Olli
b9092339f5 add links to stable tarballs 2021-10-31 17:16:13 +02:00
Olli
85c03d6063 update readme.md 2021-10-31 17:11:53 +02:00
Olli
7ede48e436 update repository location 2021-10-31 16:57:52 +02:00
Olli Parviainen
8a9d4acb12 Add links to source code release tarballs
Signed-off-by: Olli Parviainen <oparviai at iki fi>
2021-10-14 19:16:15 +03:00
Olli
d063c0d9f9 Changed gitlab.com references to codeberg.org 2021-10-14 18:29:15 +03:00
Olli Parviainen
b9afe0ac11 Merge branch 'cmake-openmp' into 'master'
CMake: Add option for OpenMP

See merge request soundtouch/soundtouch!24
2021-10-04 16:24:22 +00:00
Daniel E
572d12c3e9 CMake: Add option for OpenMP
Make support for OpenMP optional (disabled by default)
2021-10-03 23:45:00 +00:00
Olli Parviainen
e016ebfcd5 Merge branch 'diizzyy-master-patch-90177' into 'master'
CMake: Add aarch64 as identifier for ARM 64-bit

See merge request soundtouch/soundtouch!21
2021-10-03 15:49:51 +00:00
Daniel E
4fd8e1acb9 CMake: Add aarch64 as identifier for ARM 64-bit
On FreeBSD ARM 64-bit is called aarch64
2021-09-26 17:09:05 +00:00
Olli Parviainen
afb0e4a73f Merge branch 'diizzyy-master-patch-80799' into 'master'
CMake: Fix build with INTEGER_SAMPLES enabled

See merge request soundtouch/soundtouch!20
2021-09-19 17:45:35 +00:00
Daniel E
77cbbb2227 CMake: Fix build with INTEGER_SAMPLES enabled 2021-09-18 16:21:41 +00:00
Olli Parviainen
e1f315f535 Merge branch 'dll_exports' into 'master'
CMake: fix SoundTouchDLL build with MSVC

See merge request soundtouch/soundtouch!18
2021-09-07 15:26:53 +00:00
Olli Parviainen
82e9ebd075 Merge branch 'fpic' into 'master'
CMake: fix compiler warning about unknown option -fPIC with MSVC

See merge request soundtouch/soundtouch!19
2021-09-07 15:11:30 +00:00
Be
fd8e4c6835
CMake: fix compiler warning about unknown option -fPIC with MSVC 2021-09-07 08:42:45 -05:00
Be
d7b7a2f3a1
CMake: fix SoundTouchDLL build with MSVC 2021-09-07 08:35:18 -05:00
Olli
7df5617a4b cmake: remove "CMAKE" compiler definition and instead add mock "soundtouch_config.h"
Add a empty mock "soundtouch_config.h" file and remove "CMAKE" compiler
definition that was used in #ifdef that skipped including
"soundtouch_config.h" in cmake build.

This is to avoid errors about missing include file when not using
autotools build.

Also update version to 2.3.1

Signed-off-by: Olli <oparviai'at'iki.fi>
2021-09-06 20:13:01 +03:00
Olli Parviainen
2e606befef Merge branch 'shared-lib-version' into 'master'
Set VERSION and SOVERSION for shared libraries

See merge request soundtouch/soundtouch!15
2021-09-01 14:58:22 +00:00
Olli Parviainen
268a91494b Merge branch 'configure.ac' into 'master'
Fix for commit 3d7bf376

See merge request soundtouch/soundtouch!17
2021-09-01 14:57:50 +00:00
Olli Parviainen
2adf2ae71d Merge branch 'incorrect-fsf-address' into 'master'
Correct fsf address

See merge request soundtouch/soundtouch!16
2021-09-01 14:57:18 +00:00
Sérgio M. Basto
9f72a8aa6b Fix for commit 3d7bf376
we need use += and a space CXXFLAGS+=" -O3 -ffast-math" , if not += you override all system settings for CXXFLAGS and none for LDFLAGS, which ends with "/usr/bin/ld: /tmp/ccARck2g.o: relocation R_X86_64_32 against .rodata.str1.1' can not be used when making a PIE object; recompile with -fPIE`"

https://stackoverflow.com/a/38579792/778517
2021-08-31 22:11:27 +01:00
Sérgio M. Basto
d11a3adb2d Correct fsf address
https://fedoraproject.org/wiki/Common_Rpmlint_issues#incorrect-fsf-address
2021-08-30 19:07:29 +01:00
Uwe Klotz
847edf4548 Set VERSION and SOVERSION for shared libraries
Required by the RPM builds for Fedora:

b7c49ac115
2021-08-30 10:01:38 +02:00
Be
3148382fa8 CMake: make building soundstretch optional 2021-08-29 18:19:28 +03:00
Olli
c65afe49f6 cmake: add -mfpu=neon if neon build 2021-08-21 13:25:24 +03:00
Olli
28b32c0fbb Update readme, version info for release v2.3.0
Signed-off-by: Olli <oparviai'at'iki.fi>
2021-08-21 13:00:35 +03:00
Olli
bd2149daf6 Fix cmake NEON condition
Signed-off-by: Olli <oparviai'at'iki.fi>
2021-08-21 12:59:59 +03:00
Olli
776443f914 Disable OpenMP init_threading workaround in Android build
Signed-off-by: Olli <oparviai'at'iki.fi>
2021-08-21 11:38:17 +03:00
Olli
65caafdc5f cmake: add 'soundstretch' utility, regroup CMakeList.txt by targets
- add 'soundstretch' utility as cmake build target
- group CMakeList.txt contents per target for better readability
2021-08-20 21:56:12 +03:00
Olli Parviainen
6dce1068d9 Merge branch 'optimizations' into 'master'
CMake: set optimization options for MSVC as well as GCC & Clang

See merge request soundtouch/soundtouch!13
2021-08-20 17:57:09 +00:00
Be
eb6d970970
CMake: set optimization options for MSVC as well as GCC & Clang 2021-08-18 12:24:18 -05:00
Olli
f974b28682 Further cmake changes for SoundTouchDLL compilation
- enable "-Ofast" compilation flags for cmake build
- adjust compiler flags for the SoundTouchDLL compilation
- add cmake-generated "SoundTouchDLL_EXPORTS" as alias for "DLL_EXPORT"
- hide cmake temporary files in gitignore

Signed-off-by: Olli <oparviai'at'iki.fi>
2021-08-17 19:50:29 +03:00
Olli Parviainen
220eb7857c Merge branch 'cmake' into 'master'
CMake fixes for SoundTouchDLL

See merge request soundtouch/soundtouch!12
2021-08-17 16:49:07 +00:00
Be
dae91683bc
CMake fixes for SoundTouchDLL 2021-08-16 11:23:01 -05:00
Olli Parviainen
fa223609d2 Merge branch 'cmake' into 'master'
add CMake build system

See merge request soundtouch/soundtouch!11
2021-08-16 16:03:43 +00:00
Be
3617bd166b
add build directory to .gitignore 2021-08-16 10:09:32 -05:00
Be
d8d86e1a92
add CMake build system 2021-08-16 10:09:32 -05:00
Olli
e0e00878fc Remove surplus semicolon
Remove surplus semicolon that caused warning if compiling with
'-pedantic' compiler switch.

Signed-off-by: Olli <oparviai 'at' iki.fi>
2021-07-30 14:53:04 +03:00
Olli
17a63e99d5 Fix bug with too small initial skipFract value
Fix bug with too small initial skipFract value with certain processing
parameter set: replaces assert with assignment that corrects the
situation.
2021-03-03 18:11:45 +02:00
Olli
6533514372 Improve soundtouch.clear() so that it really clears TDStretch & RateTransposer states
Improve soundtouch.clear() so that it really clears all TDStretch &
RateTransposer state variables. Before this clear() left last processed
sample or fractional position state uncleared, which caused slightly
different result if same stream was processed again after clear().
2021-01-30 19:02:08 +02:00
Olli
81b0d74727 Correct initial skip value
... so that with nominal tempo the expected best sequence overlapping
location lays in middle of the correlation window. This will ensure that
with output should be similar to input when tempo adjustment is zero.
2021-01-28 21:32:35 +02:00
Olli
5e76cf2f6d Disable skipping of unaligned SIMD memory offset by default
Change default setting so that SIMD does not skip of unaligned memory
offsets, as that likely is not a necessary compromise with concurrent
CPUs any more.
2021-01-28 21:26:38 +02:00
Olli
f38cfa6850 Call "clear()" after changing anti-alias filter on/off
Call "clear()" after changing anti-alias filter on/off to prefill
buffers appropriately.
2021-01-28 20:19:06 +02:00
Olli Parviainen
762f56024b Updated versions and documents for release 2.2 2020-10-15 18:23:34 +03:00
Olli Parviainen
1d42d899ab Merge branch 'improve-autovectorization' into 'master'
Improvements to help compiler autovectorization

See merge request soundtouch/soundtouch!10
2020-10-13 18:19:08 +00:00
Olli Parviainen
bf3cec0244 Improvements to help compiler autovectorization
Refactored FIRfilter and TDStretch hot-spot routines to help compiler
perform more efficient autovectorization.

Benchmarked:
- 2x/3x improvement in gcc-generated x86 SIMD code execution
  times for SSE2/AVX instruction extensions accordingly, when
  hand-tuned SSE intrinsics were disabled. Hand-tuned SSE code
  still is slightly faster than gcc-produced AVX.
- 2.4x improvement for cumulative ARM NEON tunings when compared to
  previous SoundTouch release.

Signed-off-by: Olli Parviainen <oparviai'at'iki.fi>
2020-10-13 20:46:23 +03:00
Olli Parviainen
a911a1e986 Bugfix in integer version of calcCrossCorrAccumulate()
Using "unsigned long" for "lnorm" variable that was yet made negative in very first step caused incorrect calculation result. Corrected the type to "long".

Signed-off-by: Olli Parviainen <oparviai@iki.fi>
2020-10-03 16:58:00 +03:00
Olli Parviainen
3e74d1d18f Fixed characters in source code comments that ought to be ± 2020-07-08 19:13:30 +03:00
Olli Parviainen
f382149086 Compensate initial buffering of anti-alias filter and intepolator.
This avoids losing first few dozen of samples from beginning of the stream.

Signed-off-by: Olli Parviainen <oparviai at iki.fi>
2020-06-30 14:16:03 +03:00
Olli Parviainen
308c3484f6 Merge branch 'feature/neon-tuning' into 'master'
Tuning for ARM NEON

See merge request soundtouch/soundtouch!8
2020-06-21 17:43:36 +00:00
Olli Parviainen
3d7bf376fd Tuning for ARM NEON
Tuning to enable ARM NEON SIMD performance improvements:
- NEON detection in configure file
- Remove manual loop unrolling, gcc autovectorization does better job
without manually unrolled loops.
- Avoid unaligned pointer accesses when using NEON
2020-06-21 20:38:00 +03:00
Olli Parviainen
1e56c65ea5 Merge branch 'bpmdetect-warning-size_t-int' into 'master'
BPMDetect: Make conversion from size_t to int explicit

See merge request soundtouch/soundtouch!7
2020-05-10 14:39:52 +00:00
Rémi Verschelde
fe15975a21 BPMDetect: Make conversion from size_t to int explicit
Fixes warning C4267 on MSVC.

This assumes that `beats.size()` should never overflow `int` - if that
could happen, the API should likely be changed to handle it gracefully.
2020-04-28 10:48:47 +02:00
Olli Parviainen
a046b6971d Windows build: Retargeted to Visual Studio 2019 and Windows 10. Removed obsolete /Gm build option.
Signed-off-by: Olli Parviainen <oparviai at iki.fi>
2020-02-02 18:58:46 +02:00
Olli Parviainen
c4f1602474 Added section about building the software in Mac 2019-10-28 19:04:28 +02:00
Olli Parviainen
244fbeac24 BPM PeakFinder: Fix possible reading past end of array.
Increase minor version accordingly.
2019-01-07 18:55:36 +02:00
Olli Parviainen
12cb25ed7b Updated README.html 2019-01-01 16:55:23 +02:00
Olli
fb3ea4d9f0 Update readme.md 2018-12-08 19:01:57 +00:00
Olli Parviainen
2b2585bc74 Enable using multiple CPUs in Visual Studio build for faster build 2018-12-04 21:11:17 +02:00
Olli
eef1220d72 BPMDetect: Change correlation loop 'sum' variable type from double to float, because double causes big performance penalty for autovectorized code. 2018-12-02 22:33:55 +02:00
olli
9205fc971e Bump version to 2.1.2 to correct incorrect version info in configure.ac 2018-12-02 10:43:00 +02:00
Olli
b9659b64c6 Updated readme & version info to 2.1.1 2018-11-14 19:25:34 +02:00
Olli
7f594f8b7d New take on CVE-2018-17097 i.e. avoiding writing beyond end of buffer in case of 24-bit samples 2018-10-31 18:36:05 +02:00
olli
6d700259b9 Touched version number 2018-10-28 16:27:48 +02:00
olli
dad1d566c4 Added unset ACLOCAL to bootstrap to avoid issue that ACLOCAL has been previously set to incompatible value. 2018-10-28 16:25:23 +02:00
Olli
41a2cd3e6b Merge branch 'master' of gitlab.com:soundtouch/soundtouch 2018-10-28 16:05:26 +02:00
Olli
09e04252dd Fix CVE-2018-17097 by rounding working buffer size up to nearest 4-byte boundary. Replaced also tab characters with spaces in indentation. 2018-10-28 16:04:15 +02:00
Olli
59129fa33d Eliminate assert condition by reading # sample elements that are multiple of num-of-channels 2018-10-28 15:49:50 +02:00
Olli
a1c400eb2c Fix issue CVE-2018-17096: Replace assert with runtime exception 2018-10-28 15:32:58 +02:00
Olli
12eaa21e14 Merge branch 'android-build-update' into 'master'
Adding gradle build for Android example

See merge request soundtouch/soundtouch!6
2018-09-22 16:14:52 +00:00
ggfan
bdbe1bf551 Adding gradle build for Android example 2018-09-20 07:35:02 -07:00
Olli
1d63bbf8e1 Update readme.md 2018-09-10 06:22:36 +00:00
olli
79cbdb1140 Reformat README.html eol characters 2018-09-08 19:15:39 +03:00
Olli
3ea4f5c7b3 Merge branch 'master' of https://gitlab.com/soundtouch/soundtouch 2018-09-08 19:04:37 +03:00
Olli
68df82bd5b Merge branch 'master' of https://gitlab.com/soundtouch/soundtouch 2018-09-08 19:04:21 +03:00
Olli
00241ebba1 Merge branch 'master' of https://gitlab.com/soundtouch/soundtouch 2018-09-08 18:54:04 +03:00
Olli
1e9ec6f54b Merge branch 'master' of https://gitlab.com/soundtouch/soundtouch 2018-09-08 18:53:37 +03:00
Olli
50348640f7 Merge branch 'master' of https://gitlab.com/soundtouch/soundtouch 2018-09-08 18:52:44 +03:00
Olli
1e9c3bce2d Bump version to 2.1 2018-09-08 18:52:10 +03:00
Olli
5e3ca30225 Bump version to 2.1 2018-09-08 18:34:10 +03:00
olli
46531e5b92 Improved WavFile header/fact not-too-small check 2018-08-13 19:42:58 +03:00
oparviainen
e024068905 Fixed WavFile header/fact not-too-small check 2018-08-13 19:16:16 +03:00
oparviainen
c38f0506da Removed commented code, style cleanup 2018-08-12 20:51:24 +03:00
oparviainen
cca9271e98 Merge branch 'master' of https://gitlab.com/soundtouch/soundtouch 2018-08-12 20:25:12 +03:00
oparviainen
9e02d9b04f Added minimum size check for WAV header block lengh values 2018-08-12 20:24:37 +03:00
oparviainen
1ab7e7ccd0 Added tasks.json file for MS VisualStudio Code 2018-08-12 20:03:22 +03:00
oparviainen
4aaac92874 Updated .gitignore for gnu platform 2018-08-12 20:02:33 +03:00
oparviainen
107f2c5d20 Replaced illegal-number-of-channel assertions with run-time exception 2018-08-12 20:00:56 +03:00
Olli
4b6060adfe Merge branch 'update-vs-extra-dist' into 'master'
Update Visual Studio files on EXTRA_DIST

See merge request soundtouch/soundtouch!3
2018-08-08 17:58:56 +00:00
Olli
1f7f681f9d Merge branch 'add-interpolate-h-to-noinst-headers' into 'master'
Add Interpolate*.h to noinst_HEADERS

See merge request soundtouch/soundtouch!4
2018-08-08 17:57:50 +00:00
Olli
81cf74cf4c Merge branch 'misc-typos' into 'master'
MIsc. source comment typos

See merge request soundtouch/soundtouch!5
2018-08-08 17:55:28 +00:00
oparviainen
5c168a55ff Set AR_FLAGS in configure.ac to avoid build warning "ar: u' modifier ignored since D' is the default (see `U')" 2018-08-08 20:09:20 +03:00
oparviainen
f71db0d2c3 Added <cfloat> header file, resolved compiler warnings 2018-08-08 19:53:14 +03:00
luz.paz
0093b63141 MIsc. source comment typos
Found via `codespell -q 3`
2018-07-27 12:26:56 -04:00
Isamu Mogi
6ee56b1c17 Add Interpolate*.h to noinst_HEADERS
This fixes following error on `make distcheck`

```
Making all in SoundTouch
  CXX      AAFilter.lo
  CXX      FIRFilter.lo
  CXX      FIFOSampleBuffer.lo
  CXX      RateTransposer.lo
../../../../source/SoundTouch/RateTransposer.cpp:39:10: fatal error: 'InterpolateLinear.h' file not found
         ^~~~~~~~~~~~~~~~~~~~~
1 error generated.
```
2018-06-02 15:55:07 +09:00
Isamu Mogi
6b6c36d3e1 Update Visual Studio files on EXTRA_DIST
This fixes following error on `make dist`:

```
make[6]: *** No rule to make target `SoundTouch.dsp', needed by `distdir-am'.  Stop.
```
2018-06-02 15:53:05 +09:00
Olli
8f6f91f9b3 Merge branch 'bpm-work' into 'master'
BPM algorithm work - improved beat analysis routine and added individual beat detection

See merge request soundtouch/soundtouch!1
2018-05-16 16:04:33 +00:00
Olli
007481d711 BPM algorithm work - improved beat analysis routine and added individual beat detection 2018-05-16 18:58:19 +03:00
Olli
47f74e83ef Merged typo correction patch 2018-05-12 18:40:56 +03:00
Olli
c4154b063f Corrected typos in source code comments 2018-05-12 18:39:43 +03:00
Olli
3f2ad229bb Migrated MS Visual Studio build scripts to VS2015 2018-05-10 23:54:07 +03:00
Olli
3feea728d5 Minor updates. Removed obsoleted files. 2018-05-10 21:57:49 +03:00
Olli
e765f8146f Removed Subversion $Id$, $Date$ etc autoupdate tags 2018-05-10 21:51:49 +03:00
Olli
669ab8c974 Updated readme.md 2018-05-10 17:05:31 +00:00
oparviai
7b097533a9
Create readme.md 2018-05-10 18:32:38 +03:00
oparviai
30b017d112 SoundTouchDLL: adapt gcc compilation settings for x86/x64/arm platforms 2017-11-30 18:07:41 +00:00
oparviai
20e4bf0b04 Added BPM functions to Pascal interface of SoundTouch DLL 2017-11-26 09:10:41 +00:00
oparviai
ec9ba968f5 Added BPMDetect functions to SoundTouchDll API 2017-11-10 16:38:36 +00:00
oparviai
407f516e0d GNU compilation of SoundTouchDll that has easy function importing interfaces for java, mono etc 2017-11-03 20:08:10 +00:00
oparviai
05a3403137 Refactored C# interface & example 2017-10-30 16:53:17 +00:00
oparviai
80281c8e1b Disable anti-alias filter if SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER is defined 2017-09-07 17:04:02 +00:00
oparviai
5f8720dae6 Added & to catch() clause to handle exception as reference 2017-08-29 16:10:45 +00:00
oparviai
6e8d58cbcc Added sanity checks against illegal input audio stream parameters e.g. wildly excessive samplerate 2017-08-27 15:23:28 +00:00
oparviai
b56859a3fe Fixed Windows build script to support visual studio 14 2017-07-30 09:56:40 +00:00
oparviai
bbeab39f0a Version SoundTouch 2.0 2017-07-30 09:35:00 +00:00
oparviai
cd74dccaf1 Disable MMX integer optimizations in X64 compilation 2017-07-30 09:28:06 +00:00
oparviai
bd0a806285 Updated documentation 2017-07-25 14:26:50 +00:00
oparviai
59e6726118 Added C# example application that processes mp3 files with SoundTouch 2017-07-25 12:40:11 +00:00
oparviai
92bfdd1e8d Fixed a bug introduced in r245 that caused small constant time offset in the output vs. input stream 2017-04-07 19:01:22 +00:00
oparviai
c31fca9c9f Added int16/short sample version of putSamples()/receiveSamples() functions to SoundTouch.dll API 2017-03-05 16:36:35 +00:00
oparviai
6f82bdebdb Modify 'maxnorm' value insider critical section when using OpenMP with integer samples 2017-03-05 13:56:03 +00:00
oparviai
5d9bc2fdf3 Adjusted algorithm parameters for reducing reverberation artifact at tempo slowdown 2017-01-08 16:56:20 +00:00
oparviai
1049304b5d Fixed issue that clipped brief sequence of audio from beginning of the input audio 2017-01-08 16:27:02 +00:00
oparviai
e302cd7123 Fix to issue that started audio track with brief sequence of silence 2016-10-20 16:30:11 +00:00
oparviai
753848865d Added function to get duration ratio between the original input and processed output tracks. 2016-10-15 19:34:59 +00:00
oparviai
ac03757ec8 Added functions to get initial processing latency, and clarified reporting input/output batch sizes 2016-10-15 18:55:12 +00:00
oparviai
62d63e7881 edit 2016-01-13 07:15:17 +00:00
oparviai
f574c92dcf Bugfix: Incorrect Pi value from 5th decimal onwards ... 2016-01-12 17:26:21 +00:00
oparviai
8023db738f Cleaned unused variables from BPMDetect 2016-01-12 17:24:46 +00:00
oparviai
882f248a0c bugfix: flush() didn't properly flush final samples from the pipeline on 2nd time, in case that soundtouch object instance were recycled and used for processing a 2nd audio stream. 2016-01-10 10:31:35 +00:00
oparviai
9287800b65 Improved beat detection algorithm accuracy and made it better adaptable for real-time beat changes. 2016-01-05 20:59:57 +00:00
oparviai
e1c7cffbcd - Fixed incorrect maximally-small float variable initialization to use -FLT_MAX instead of FLT_MIN. This glitch may have caused possible negative index access when using best overlap quick seek algorithm
- version to 1.9.3(pre)
2016-01-05 20:42:45 +00:00
oparviai
81cb7a3406 Update Android doc 2015-11-11 21:47:19 +00:00
oparviai
089edd12f4 updated comments 2015-11-05 17:46:08 +00:00
oparviai
fe44590ab6 small update to OpenMP documentation 2015-11-05 17:32:27 +00:00
oparviai
5f84fe3eb7 update readme 2015-11-01 16:13:07 +00:00
oparviai
18a230a54c - Fix in GNU package management issues.
- version 1.9.2
2015-09-20 07:38:32 +00:00
oparviai
04b96e6b52 Update README for 1.9.1 2015-09-08 07:11:41 +00:00
oparviai
8c06711f86 Changed version to 1.9.1 2015-09-08 07:04:44 +00:00
oparviai
db04025351 - Redesigned quickseek algorithm for improved sound quality in quickseek mode
- Adaptive integer divider scaling for improved sound quality when using integer processing
- Version 1.9.1-pre
2015-08-08 21:00:15 +00:00
oparviai
c9507ff7f1 - Improved SoundTouch::flush() so that it produces exactly accurate number of output samples.
- Changed 'float' variables into 'double' for more precise calculation of input-vs-output samples.
2015-07-26 14:45:48 +00:00
oparviai
da748228b9 Patch to autoconfig option flagging 2015-07-12 18:52:19 +00:00
oparviai
2e8250d03a Fix to allow setting CXXFLAGS externally 2015-07-03 14:56:44 +00:00
oparviai
1a3c1cd50e Repaired Configure script MMX & SSE detection 2015-05-18 17:54:01 +00:00
oparviai
2f2b3d756a Updated readme details 2015-05-18 17:39:26 +00:00
oparviai
2cbd68c32b Change year 2015-05-18 17:32:21 +00:00
oparviai
9ff52beba7 Migrated Automake script variable INCLUDE to AM_CPPFLAGS 2015-05-18 17:04:47 +00:00
oparviai
55dcf4a956 Add note about VC++ OpenMP dll libraries 2015-05-18 16:21:31 +00:00
oparviai
76f76ffb84 - Update documentation
- Updated version numbers to 1.9
- Disable OpenMP by default, to be enabled by developer
2015-05-18 15:28:41 +00:00
oparviai
83e46b5644 Bugfix: limit __SOFTFP__ switch usage only to Android 2015-05-18 15:25:07 +00:00
oparviai
5ad8994798 soundtouch_config.h configuration patch 2015-05-18 15:22:27 +00:00
oparviai
4bc115df86 Floating point patch in PeakFinder 2015-05-18 15:22:02 +00:00
oparviai
d44723ea57 - OpenMP parallel processing disabled by default; can be enabled in compile-time
- Android: Workaround for threading issue to enable OpenMP parallel processing in Android
2015-05-15 10:22:36 +00:00
oparviai
92973bc18e Developed more refined Android example application that also works in ARM & X86 platforms. 2015-05-15 00:07:10 +00:00
oparviai
1040bd1d28 - Added X86 & MIPS library versions to Android
- Added Android example application framework
2015-05-14 20:03:56 +00:00
oparviai
708f1d7e0b Revised autoconf/automake scripts for easier adding of custom CXXFLAGS 2015-05-01 07:55:47 +00:00
oparviai
cbfec4188e Added AC_CONFIG_MACRO_DIR to configure.ac 2015-03-01 19:41:05 +00:00
oparviai
32dcebc1d7 release memory upon destroying instance 2015-02-22 15:16:48 +00:00
oparviai
c36e2fa958 mmx variable initialization patch 2015-02-22 15:10:38 +00:00
oparviai
3e9cc3fd4b bugfix 2015-02-22 15:07:12 +00:00
oparviai
123e3299fe Enable openmp for Visual C++ x64 build 2015-02-22 13:34:51 +00:00
oparviai
6935032a52 Added openmp configuration for gnu buid 2015-02-22 08:19:09 +00:00
oparviai
d7d0a5c0f9 Implemented parallel computation using OpenMP pragmas 2015-02-21 21:24:29 +00:00
oparviai
126d1ac41d Eliminated alloca() call that caused compatibility woes 2014-10-08 15:26:57 +00:00
oparviai
bfc89b45a9 Added support for WAV file 'fact' chunk 2014-10-05 16:20:24 +00:00
oparviai
5100cefbb0 Patch: Change in Makefile.am doc folder settings 2014-10-05 15:33:08 +00:00
oparviai
0715880b1f Fixed c++ function name mangling issue in SoundTouch.dll compilation 2014-04-06 18:06:50 +00:00
oparviai
099a6240eb Added x64 compilation to Visual Studio project files 2014-04-06 18:03:48 +00:00
oparviai
1da2f8e700 Replaced custom 'BOOL' type with C++ 'bool' 2014-04-06 16:04:42 +00:00
oparviai
e23bd6d093 Replaced custom 'BOOL' type with C++ 'bool' 2014-04-06 15:57:21 +00:00
oparviai
f68f8e9e09 Repaired Android makefile by adding the new Interpolate...cpp files. 2014-04-05 18:37:59 +00:00
oparviai
01ba661351 Updated README regarding Visual C++ versions 2014-01-07 20:26:30 +00:00
oparviai
9406cf5b28 Updated README notes for release 1.8.0 2014-01-07 20:17:17 +00:00
oparviai
b2ff6711d0 Enabled Automake silent build option 2014-01-07 19:58:54 +00:00
oparviai
33638a2243 Fixed GNU compilation 2014-01-07 19:41:23 +00:00
oparviai
4da3b1eaf9 Fixed line endings in configure.ac 2014-01-07 19:33:49 +00:00
oparviai
2d91306ac0 Changed version string to 1.8.0 2014-01-07 19:26:29 +00:00
oparviai
1f6391a9ca Performance improvement in calcCrossCorr function - maintain accumulating normalization calculation instead of recalculating normalization factor on each round. 2014-01-07 18:25:40 +00:00
oparviai
afdfb293f6 Apple compatibility fixes 2014-01-07 18:24:28 +00:00
oparviai
746a90d610 Fixed integer overflow bug in integer versions of cross-correlation routines. 2014-01-06 19:40:40 +00:00
oparviai
a61c28e36a Increased Antialias filter length from 32 to 64 2014-01-06 19:19:38 +00:00
oparviai
026ebe3841 Implemented integer version of linear interpolator 2014-01-06 19:16:02 +00:00
oparviai
f16b062219 Enabled keyword extension 2014-01-06 18:41:42 +00:00
oparviai
a09135884a Implemented separate Cubic, Linear and Shannon interpolation algorithms. 2014-01-06 18:40:23 +00:00
oparviai
abfeb3fcc9 Restructured RateTransposer to allow hosting alternative resampling algorithms. 2014-01-05 21:40:22 +00:00
oparviai
8174f6bc10 cleanup previous 2014-01-05 17:22:53 +00:00
oparviai
510a94e990 Fixed small sinc() calculation bug that caused AA filter attenuation be around -10dB instead of <-50dB. 2014-01-05 17:19:19 +00:00
oparviai
510ac08657 Bugfix in RateTransposerFloat::transposeMono 2014-01-05 15:57:10 +00:00
oparviai
70d7518295 Bugfix in Android jni interface 2013-06-15 11:44:11 +00:00
oparviai
55aa6f15e9 Bugfix and cleanups 2013-06-14 17:34:33 +00:00
oparviai
8c65661b91 Added support for multi-channel audio 2013-06-12 15:24:44 +00:00
oparviai
9bb265e3cd Fixed typo 2012-12-28 20:55:19 +00:00
oparviai
c6bf1c7585 Fixed typo 2012-12-28 20:50:57 +00:00
oparviai
7a0a940953 Fine tuning of Android compilation 2012-12-28 19:55:23 +00:00
oparviai
4d8825ef6d Removed piece of dead code 2012-12-28 19:52:47 +00:00
oparviai
7dea63e0e1 Set version to 1.7.1 2012-12-28 19:32:59 +00:00
oparviai
46a7dc3c39 Added files for Android example compilation 2012-12-28 14:53:56 +00:00
oparviai
9b902ef3b7 Added files for Android example compilation 2012-12-28 14:49:08 +00:00
oparviai
c3f4ff9532 Fixed pointer aligning for mingw64 compilation 2012-11-08 18:53:01 +00:00
oparviai
91305a5806 Fixed #include files for mingw64 compilation 2012-11-08 18:44:37 +00:00
oparviai
fbc2ace440 Updated DLL compilation in GNU 2012-09-29 11:07:55 +00:00
130 changed files with 17002 additions and 10794 deletions

55
.gitignore vendored Normal file
View File

@ -0,0 +1,55 @@
bin
lib
# Win build files
*.dll
*.exe
*.lib
# GNU build files
*.o
*.so*
*.lo
*.P*
*.la*
*.a
*.pc
*config*
Makefile
Makefile.in
.libs
aclocal.m4
autom4te.cache
stamp-*
libtool
soundstretch
# Files generated by MSVC
*.bsc
*.suo
*.sdf
*.filters
*.user
source/SoundTouch/Win32/
source/SoundTouch/x64/
source/SoundStretch/Win32/
source/SoundStretch/x64/
source/SoundTouchDll/Win32/
source/SoundTouchDll/x64/
source/SoundTouchDll/DllTest/Win32/
source/SoundTouchDll/DllTest/x64/
.vs
# Files generated by Android Studio
source/android-lib/.gradle
source/android-lib/.idea
**/*.iml
source/android-lib/local.properties
source/android-lib/build
source/android-lib/.externalNativeBuild
# CMake build directory
build*
CMakeFiles
CMakeCache.txt
*.cmake

32
.vscode/tasks.json vendored Normal file
View File

@ -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": []
}
]
}

191
CMakeLists.txt Normal file
View File

@ -0,0 +1,191 @@
cmake_minimum_required(VERSION 3.5)
project(SoundTouch VERSION 2.3.3 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
include(GNUInstallDirs)
set(COMPILE_OPTIONS)
if(MSVC)
set(COMPILE_DEFINITIONS /O2 /fp:fast)
else()
list(APPEND COMPILE_OPTIONS -Wall -Wextra -Wzero-as-null-pointer-constant -Wno-unknown-pragmas)
if(EMSCRIPTEN)
list(APPEND COMPILE_OPTIONS -O3)
else()
# Apply -ffast-math to allow compiler autovectorization generate effective SIMD code for arm compilation
list(APPEND COMPILE_OPTIONS -O3 -ffast-math)
endif()
endif()
#####################
# SoundTouch library
add_library(SoundTouch
source/SoundTouch/AAFilter.cpp
source/SoundTouch/BPMDetect.cpp
source/SoundTouch/cpu_detect_x86.cpp
source/SoundTouch/FIFOSampleBuffer.cpp
source/SoundTouch/FIRFilter.cpp
source/SoundTouch/InterpolateCubic.cpp
source/SoundTouch/InterpolateLinear.cpp
source/SoundTouch/InterpolateShannon.cpp
source/SoundTouch/mmx_optimized.cpp
source/SoundTouch/PeakFinder.cpp
source/SoundTouch/RateTransposer.cpp
source/SoundTouch/SoundTouch.cpp
source/SoundTouch/sse_optimized.cpp
source/SoundTouch/TDStretch.cpp
)
target_include_directories(SoundTouch PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_definitions(SoundTouch PRIVATE ${COMPILE_DEFINITIONS})
target_compile_options(SoundTouch PRIVATE ${COMPILE_OPTIONS})
if(BUILD_SHARED_LIBS)
set_target_properties(SoundTouch PROPERTIES
VERSION ${CMAKE_PROJECT_VERSION}
)
if(WIN32)
set_target_properties(SoundTouch PROPERTIES
WINDOWS_EXPORT_ALL_SYMBOLS TRUE
)
else()
set_target_properties(SoundTouch PROPERTIES
SOVERSION ${PROJECT_VERSION_MAJOR}
)
endif()
endif()
option(INTEGER_SAMPLES "Use integers instead of floats for samples" OFF)
if(INTEGER_SAMPLES)
target_compile_definitions(SoundTouch PRIVATE SOUNDTOUCH_INTEGER_SAMPLES)
else()
target_compile_definitions(SoundTouch PRIVATE SOUNDTOUCH_FLOAT_SAMPLES)
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(armv7.*|armv8.*|aarch64.*)$")
set(NEON_CPU ON)
else()
set(NEON_CPU OFF)
endif()
option(NEON "Use ARM Neon SIMD instructions if in ARM CPU" ON)
if(${NEON} AND ${NEON_CPU})
target_compile_definitions(SoundTouch PRIVATE SOUNDTOUCH_USE_NEON)
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64.*$")
target_compile_options(SoundTouch PRIVATE -mfpu=neon)
endif()
endif()
find_package(OpenMP)
option(OPENMP "Use parallel multicore calculation through OpenMP" OFF)
if(OPENMP AND OPENMP_FOUND)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
install(
FILES
include/BPMDetect.h
include/FIFOSampleBuffer.h
include/FIFOSamplePipe.h
include/STTypes.h
include/SoundTouch.h
include/soundtouch_config.h
DESTINATION
"${CMAKE_INSTALL_INCLUDEDIR}/soundtouch"
COMPONENT SoundTouch
)
install(TARGETS SoundTouch
EXPORT SoundTouchTargets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT SoundTouch
)
#######################
# soundstretch utility
option(SOUNDSTRETCH "Build soundstretch command line utility." ON)
if(SOUNDSTRETCH)
add_executable(soundstretch
source/SoundStretch/main.cpp
source/SoundStretch/RunParameters.cpp
source/SoundStretch/WavFile.cpp
)
target_include_directories(soundstretch PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
target_compile_definitions(soundstretch PRIVATE ${COMPILE_DEFINITIONS})
target_compile_options(soundstretch PRIVATE ${COMPILE_OPTIONS})
target_link_libraries(soundstretch PRIVATE SoundTouch)
if(INTEGER_SAMPLES)
target_compile_definitions(soundstretch PRIVATE SOUNDTOUCH_INTEGER_SAMPLES)
endif()
install(TARGETS soundstretch
DESTINATION bin
COMPONENT soundstretch
)
endif()
########################
# SoundTouchDll library
option(SOUNDTOUCH_DLL "Build SoundTouchDLL C wrapper library" OFF)
if(SOUNDTOUCH_DLL)
add_library(SoundTouchDLL SHARED
source/SoundTouchDLL/SoundTouchDLL.cpp
source/SoundTouchDLL/SoundTouchDLL.rc
)
set_target_properties(SoundTouch PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
target_compile_options(SoundTouchDLL PRIVATE ${COMPILE_OPTIONS})
set_target_properties(SoundTouchDLL PROPERTIES CXX_VISIBILITY_PRESET hidden)
target_compile_definitions(SoundTouchDLL PRIVATE DLL_EXPORTS)
target_include_directories(SoundTouchDLL PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
target_link_libraries(SoundTouchDLL PRIVATE SoundTouch)
install(FILES source/SoundTouchDLL/SoundTouchDLL.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/soundtouch" COMPONENT SoundTouchDLL)
install(TARGETS SoundTouchDLL EXPORT SoundTouchTargets COMPONENT SoundTouchDLL)
endif()
########################
# pkgconfig
set(prefix "${CMAKE_INSTALL_PREFIX}")
set(execprefix "\${prefix}")
set(libdir "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
set(VERSION "${CMAKE_PROJECT_VERSION}")
configure_file(soundtouch.pc.in "${CMAKE_CURRENT_BINARY_DIR}/soundtouch.pc" @ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/soundtouch.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" COMPONENT SoundTouch)
# CMake config
include(CMakePackageConfigHelpers)
set(SOUNDTOUCH_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/SoundTouch")
install(
EXPORT SoundTouchTargets
FILE SoundTouchTargets.cmake
NAMESPACE SoundTouch::
DESTINATION "${SOUNDTOUCH_INSTALL_CMAKEDIR}"
COMPONENT SoundTouch
)
configure_package_config_file(SoundTouchConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/SoundTouchConfig.cmake"
INSTALL_DESTINATION "${SOUNDTOUCH_INSTALL_CMAKEDIR}"
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/SoundTouchConfigVersion.cmake"
VERSION "${CMAKE_PROJECT_VERSION}"
COMPATIBILITY SameMajorVersion
)
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/SoundTouchConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/SoundTouchConfigVersion.cmake"
DESTINATION "${SOUNDTOUCH_INSTALL_CMAKEDIR}"
COMPONENT SoundTouch
)

View File

@ -2,7 +2,7 @@
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@ -117,7 +117,7 @@ be combined with the library in order to run.
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
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
@ -455,4 +455,4 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
END OF TERMS AND CONDITIONS

View File

@ -1,20 +1,16 @@
## Process this file with automake to create Makefile.in
##
## $Id$
##
## Copyright (C) 2003 - David W. Durham
##
## 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
@ -26,9 +22,8 @@ include $(top_srcdir)/config/am_include.mk
## 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
pkgdoc_DATA=COPYING.TXT README.html
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=

File diff suppressed because it is too large Load Diff

14
SoundTouchConfig.cmake.in Normal file
View File

@ -0,0 +1,14 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/SoundTouchTargets.cmake")
check_required_components(SoundTouch)
get_target_property(SoundTouch_LOCATION SoundTouch::SoundTouch LOCATION)
message(STATUS "Found SoundTouch: ${SoundTouch_LOCATION}")
if(@SOUNDTOUCH_DLL@)
check_required_components(SoundTouchDLL)
get_target_property(SoundTouchDLL_LOCATION SoundTouch::SoundTouchDLL LOCATION)
message(STATUS "Found SoundTouchDLL: ${SoundTouchDLL_LOCATION}")
endif()

View File

@ -1,8 +1,8 @@
set SOUND_DIR=d:\dev\test_sounds
set SOUND_DIR=c:\dev\test_sounds
set OUT_DIR=.
set TEST_NAME=semmari
set OUT_NAME=out
set SS=soundstretch
set SS=soundstretch_x64
set TEST_PARAM=-pitch=-3 -bpm
call %SS% %SOUND_DIR%\%TEST_NAME%-8b1.wav %OUT_DIR%\%OUT_NAME%-8b1.wav %TEST_PARAM%

View File

@ -1,7 +1,7 @@
# $Id$
#!/bin/sh
unset ACLOCAL
if [ "$1" = "--clean" ]
then
if [ -a Makefile ]
@ -10,15 +10,12 @@ then
elif [ -a configure ]
then
configure && $0 --clean
else
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

View File

@ -1,8 +1,6 @@
## vim:tw=78
## Process this file with automake to create Makefile.in
##
## $Id$
##
## 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
@ -19,16 +17,10 @@
## Place - Suite 330, Boston, MA 02111-1307, USA
## These are common definitions used in all Makefiles
## It is actually included when a makefile.am is coverted to Makefile.in
## It is actually included when a makefile.am is converted to Makefile.in
## by automake, so it's ok to have @MACROS@ that will be set by configure
## INCLUDES is automatically added to CXXFLAGS at compile time. The
## $(top_srcdir) macro is set by configure. It's important to use $(top_srcdir)
## in case a user decides to build in a separate directory from the base package
## directory. Using absolute, or relative paths is a bad idea.
INCLUDES=-I$(top_srcdir)/include
AM_CPPFLAGS=-I$(top_srcdir)/include
# doc directory
pkgdocdir=$(prefix)/doc/@PACKAGE@

View File

@ -1,3 +0,0 @@
Starting from SoundTouch 1.6.0, the "configure" file is removed from the source code package due to autoconf/automake version conflicts.
Instead, generate the "configure" file using local tools by invoking "./bootstrap" script, then configure & compile as usual.

View File

@ -1,36 +1,41 @@
dnl SoundTouch configure.ac, by David W. Durham
dnl
dnl $Id$
dnl
dnl This file is part of SoundTouch, an audio processing library for pitch/time adjustments
dnl
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
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
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, 1.7.0, [http://www.surina.net/soundtouch])
AC_INIT([SoundTouch],[2.3.2],[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)
AM_CONFIG_HEADER([include/soundtouch_config.h])
AC_CONFIG_MACRO_DIR([config/m4])
AC_CONFIG_HEADERS([config.h include/soundtouch_config.h])
AM_INIT_AUTOMAKE
#AC_DISABLE_SHARED dnl This makes libtool only build static libs
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_USE_SYSTEM_EXTENSIONS dnl enable posix extensions in glibc
AC_LANG(C++)
# Compiler flags. Apply -ffast-math to allow compiler autovectorization generate effective SIMD code for arm compilation
CXXFLAGS="${CXXFLAGS} -O3 -ffast-math -Wall -Wextra -Wzero-as-null-pointer-constant -Wno-unknown-pragmas"
# Set AR_FLAGS to avoid build warning "ar: `u' modifier ignored since `D' is the default (see `U')"
AR_FLAGS='cr'
dnl ############################################################################
@ -45,7 +50,7 @@ AC_PROG_INSTALL
#AC_PROG_LN_S
AC_PROG_MAKE_SET
AM_PROG_LIBTOOL dnl turn on using libtool
LT_INIT dnl turn on using libtool
@ -53,17 +58,18 @@ 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])
AC_CHECK_HEADERS([cpuid.h])
AC_CHECK_HEADERS([arm_neon.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
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 $
@ -75,26 +81,34 @@ AC_C_INLINE
AC_ARG_ENABLE(integer-samples,
[AC_HELP_STRING([--enable-integer-samples],
[use integer samples instead of floats
[default=yes]])],,
[AS_HELP_STRING([--enable-integer-samples],[use integer samples instead of floats [default=no]])],,
[enable_integer_samples=no])
AC_ARG_ENABLE(openmp,
[AS_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}"],
[use MMX or SSE optimization [default=yes]])],[enable_x86_optimizations="${enableval}"],
[enable_x86_optimizations=yes])
# Let the user enable/disable the x86 optimizations.
# Useful when compiling on non-x86 architectures.
AC_ARG_ENABLE([neon-optimizations],
[AS_HELP_STRING([--enable-neon-optimizations],
[use ARM NEON optimization [default=yes]])],[enable_neon_optimizations="${enableval}"],
[enable_neon_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])
@ -102,16 +116,23 @@ else
echo "****** Float sample type enabled ******"
AC_DEFINE(SOUNDTOUCH_FLOAT_SAMPLES,1,[Use Float as Sample type])
fi
AM_CONDITIONAL([SOUNDTOUCH_FLOAT_SAMPLES], [test "x$enable_integer_samples" != "xyes"])
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
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
OPT_CXXFLAGS="-mmmx -Winline"
CXXFLAGS="$OPT_CXXFLAGS $CXXFLAGS"
CXXFLAGS="-mmmx -Winline $CXXFLAGS"
# Check if the user can compile MMX code using intrinsics.
# GCC supports MMX intrinsics since version 3.3
@ -137,14 +158,15 @@ if test "x$enable_x86_optimizations" = "xyes" -a "x$ac_cv_header_cpuid_h" = "xye
echo "****** No MMX support found ******"
if test "x$enable_integer_samples" = "xyes"; then
echo "****** Disabling optimizations. Using integer samples with no MMX support ******"
AC_DEFINE([SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS],[1],[Do not use x86 optimizations])
CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
fi
fi
# SSE support
original_saved_CXXFLAGS=$CXXFLAGS
have_sse_intrinsics=no
OPT_CXXFLAGS="-msse -Winline"
CXXFLAGS="$OPT_CXXFLAGS $CXXFLAGS"
CXXFLAGS="-msse -Winline $CXXFLAGS"
# Check if the user can compile SSE code using intrinsics.
# GCC supports SSE intrinsics since version 3.3
@ -170,16 +192,69 @@ if test "x$enable_x86_optimizations" = "xyes" -a "x$ac_cv_header_cpuid_h" = "xye
echo "****** No SSE support found ******"
if test "x$enable_integer_samples" != "xyes"; then
echo "****** Disabling optimizations. Using float samples with no SSE support ******"
AC_DEFINE([SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS],[1],[Do not use x86 optimizations])
CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
fi
fi
else
# Disable optimizations in SSTypes.h since the user requested it.
echo "****** x86 optimizations disabled ******"
AC_DEFINE([SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS],[1],[Do not use x86 optimizations])
CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
fi
if test "x$enable_neon_optimizations" = "xyes" -a "x$ac_cv_header_arm_neon_h" = "xyes"; then
# Check for ARM NEON support
original_saved_CXXFLAGS=$CXXFLAGS
have_neon=no
CXXFLAGS="-mfpu=neon -march=native $CXXFLAGS"
# Check if can compile neon code using intrinsics, require GCC >= 4.3 for autovectorization.
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3))
#error "Need GCC >= 4.3 for neon autovectorization"
#endif
#include <arm_neon.h>
int main () {
int32x4_t t = {1};
return vaddq_s32(t,t)[0] == 2;
}]])],[have_neon=yes])
CXXFLAGS=$original_saved_CXXFLAGS
if test "x$have_neon" = "xyes" ; then
echo "****** NEON support enabled ******"
CPPFLAGS="-mfpu=neon -march=native -mtune=native $CPPFLAGS"
AC_DEFINE(SOUNDTOUCH_USE_NEON,1,[Use ARM NEON extension])
fi
fi
AC_CANONICAL_HOST
HOST_OS=""
AS_CASE([$host_cpu],
[x86_64],
[
x86_64=true
x86=true
],
[i?86],
[
x86=true
])
AM_CONDITIONAL([X86], [test "$x86" = true])
AM_CONDITIONAL([X86_64], [test "$x86_64" = true])
AC_SUBST([HOST_OS])
# 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.
#
@ -195,11 +270,9 @@ 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]))
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])
@ -229,11 +302,12 @@ AC_CONFIG_FILES([
source/Makefile
source/SoundTouch/Makefile
source/SoundStretch/Makefile
source/SoundTouchDLL/Makefile
include/Makefile
])
AC_OUTPUT(
soundtouch.pc
)
AC_CONFIG_FILES([soundtouch.pc
])
AC_OUTPUT
dnl use 'echo' to put stuff here if you want a message to the builder

View File

@ -1,5 +1,4 @@
# Helper script for building a source code release package
# $Id$
rm -Rf soundtouch
rm soundtouch.zip

View File

@ -1,164 +1,205 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Beats-per-minute (BPM) detection routine.
///
/// The beat detection algorithm works as follows:
/// - Use function 'inputSamples' to input a chunks of samples to the class for
/// analysis. It's a good idea to enter a large sound file or stream in smallish
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden,
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
/// Simple averaging is used for anti-alias filtering because the resulting signal
/// quality isn't of that high importance.
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
/// taking absolute value that's smoothed by sliding average. Signal levels that
/// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
/// function, calculates it's precise location and converts this reading to bpm's.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _BPMDetect_H_
#define _BPMDetect_H_
#include "STTypes.h"
#include "FIFOSampleBuffer.h"
namespace soundtouch
{
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
#define MIN_BPM 29
/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
#define MAX_BPM 200
/// Class for calculating BPM rate for audio data.
class BPMDetect
{
protected:
/// Auto-correlation accumulator bins.
float *xcorr;
/// Amplitude envelope sliding average approximation level accumulator
double envelopeAccu;
/// RMS volume sliding average approximation level accumulator
double RMSVolumeAccu;
/// Sample average counter.
int decimateCount;
/// Sample average accumulator for FIFO-like decimation.
soundtouch::LONG_SAMPLETYPE decimateSum;
/// Decimate sound by this coefficient to reach approx. 500 Hz.
int decimateBy;
/// Auto-correlation window length
int windowLen;
/// Number of channels (1 = mono, 2 = stereo)
int channels;
/// sample rate
int sampleRate;
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for
/// the first these many correlation bins.
int windowStart;
/// FIFO-buffer for decimated processing samples.
soundtouch::FIFOSampleBuffer *buffer;
/// Updates auto-correlation function for given number of decimated samples that
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
/// though).
void updateXCorr(int process_samples /// How many samples are processed.
);
/// Decimates samples to approx. 500 Hz.
///
/// \return Number of output samples.
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
int numsamples ///< Number of source samples.
);
/// Calculates amplitude envelope for the buffer of samples.
/// Result is output to 'samples'.
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
int numsamples ///< Number of samples in buffer
);
/// remove constant bias from xcorr data
void removeBias();
public:
/// Constructor.
BPMDetect(int numChannels, ///< Number of channels in sample data.
int sampleRate ///< Sample rate in Hz.
);
/// Destructor.
virtual ~BPMDetect();
/// Inputs a block of samples for analyzing: Envelopes the samples and then
/// updates the autocorrelation estimation. When whole song data has been input
/// in smaller blocks using this function, read the resulting bpm with 'getBpm'
/// function.
///
/// Notice that data in 'samples' array can be disrupted in processing.
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
int numSamples ///< Number of samples in buffer
);
/// Analyzes the results and returns the BPM rate. Use this function to read result
/// after whole song data has been input to the class by consecutive calls of
/// 'inputSamples' function.
///
/// \return Beats-per-minute rate, or zero if detection failed.
float getBpm();
};
}
#endif // _BPMDetect_H_
////////////////////////////////////////////////////////////////////////////////
///
/// Beats-per-minute (BPM) detection routine.
///
/// The beat detection algorithm works as follows:
/// - Use function 'inputSamples' to input a chunks of samples to the class for
/// analysis. It's a good idea to enter a large sound file or stream in smallish
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden,
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
/// Simple averaging is used for anti-alias filtering because the resulting signal
/// quality isn't of that high importance.
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
/// taking absolute value that's smoothed by sliding average. Signal levels that
/// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
/// function, calculates it's precise location and converts this reading to bpm's.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _BPMDetect_H_
#define _BPMDetect_H_
#include <vector>
#include "STTypes.h"
#include "FIFOSampleBuffer.h"
namespace soundtouch
{
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
#define MIN_BPM 45
/// Maximum allowed BPM rate range. Used for calculating algorithm parametrs
#define MAX_BPM_RANGE 200
/// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit.
#define MAX_BPM_VALID 190
////////////////////////////////////////////////////////////////////////////////
typedef struct
{
float pos;
float strength;
} BEAT;
class IIR2_filter
{
double coeffs[5];
double prev[5];
public:
IIR2_filter(const double *lpf_coeffs);
float update(float x);
};
/// Class for calculating BPM rate for audio data.
class BPMDetect
{
protected:
/// Auto-correlation accumulator bins.
float *xcorr;
/// Sample average counter.
int decimateCount;
/// Sample average accumulator for FIFO-like decimation.
soundtouch::LONG_SAMPLETYPE decimateSum;
/// Decimate sound by this coefficient to reach approx. 500 Hz.
int decimateBy;
/// Auto-correlation window length
int windowLen;
/// Number of channels (1 = mono, 2 = stereo)
int channels;
/// sample rate
int sampleRate;
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for
/// the first these many correlation bins.
int windowStart;
/// window functions for data preconditioning
float *hamw;
float *hamw2;
// beat detection variables
int pos;
int peakPos;
int beatcorr_ringbuffpos;
int init_scaler;
float peakVal;
float *beatcorr_ringbuff;
/// FIFO-buffer for decimated processing samples.
soundtouch::FIFOSampleBuffer *buffer;
/// Collection of detected beat positions
//BeatCollection beats;
std::vector<BEAT> beats;
// 2nd order low-pass-filter
IIR2_filter beat_lpf;
/// Updates auto-correlation function for given number of decimated samples that
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
/// though).
void updateXCorr(int process_samples /// How many samples are processed.
);
/// Decimates samples to approx. 500 Hz.
///
/// \return Number of output samples.
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
int numsamples ///< Number of source samples.
);
/// Calculates amplitude envelope for the buffer of samples.
/// Result is output to 'samples'.
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
int numsamples ///< Number of samples in buffer
);
/// remove constant bias from xcorr data
void removeBias();
// Detect individual beat positions
void updateBeatPos(int process_samples);
public:
/// Constructor.
BPMDetect(int numChannels, ///< Number of channels in sample data.
int sampleRate ///< Sample rate in Hz.
);
/// Destructor.
virtual ~BPMDetect();
/// Inputs a block of samples for analyzing: Envelopes the samples and then
/// updates the autocorrelation estimation. When whole song data has been input
/// in smaller blocks using this function, read the resulting bpm with 'getBpm'
/// function.
///
/// Notice that data in 'samples' array can be disrupted in processing.
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
int numSamples ///< Number of samples in buffer
);
/// Analyzes the results and returns the BPM rate. Use this function to read result
/// after whole song data has been input to the class by consecutive calls of
/// 'inputSamples' function.
///
/// \return Beats-per-minute rate, or zero if detection failed.
float getBpm();
/// Get beat position arrays. Note: The array includes also really low beat detection values
/// in absence of clear strong beats. Consumer may wish to filter low values away.
/// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array.
///
/// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
///
/// \return number of beats in the arrays.
int getBeats(float *pos, float *strength, int max_num);
};
}
#endif // _BPMDetect_H_

View File

@ -1,178 +1,180 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe.
///
/// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the
/// output samples from the buffer as well as grows the storage size
/// whenever necessary.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSampleBuffer_H
#define FIFOSampleBuffer_H
#include "FIFOSamplePipe.h"
namespace soundtouch
{
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
/// care of storage size adjustment and data moving during input/output operations.
///
/// Notice that in case of stereo audio, one sample is considered to consist of
/// both channel data.
class FIFOSampleBuffer : public FIFOSamplePipe
{
private:
/// Sample buffer.
SAMPLETYPE *buffer;
// Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
// 16-byte aligned location of this buffer
SAMPLETYPE *bufferUnaligned;
/// Sample buffer size in bytes
uint sizeInBytes;
/// How many samples are currently in buffer.
uint samplesInBuffer;
/// Channels, 1=mono, 2=stereo.
uint channels;
/// Current position pointer to the buffer. This pointer is increased when samples are
/// removed from the pipe so that it's necessary to actually rewind buffer (move data)
/// only new data when is put to the pipe.
uint bufferPos;
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
/// beginning of the buffer.
void rewind();
/// Ensures that the buffer has capacity for at least this many samples.
void ensureCapacity(uint capacityRequirement);
/// Returns current capacity.
uint getCapacity() const;
public:
/// Constructor
FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
///< Default is stereo.
);
/// destructor
~FIFOSampleBuffer();
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin();
/// Returns a pointer to the end of the used part of the sample buffer (i.e.
/// where the new samples are to be inserted). This function may be used for
/// inserting new samples into the sample buffer directly. Please be careful
/// not corrupt the book-keeping!
///
/// When using this function as means for inserting new samples, also remember
/// to increase the sample count afterwards, by calling the
/// 'putSamples(numSamples)' function.
SAMPLETYPE *ptrEnd(
uint slackCapacity ///< How much free capacity (in samples) there _at least_
///< should be so that the caller can succesfully insert the
///< desired samples to the buffer. If necessary, the function
///< grows the buffer size to comply with this requirement.
);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert.
);
/// Adjusts the book-keeping to increase number of samples in the buffer without
/// copying any actual samples.
///
/// This function is used to update the number of samples in the sample buffer
/// when accessing the buffer directly with 'ptrEnd' function. Please be
/// careful though!
virtual void putSamples(uint numSamples ///< Number of samples been inserted.
);
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
);
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
);
/// Returns number of samples currently available.
virtual uint numSamples() const;
/// Sets number of channels, 1 = mono, 2 = stereo.
void setChannels(int numChannels);
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const;
/// Clears all the samples.
virtual void clear();
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
uint adjustAmountOfSamples(uint numSamples);
};
}
#endif
////////////////////////////////////////////////////////////////////////////////
///
/// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe.
///
/// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the
/// output samples from the buffer as well as grows the storage size
/// whenever necessary.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSampleBuffer_H
#define FIFOSampleBuffer_H
#include "FIFOSamplePipe.h"
namespace soundtouch
{
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
/// care of storage size adjustment and data moving during input/output operations.
///
/// Notice that in case of stereo audio, one sample is considered to consist of
/// both channel data.
class FIFOSampleBuffer : public FIFOSamplePipe
{
private:
/// Sample buffer.
SAMPLETYPE *buffer;
// Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
// 16-byte aligned location of this buffer
SAMPLETYPE *bufferUnaligned;
/// Sample buffer size in bytes
uint sizeInBytes;
/// How many samples are currently in buffer.
uint samplesInBuffer;
/// Channels, 1=mono, 2=stereo.
uint channels;
/// Current position pointer to the buffer. This pointer is increased when samples are
/// removed from the pipe so that it's necessary to actually rewind buffer (move data)
/// only new data when is put to the pipe.
uint bufferPos;
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
/// beginning of the buffer.
void rewind();
/// Ensures that the buffer has capacity for at least this many samples.
void ensureCapacity(uint capacityRequirement);
/// Returns current capacity.
uint getCapacity() const;
public:
/// Constructor
FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
///< Default is stereo.
);
/// destructor
~FIFOSampleBuffer() override;
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() override;
/// Returns a pointer to the end of the used part of the sample buffer (i.e.
/// where the new samples are to be inserted). This function may be used for
/// inserting new samples into the sample buffer directly. Please be careful
/// not corrupt the book-keeping!
///
/// When using this function as means for inserting new samples, also remember
/// to increase the sample count afterwards, by calling the
/// 'putSamples(numSamples)' function.
SAMPLETYPE *ptrEnd(
uint slackCapacity ///< How much free capacity (in samples) there _at least_
///< should be so that the caller can successfully insert the
///< desired samples to the buffer. If necessary, the function
///< grows the buffer size to comply with this requirement.
);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert.
) override;
/// Adjusts the book-keeping to increase number of samples in the buffer without
/// copying any actual samples.
///
/// This function is used to update the number of samples in the sample buffer
/// when accessing the buffer directly with 'ptrEnd' function. Please be
/// careful though!
virtual void putSamples(uint numSamples ///< Number of samples been inserted.
);
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) override;
/// Returns number of samples currently available.
virtual uint numSamples() const override;
/// Sets number of channels, 1 = mono, 2 = stereo.
void setChannels(int numChannels);
/// Get number of channels
int getChannels()
{
return channels;
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const override;
/// Clears all the samples.
virtual void clear() override;
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
uint adjustAmountOfSamples(uint numSamples) override;
/// Add silence to end of buffer
void addSilent(uint nSamples);
};
}
#endif

View File

@ -1,234 +1,230 @@
////////////////////////////////////////////////////////////////////////////////
///
/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
/// samples by operating like a first-in-first-out pipe: New samples are fed
/// into one end of the pipe with the 'putSamples' function, and the processed
/// samples are received from the other end with the 'receiveSamples' function.
///
/// 'FIFOProcessor' : A base class for classes the do signal processing with
/// the samples while operating like a first-in-first-out pipe. When samples
/// are input with the 'putSamples' function, the class processes them
/// and moves the processed samples to the given 'output' pipe object, which
/// may be either another processing stage, or a fifo sample buffer object.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSamplePipe_H
#define FIFOSamplePipe_H
#include <assert.h>
#include <stdlib.h>
#include "STTypes.h"
namespace soundtouch
{
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
class FIFOSamplePipe
{
public:
// virtual default destructor
virtual ~FIFOSamplePipe() {}
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() = 0;
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert.
) = 0;
// Moves samples from the 'other' pipe instance to this instance.
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
)
{
int oNumSamples = other.numSamples();
putSamples(other.ptrBegin(), oNumSamples);
other.receiveSamples(oNumSamples);
};
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
) = 0;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) = 0;
/// Returns number of samples currently available.
virtual uint numSamples() const = 0;
// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const = 0;
/// Clears all the samples.
virtual void clear() = 0;
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples) = 0;
};
/// Base-class for sound processing routines working in FIFO principle. With this base
/// class it's easy to implement sound processing stages that can be chained together,
/// so that samples that are fed into beginning of the pipe automatically go through
/// all the processing stages.
///
/// When samples are input to this class, they're first processed and then put to
/// the FIFO pipe that's defined as output of this class. This output pipe can be
/// either other processing stage or a FIFO sample buffer.
class FIFOProcessor :public FIFOSamplePipe
{
protected:
/// Internal pipe where processed samples are put.
FIFOSamplePipe *output;
/// Sets output pipe.
void setOutPipe(FIFOSamplePipe *pOutput)
{
assert(output == NULL);
assert(pOutput != NULL);
output = pOutput;
}
/// Constructor. Doesn't define output pipe; it has to be set be
/// 'setOutPipe' function.
FIFOProcessor()
{
output = NULL;
}
/// Constructor. Configures output pipe.
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
)
{
output = pOutput;
}
/// Destructor.
virtual ~FIFOProcessor()
{
}
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin()
{
return output->ptrBegin();
}
public:
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
)
{
return output->receiveSamples(outBuffer, maxSamples);
}
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
)
{
return output->receiveSamples(maxSamples);
}
/// Returns number of samples currently available.
virtual uint numSamples() const
{
return output->numSamples();
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const
{
return output->isEmpty();
}
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples)
{
return output->adjustAmountOfSamples(numSamples);
}
};
}
#endif
////////////////////////////////////////////////////////////////////////////////
///
/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
/// samples by operating like a first-in-first-out pipe: New samples are fed
/// into one end of the pipe with the 'putSamples' function, and the processed
/// samples are received from the other end with the 'receiveSamples' function.
///
/// 'FIFOProcessor' : A base class for classes the do signal processing with
/// the samples while operating like a first-in-first-out pipe. When samples
/// are input with the 'putSamples' function, the class processes them
/// and moves the processed samples to the given 'output' pipe object, which
/// may be either another processing stage, or a fifo sample buffer object.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIFOSamplePipe_H
#define FIFOSamplePipe_H
#include <assert.h>
#include <stdlib.h>
#include "STTypes.h"
namespace soundtouch
{
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
class FIFOSamplePipe
{
protected:
bool verifyNumberOfChannels(int nChannels) const
{
if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS))
{
return true;
}
ST_THROW_RT_ERROR("Error: Illegal number of channels");
return false;
}
public:
// virtual default destructor
virtual ~FIFOSamplePipe() {}
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() = 0;
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
/// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert.
) = 0;
// Moves samples from the 'other' pipe instance to this instance.
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
)
{
const uint oNumSamples = other.numSamples();
putSamples(other.ptrBegin(), oNumSamples);
other.receiveSamples(oNumSamples);
}
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
) = 0;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) = 0;
/// Returns number of samples currently available.
virtual uint numSamples() const = 0;
// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const = 0;
/// Clears all the samples.
virtual void clear() = 0;
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples) = 0;
};
/// Base-class for sound processing routines working in FIFO principle. With this base
/// class it's easy to implement sound processing stages that can be chained together,
/// so that samples that are fed into beginning of the pipe automatically go through
/// all the processing stages.
///
/// When samples are input to this class, they're first processed and then put to
/// the FIFO pipe that's defined as output of this class. This output pipe can be
/// either other processing stage or a FIFO sample buffer.
class FIFOProcessor :public FIFOSamplePipe
{
protected:
/// Internal pipe where processed samples are put.
FIFOSamplePipe *output;
/// Sets output pipe.
void setOutPipe(FIFOSamplePipe *pOutput)
{
assert(output == nullptr);
assert(pOutput != nullptr);
output = pOutput;
}
/// Constructor. Doesn't define output pipe; it has to be set be
/// 'setOutPipe' function.
FIFOProcessor()
{
output = nullptr;
}
/// Constructor. Configures output pipe.
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
)
{
output = pOutput;
}
/// Destructor.
virtual ~FIFOProcessor() override
{
}
/// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly.
/// Please be careful for not to corrupt the book-keeping!
///
/// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() override
{
return output->ptrBegin();
}
public:
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
) override
{
return output->receiveSamples(outBuffer, maxSamples);
}
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) override
{
return output->receiveSamples(maxSamples);
}
/// Returns number of samples currently available.
virtual uint numSamples() const override
{
return output->numSamples();
}
/// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const override
{
return output->isEmpty();
}
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples) override
{
return output->adjustAmountOfSamples(numSamples);
}
};
}
#endif

View File

@ -1,26 +1,22 @@
## Process this file with automake to create Makefile.in
##
## $Id$
##
## Copyright (C) 2003 - David W. Durham
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
## I used config/am_include.mk for common definitions
include $(top_srcdir)/config/am_include.mk
pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h
## Process this file with automake to create Makefile.in
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
## I used config/am_include.mk for common definitions
include $(top_srcdir)/config/am_include.mk
pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h

View File

@ -1,167 +1,191 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Common type definitions for SoundTouch audio processing library.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 3 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef STTypes_H
#define STTypes_H
typedef unsigned int uint;
typedef unsigned long ulong;
#ifdef __GNUC__
// In GCC, include soundtouch_config.h made by config scritps
#include "soundtouch_config.h"
#endif
#ifndef _WINDEF_
// if these aren't defined already by Windows headers, define now
typedef int BOOL;
#define FALSE 0
#define TRUE 1
#endif // _WINDEF_
namespace soundtouch
{
/// Activate these undef's to overrule the possible sampletype
/// setting inherited from some other header file:
//#undef SOUNDTOUCH_INTEGER_SAMPLES
//#undef SOUNDTOUCH_FLOAT_SAMPLES
#if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
/// Choose either 32bit floating point or 16bit integer sampletype
/// by choosing one of the following defines, unless this selection
/// has already been done in some other file.
////
/// Notes:
/// - In Windows environment, choose the sample format with the
/// following defines.
/// - In GNU environment, the floating point samples are used by
/// default, but integer samples can be chosen by giving the
/// following switch to the configure script:
/// ./configure --enable-integer-samples
/// However, if you still prefer to select the sample format here
/// also in GNU environment, then please #undef the INTEGER_SAMPLE
/// and FLOAT_SAMPLE defines first as in comments above.
//#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples
#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples
#endif
#if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)
/// Define this to allow X86-specific assembler/intrinsic optimizations.
/// Notice that library contains also usual C++ versions of each of these
/// these routines, so if you're having difficulties getting the optimized
/// routines compiled for whatever reason, you may disable these optimizations
/// to make the library compile.
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
/// In GNU environment, allow the user to override this setting by
/// giving the following switch to the configure script:
/// ./configure --disable-x86-optimizations
/// ./configure --enable-x86-optimizations=no
#ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
#endif
#else
/// Always disable optimizations when not using a x86 systems.
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
#endif
// If defined, allows the SIMD-optimized routines to take minor shortcuts
// for improved performance. Undefine to require faithfully similar SIMD
// calculations as in normal C implementation.
#define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// 16bit integer sample type
typedef short SAMPLETYPE;
// data type for sample accumulation: Use 32bit integer to prevent overflows
typedef long LONG_SAMPLETYPE;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// check that only one sample type is defined
#error "conflicting sample types defined"
#endif // SOUNDTOUCH_FLOAT_SAMPLES
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow MMX optimizations
#define SOUNDTOUCH_ALLOW_MMX 1
#endif
#else
// floating point samples
typedef float SAMPLETYPE;
// data type for sample accumulation: Use double to utilize full precision.
typedef double LONG_SAMPLETYPE;
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow SSE optimizations
#define SOUNDTOUCH_ALLOW_SSE 1
#endif
#endif // SOUNDTOUCH_INTEGER_SAMPLES
};
// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions:
// #define ST_NO_EXCEPTION_HANDLING 1
#ifdef ST_NO_EXCEPTION_HANDLING
// Exceptions disabled. Throw asserts instead if enabled.
#include <assert.h>
#define ST_THROW_RT_ERROR(x) {assert((const char *)x);}
#else
// use c++ standard exceptions
#include <stdexcept>
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
#endif
// When this #define is active, eliminates a clicking sound when the "rate" or "pitch"
// parameter setting crosses from value <1 to >=1 or vice versa during processing.
// Default is off as such crossover is untypical case and involves a slight sound
// quality compromise.
//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1
#endif
////////////////////////////////////////////////////////////////////////////////
///
/// Common type definitions for SoundTouch audio processing library.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef STTypes_H
#define STTypes_H
typedef unsigned int uint;
typedef unsigned long ulong;
// Patch for MinGW: on Win64 long is 32-bit
#ifdef _WIN64
typedef unsigned long long ulongptr;
#else
typedef ulong ulongptr;
#endif
// Helper macro for aligning pointer up to next 16-byte boundary
#define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 )
#if (defined(__GNUC__) && !defined(ANDROID))
// In GCC, include soundtouch_config.h made by config scritps.
// Skip this in Android compilation that uses GCC but without configure scripts.
#include "soundtouch_config.h"
#endif
namespace soundtouch
{
/// Max allowed number of channels. This is not a hard limit but to have some
/// maximum value for argument sanity checks -- can be increased if necessary
#define SOUNDTOUCH_MAX_CHANNELS 32
/// Activate these undef's to overrule the possible sampletype
/// setting inherited from some other header file:
//#undef SOUNDTOUCH_INTEGER_SAMPLES
//#undef SOUNDTOUCH_FLOAT_SAMPLES
/// If following flag is defined, always uses multichannel processing
/// routines also for mono and stero sound. This is for routine testing
/// purposes; output should be same with either routines, yet disabling
/// the dedicated mono/stereo processing routines will result in slower
/// runtime performance so recommendation is to keep this off.
// #define USE_MULTICH_ALWAYS
#if (defined(__SOFTFP__) && defined(ANDROID))
// For Android compilation: Force use of Integer samples in case that
// compilation uses soft-floating point emulation - soft-fp is way too slow
#undef SOUNDTOUCH_FLOAT_SAMPLES
#define SOUNDTOUCH_INTEGER_SAMPLES 1
#endif
#if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
/// Choose either 32bit floating point or 16bit integer sampletype
/// by choosing one of the following defines, unless this selection
/// has already been done in some other file.
////
/// Notes:
/// - In Windows environment, choose the sample format with the
/// following defines.
/// - In GNU environment, the floating point samples are used by
/// default, but integer samples can be chosen by giving the
/// following switch to the configure script:
/// ./configure --enable-integer-samples
/// However, if you still prefer to select the sample format here
/// also in GNU environment, then please #undef the INTEGER_SAMPLE
/// and FLOAT_SAMPLE defines first as in comments above.
//#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples
#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples
#endif
#if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)
/// Define this to allow X86-specific assembler/intrinsic optimizations.
/// Notice that library contains also usual C++ versions of each of these
/// these routines, so if you're having difficulties getting the optimized
/// routines compiled for whatever reason, you may disable these optimizations
/// to make the library compile.
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
/// In GNU environment, allow the user to override this setting by
/// giving the following switch to the configure script:
/// ./configure --disable-x86-optimizations
/// ./configure --enable-x86-optimizations=no
#ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
#endif
#else
/// Always disable optimizations when not using a x86 systems.
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
#endif
// If defined, allows the SIMD-optimized routines to skip unevenly aligned
// memory offsets that can cause performance penalty in some SIMD implementations.
// Causes slight compromise in sound quality.
// #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// 16bit integer sample type
typedef short SAMPLETYPE;
// data type for sample accumulation: Use 32bit integer to prevent overflows
typedef long LONG_SAMPLETYPE;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// check that only one sample type is defined
#error "conflicting sample types defined"
#endif // SOUNDTOUCH_FLOAT_SAMPLES
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow MMX optimizations (not available in X64 mode)
#if (!_M_X64)
#define SOUNDTOUCH_ALLOW_MMX 1
#endif
#endif
#else
// floating point samples
typedef float SAMPLETYPE;
// data type for sample accumulation: Use float also here to enable
// efficient autovectorization
typedef float LONG_SAMPLETYPE;
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow SSE optimizations
#define SOUNDTOUCH_ALLOW_SSE 1
#endif
#endif // SOUNDTOUCH_INTEGER_SAMPLES
#if ((SOUNDTOUCH_ALLOW_SSE) || (__SSE__) || (SOUNDTOUCH_USE_NEON))
#if SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION
#define ST_SIMD_AVOID_UNALIGNED
#endif
#endif
}
// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions:
// #define ST_NO_EXCEPTION_HANDLING 1
#ifdef ST_NO_EXCEPTION_HANDLING
// Exceptions disabled. Throw asserts instead if enabled.
#include <assert.h>
#define ST_THROW_RT_ERROR(x) {assert((const char *)x);}
#else
// use c++ standard exceptions
#include <stdexcept>
#include <string>
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
#endif
// When this #define is active, eliminates a clicking sound when the "rate" or "pitch"
// parameter setting crosses from value <1 to >=1 or vice versa during processing.
// Default is off as such crossover is untypical case and involves a slight sound
// quality compromise.
//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1
#endif

View File

@ -1,277 +1,348 @@
//////////////////////////////////////////////////////////////////////////////
///
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
///
/// Notes:
/// - Initialize the SoundTouch object instance by setting up the sound stream
/// parameters with functions 'setSampleRate' and 'setChannels', then set
/// desired tempo/pitch/rate settings with the corresponding functions.
///
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
/// samples that are to be processed are fed into one of the pipe by calling
/// function 'putSamples', while the ready processed samples can be read
/// from the other end of the pipeline with function 'receiveSamples'.
///
/// - The SoundTouch processing classes require certain sized 'batches' of
/// samples in order to process the sound. For this reason the classes buffer
/// incoming samples until there are enough of samples available for
/// processing, then they carry out the processing step and consequently
/// make the processed samples available for outputting.
///
/// - For the above reason, the processing routines introduce a certain
/// 'latency' between the input and output, so that the samples input to
/// SoundTouch may not be immediately available in the output, and neither
/// the amount of outputtable samples may not immediately be in direct
/// relationship with the amount of previously input samples.
///
/// - The tempo/pitch/rate control parameters can be altered during processing.
/// Please notice though that they aren't currently protected by semaphores,
/// so in multi-thread application external semaphore protection may be
/// required.
///
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
/// tempo and pitch in the same ratio) of the sound. The third available control
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
/// combining the two other controls.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef SoundTouch_H
#define SoundTouch_H
#include "FIFOSamplePipe.h"
#include "STTypes.h"
namespace soundtouch
{
/// Soundtouch library version string
#define SOUNDTOUCH_VERSION "1.7.0"
/// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (10700)
//
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
#define SETTING_USE_AA_FILTER 0
/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
#define SETTING_AA_FILTER_LENGTH 1
/// Enable/disable quick seeking algorithm in tempo changer routine
/// (enabling quick seeking lowers CPU utilization but causes a minor sound
/// quality compromising)
#define SETTING_USE_QUICKSEEK 2
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
/// to how long sequences the original sound is chopped in the time-stretch algorithm.
/// See "STTypes.h" or README for more information.
#define SETTING_SEQUENCE_MS 3
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
/// best possible overlapping location. This determines from how wide window the algorithm
/// may look for an optimal joining location when mixing the sound sequences back together.
/// See "STTypes.h" or README for more information.
#define SETTING_SEEKWINDOW_MS 4
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
/// are mixed back together, to form a continuous sound stream, this parameter defines over
/// how long period the two consecutive sequences are let to overlap each other.
/// See "STTypes.h" or README for more information.
#define SETTING_OVERLAP_MS 5
/// Call "getSetting" with this ID to query nominal average processing sequence
/// size in samples. This value tells approcimate value how many input samples
/// SoundTouch needs to gather before it does DSP processing run for the sample batch.
///
/// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - Returned value is approximate average value, exact processing batch
/// size may wary from time to time
/// - This parameter value is not constant but may change depending on
/// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_INPUT_SEQUENCE 6
/// Call "getSetting" with this ID to query nominal average processing output
/// size in samples. This value tells approcimate value how many output samples
/// SoundTouch outputs once it does DSP processing run for a batch of input samples.
///
/// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - Returned value is approximate average value, exact processing batch
/// size may wary from time to time
/// - This parameter value is not constant but may change depending on
/// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7
class SoundTouch : public FIFOProcessor
{
private:
/// Rate transposer class instance
class RateTransposer *pRateTransposer;
/// Time-stretch class instance
class TDStretch *pTDStretch;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
float virtualRate;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
float virtualTempo;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
float virtualPitch;
/// Flag: Has sample rate been set?
BOOL bSrateSet;
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
/// 'virtualPitch' parameters.
void calcEffectiveRateAndTempo();
protected :
/// Number of channels
uint channels;
/// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
float rate;
/// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
float tempo;
public:
SoundTouch();
virtual ~SoundTouch();
/// Get SoundTouch library version string
static const char *getVersionString();
/// Get SoundTouch library version Id
static uint getVersionId();
/// Sets new rate control value. Normal rate = 1.0, smaller values
/// represent slower rate, larger faster rates.
void setRate(float newRate);
/// Sets new tempo control value. Normal tempo = 1.0, smaller values
/// represent slower tempo, larger faster tempo.
void setTempo(float newTempo);
/// Sets new rate control value as a difference in percents compared
/// to the original rate (-50 .. +100 %)
void setRateChange(float newRate);
/// Sets new tempo control value as a difference in percents compared
/// to the original tempo (-50 .. +100 %)
void setTempoChange(float newTempo);
/// Sets new pitch control value. Original pitch = 1.0, smaller values
/// represent lower pitches, larger values higher pitch.
void setPitch(float newPitch);
/// Sets pitch change in octaves compared to the original pitch
/// (-1.00 .. +1.00)
void setPitchOctaves(float newPitch);
/// Sets pitch change in semi-tones compared to the original pitch
/// (-12 .. +12)
void setPitchSemiTones(int newPitch);
void setPitchSemiTones(float newPitch);
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(uint numChannels);
/// Sets sample rate.
void setSampleRate(uint srate);
/// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers.
//
/// Note: This function is meant for extracting the last samples of a sound
/// stream. This function may introduce additional blank samples in the end
/// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream.
void flush();
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception.
virtual void putSamples(
const SAMPLETYPE *samples, ///< Pointer to sample buffer.
uint numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample
///< contains data for both channels.
);
/// Clears all the samples in the object's output and internal processing
/// buffers.
virtual void clear();
/// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
///
/// \return 'TRUE' if the setting was succesfully changed
BOOL setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
int value ///< New setting value.
);
/// Reads a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
///
/// \return the setting value.
int getSetting(int settingId ///< Setting ID number, see SETTING_... defines.
) const;
/// Returns number of samples currently unprocessed.
virtual uint numUnprocessedSamples() const;
/// Other handy functions that are implemented in the ancestor classes (see
/// classes 'FIFOProcessor' and 'FIFOSamplePipe')
///
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
/// - numSamples() : Get number of 'ready' samples that can be received with
/// function 'receiveSamples()'
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
/// - clear() : Clears all samples from ready/processing buffers.
};
}
#endif
//////////////////////////////////////////////////////////////////////////////
///
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
///
/// Notes:
/// - Initialize the SoundTouch object instance by setting up the sound stream
/// parameters with functions 'setSampleRate' and 'setChannels', then set
/// desired tempo/pitch/rate settings with the corresponding functions.
///
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
/// samples that are to be processed are fed into one of the pipe by calling
/// function 'putSamples', while the ready processed samples can be read
/// from the other end of the pipeline with function 'receiveSamples'.
///
/// - The SoundTouch processing classes require certain sized 'batches' of
/// samples in order to process the sound. For this reason the classes buffer
/// incoming samples until there are enough of samples available for
/// processing, then they carry out the processing step and consequently
/// make the processed samples available for outputting.
///
/// - For the above reason, the processing routines introduce a certain
/// 'latency' between the input and output, so that the samples input to
/// SoundTouch may not be immediately available in the output, and neither
/// the amount of outputtable samples may not immediately be in direct
/// relationship with the amount of previously input samples.
///
/// - The tempo/pitch/rate control parameters can be altered during processing.
/// Please notice though that they aren't currently protected by semaphores,
/// so in multi-thread application external semaphore protection may be
/// required.
///
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
/// tempo and pitch in the same ratio) of the sound. The third available control
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
/// combining the two other controls.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef SoundTouch_H
#define SoundTouch_H
#include "FIFOSamplePipe.h"
#include "STTypes.h"
namespace soundtouch
{
/// Soundtouch library version string
#define SOUNDTOUCH_VERSION "2.3.3"
/// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (20303)
//
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
#define SETTING_USE_AA_FILTER 0
/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
#define SETTING_AA_FILTER_LENGTH 1
/// Enable/disable quick seeking algorithm in tempo changer routine
/// (enabling quick seeking lowers CPU utilization but causes a minor sound
/// quality compromising)
#define SETTING_USE_QUICKSEEK 2
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
/// to how long sequences the original sound is chopped in the time-stretch algorithm.
/// See "STTypes.h" or README for more information.
#define SETTING_SEQUENCE_MS 3
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
/// best possible overlapping location. This determines from how wide window the algorithm
/// may look for an optimal joining location when mixing the sound sequences back together.
/// See "STTypes.h" or README for more information.
#define SETTING_SEEKWINDOW_MS 4
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
/// are mixed back together, to form a continuous sound stream, this parameter defines over
/// how long period the two consecutive sequences are let to overlap each other.
/// See "STTypes.h" or README for more information.
#define SETTING_OVERLAP_MS 5
/// Call "getSetting" with this ID to query processing sequence size in samples.
/// This value gives approximate value of how many input samples you'll need to
/// feed into SoundTouch after initial buffering to get out a new batch of
/// output samples.
///
/// This value does not include initial buffering at beginning of a new processing
/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size.
///
/// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_INPUT_SEQUENCE 6
/// Call "getSetting" with this ID to query nominal average processing output
/// size in samples. This value tells approcimate value how many output samples
/// SoundTouch outputs once it does DSP processing run for a batch of input samples.
///
/// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings.
#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7
/// Call "getSetting" with this ID to query initial processing latency, i.e.
/// approx. how many samples you'll need to enter to SoundTouch pipeline before
/// you can expect to get first batch of ready output samples out.
///
/// After the first output batch, you can then expect to get approx.
/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every
/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch.
///
/// Example:
/// processing with parameter -tempo=5
/// => initial latency = 5509 samples
/// input sequence = 4167 samples
/// output sequence = 3969 samples
///
/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of
/// the stream, and then you'll get out the first 3969 samples. After that, for
/// every approx. 4167 samples that you'll put in, you'll receive again approx.
/// 3969 samples out.
///
/// This also means that average latency during stream processing is
/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2
/// = 3524 samples
///
/// Notices:
/// - This is read-only parameter, i.e. setSetting ignores this parameter
/// - This parameter value is not constant but change depending on
/// tempo/pitch/rate/samplerate settings.
#define SETTING_INITIAL_LATENCY 8
class SoundTouch : public FIFOProcessor
{
private:
/// Rate transposer class instance
class RateTransposer *pRateTransposer;
/// Time-stretch class instance
class TDStretch *pTDStretch;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
double virtualRate;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
double virtualTempo;
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
double virtualPitch;
/// Flag: Has sample rate been set?
bool bSrateSet;
/// Accumulator for how many samples in total will be expected as output vs. samples put in,
/// considering current processing settings.
double samplesExpectedOut;
/// Accumulator for how many samples in total have been read out from the processing so far
long samplesOutput;
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
/// 'virtualPitch' parameters.
void calcEffectiveRateAndTempo();
protected :
/// Number of channels
uint channels;
/// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
double rate;
/// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
double tempo;
public:
SoundTouch();
virtual ~SoundTouch() override;
/// Get SoundTouch library version string
static const char *getVersionString();
/// Get SoundTouch library version Id
static uint getVersionId();
/// Sets new rate control value. Normal rate = 1.0, smaller values
/// represent slower rate, larger faster rates.
void setRate(double newRate);
/// Sets new tempo control value. Normal tempo = 1.0, smaller values
/// represent slower tempo, larger faster tempo.
void setTempo(double newTempo);
/// Sets new rate control value as a difference in percents compared
/// to the original rate (-50 .. +100 %)
void setRateChange(double newRate);
/// Sets new tempo control value as a difference in percents compared
/// to the original tempo (-50 .. +100 %)
void setTempoChange(double newTempo);
/// Sets new pitch control value. Original pitch = 1.0, smaller values
/// represent lower pitches, larger values higher pitch.
void setPitch(double newPitch);
/// Sets pitch change in octaves compared to the original pitch
/// (-1.00 .. +1.00)
void setPitchOctaves(double newPitch);
/// Sets pitch change in semi-tones compared to the original pitch
/// (-12 .. +12)
void setPitchSemiTones(int newPitch);
void setPitchSemiTones(double newPitch);
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(uint numChannels);
/// Sets sample rate.
void setSampleRate(uint srate);
/// Get ratio between input and output audio durations, useful for calculating
/// processed output duration: if you'll process a stream of N samples, then
/// you can expect to get out N * getInputOutputSampleRatio() samples.
///
/// This ratio will give accurate target duration ratio for a full audio track,
/// given that the the whole track is processed with same processing parameters.
///
/// If this ratio is applied to calculate intermediate offsets inside a processing
/// stream, then this ratio is approximate and can deviate +- some tens of milliseconds
/// from ideal offset, yet by end of the audio stream the duration ratio will become
/// exact.
///
/// Example: if processing with parameters "-tempo=15 -pitch=-3", the function
/// will return value 0.8695652... Now, if processing an audio stream whose duration
/// is exactly one million audio samples, then you can expect the processed
/// output duration be 0.869565 * 1000000 = 869565 samples.
double getInputOutputSampleRatio();
/// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers.
//
/// Note: This function is meant for extracting the last samples of a sound
/// stream. This function may introduce additional blank samples in the end
/// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream.
void flush();
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception.
virtual void putSamples(
const SAMPLETYPE *samples, ///< Pointer to sample buffer.
uint numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample
///< contains data for both channels.
) override;
/// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than
/// 'numsample' samples in the buffer, returns all that available.
///
/// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max.
) override;
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere.
///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) override;
/// Clears all the samples in the object's output and internal processing
/// buffers.
virtual void clear() override;
/// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
///
/// \return 'true' if the setting was successfully changed
bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
int value ///< New setting value.
);
/// Reads a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's.
///
/// \return the setting value.
int getSetting(int settingId ///< Setting ID number, see SETTING_... defines.
) const;
/// Returns number of samples currently unprocessed.
virtual uint numUnprocessedSamples() const;
/// Return number of channels
uint numChannels() const
{
return channels;
}
/// Other handy functions that are implemented in the ancestor classes (see
/// classes 'FIFOProcessor' and 'FIFOSamplePipe')
///
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
/// - numSamples() : Get number of 'ready' samples that can be received with
/// function 'receiveSamples()'
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
/// - clear() : Clears all samples from ready/processing buffers.
};
}
#endif

View File

@ -0,0 +1,3 @@
// autotools configuration step replaces this file with a configured version.
// this empty file stub is provided to avoid error about missing include file
// when not using autotools build

View File

@ -0,0 +1,8 @@
/* Use Float as Sample type */
#undef SOUNDTOUCH_FLOAT_SAMPLES
/* Use Integer as Sample type */
#undef SOUNDTOUCH_INTEGER_SAMPLES
/* Use ARM NEON extension */
#undef SOUNDTOUCH_USE_NEON

View File

@ -5,42 +5,21 @@
@REM "vcvars32.bat" in VC install directotry before running this one.
@REM
@REM Copyright (c) Olli Parviainen
@REM File Created: 09/Sep/2003
@REM
@REM $Id$
@rem ****************************
@rem try first for VS6.0 support
@if "%MsDevDir%"=="" goto nomsdevdir
md bin
md lib
msdev source\SoundTouch\SoundTouch.dsw /MAKE ALL
msdev source\SoundStretch\SoundStretch.dsw /MAKE ALL
goto end
:nomsdevdir
@rem **********************************
@rem try with devenv for VS2003 support
@if "%DevEnvDir%"=="" goto nodevdir
md bin
md lib
devenv source\SoundTouch\SoundTouch.vcproj /upgrade
devenv source\SoundTouch\SoundTouch.vcproj /build debug
devenv source\SoundTouch\SoundTouch.vcproj /build release
@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"
devenv source\SoundStretch\SoundStretch.vcproj /upgrade
devenv source\SoundStretch\SoundStretch.vcproj /build debug
devenv source\SoundStretch\SoundStretch.vcproj /build release
devenv source\SoundTouchDll\SoundTouchDll.vcproj /upgrade
devenv source\SoundTouchDll\SoundTouchDll.vcproj /build debug
devenv source\SoundTouchDll\SoundTouchDll.vcproj /build release
@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
@ -48,14 +27,15 @@ devenv source\SoundTouchDll\SoundTouchDll.vcproj /build release
:nodevdir
@echo off
echo *********************************************************************
echo ****************************************************************************
echo **
echo ** ERROR: Visual Studio path not set.
echo **
echo ** Run "vsvars32.bat" or "vcvars32.bat" from Visual Studio installation
echo ** directory, e.g. "\Program Files\Microsoft Visual Studio\VC98\Bin",
echo ** Open "tools"->"Developer Command Line" from Visual Studio IDE, or
echo ** run "vcvars32.bat" from Visual Studio installation dir, e.g.
echo ** "C:\Program Files (x86)\Microsoft Visual Studio xxx\VC\bin",
echo ** then try again.
echo **
echo *********************************************************************
echo ****************************************************************************
:end

66
readme.md Normal file
View File

@ -0,0 +1,66 @@
# SoundTouch library
## About
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](https://www.surina.net/soundtouch/readme.html) for more information and audio examples.
### The latest stable release is 2.3.3
## 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](http://soundtouch.surina.net/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.
## Tarballs
Source code release tarballs:
* https://www.surina.net/soundtouch/soundtouch-2.3.3.tar.gz
* https://www.surina.net/soundtouch/soundtouch-2.3.2.tar.gz
* https://www.surina.net/soundtouch/soundtouch-2.3.1.tar.gz
* https://www.surina.net/soundtouch/soundtouch-2.3.0.tar.gz
* https://www.surina.net/soundtouch/soundtouch-2.2.0.tar.gz
* https://www.surina.net/soundtouch/soundtouch-2.1.2.tar.gz
* https://www.surina.net/soundtouch/soundtouch-2.1.1.tar.gz
* https://www.surina.net/soundtouch/soundtouch-2.0.0.tar.gz
## 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

View File

@ -1,14 +0,0 @@
# This file is obsoleted but provided for backwards compatibility
# with legacy package environments
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

View File

@ -1,7 +1,4 @@
# m4 configure test script for the SoundTouch library
# (c)2003 David W. Durham
#
# $Id$
#
# This file can be included with other packages that need to test
# for libSoundTouch.
@ -11,7 +8,7 @@
# 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
# A user of libSoundTouch should add @SOUNDTOUCH_LIBS@ and
# @SOUNDTOUCH_CXXFLAGS@ to the appropriate variables in his
# Makefile.am files
#
@ -35,10 +32,10 @@ AC_DEFUN([AM_PATH_SOUNDTOUCH],[
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],[
@ -52,7 +49,7 @@ AC_DEFUN([AM_PATH_SOUNDTOUCH],[
dnl run action-if-found
ifelse([$2], , :, [$2])
],[
],[
dnl run action-if-not-found
ifelse([$3], , :, [$3])
])

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,128 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>SoundTouch in Android</title>
<meta http-equiv="Content-Type"
content="text/html; charset=windows-1252">
<meta http-equiv="Content-Language" content="en-us">
<meta name="author" content="Olli Parviainen">
<meta name="description"
content="Readme file for SoundTouch library Android compilation">
<style> <!-- .normal { font-family: Arial }
--></style>
</head>
<body class="normal">
<hr>
<h1>SoundTouch in Android</h1>
<hr>
<h2>Compiling SoundTouch for Android</h2>
<p>SoundTouch source code package contains &quot;Android-lib&quot; example project that compiles SoundTouch
source codes into Android native library, and gives an example of JNI interface
for invoking
the native SoundTouch routines from an Android application written in Java.</p>
<p style="font-weight: 700">Software prerequisites:</p>
<ul>
<li>Android SDK environment for developing your own Android application. Visit the <a href="http://developer.android.com/index.html">Android developers' site</a>
for more information about the Android SDK and developing Android applications.</li>
<li>Android NDK compiler kit for compiling native library binaries. The Android NDK
is <a href="http://developer.android.com/tools/sdk/ndk/index.html">
available for download</a> at the Android developer tools site.</li>
<li>In case you're working in Windows environment, install
<a href="http://cygwin.com/install.html">
Cygwin</a> to run the Android NDK/SDK compiler scripts</li>
<li>Latest SoundTouch source code package available at <a href="http://soundtouch.surina.net/sourcecode.html">
soundtouch.surina.net</a>.</li>
</ul>
<p><b>Hint: </b>As installing and configuring all the components for an Android SDK/NDK
environment requires fair effort, it&#39;s good idea to create a dedicated Virtual
Machine environment for the Android development environment installation.
Having the Android developer environment setup in dedicated Virtual Machine
allows keeping all these settings isolated from your other PC operations, and
eases taking backup snapshots of your full development environment.</p>
<p><b>Compiling</b></p>
<p>
To compile the SoundTouch library source codes into an Android native library,
open Cygwin/bash shell, go to directory <b>&quot;soundtouch/source/Android-lib/jni&quot;</b> and invoke the NDK
compiler with following command:</p>
<pre> $NDK/ndk-build</pre>
<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>
<p>Notice that to allow Cygwin/bash to locate the NDK compile scripts, you
need to define the location of the NDK installation defined in environment
variable &quot;NDK&quot;. That's easiest done by adding the NDK path definition at end of
your <b>~/.bash_profile</b> file, for instance as follows:</p>
<pre> NDK=/cygdrive/d/Android/android-ndk-r6</pre>
<p><b>Enabling OpenMP parallel computing mode</b></p>
<p>
SoundTouch supports OpenMP for parallel computing in multi-core
environments, and these improvements can be enabled also in the Android
build. See the SoundTouch main README.html file for generic notes about the
OpenMP implementation.</p>
<p>
To enable OpenMP mode in Android compilation, edit file <strong>Android.mk</strong>
and enable the &quot;-fopenmp&quot; flag in LOCAL_CFLAGS and LOCAL_LDFLAGS variables.
This is done by removing hash # from before the following lines in the
Android.mk file, before compiling the library:</p>
<pre> LOCAL_CFLAGS += -fopenmp
LOCAL_LDFLAGS += -fopenmp</pre>
<p><strong>OpenMP COMPATIBILITY NOTE: </strong>Android NDK has a threading issue
(at least until NDK v10) that causes the native library crash with fatal signal
11 if calling OpenMP-improved routines from a background thread. SoundTouch has
a workaround for this issue in soundtouch-jni.cpp, and this workaround requires
calling function <strong>SoundTouch.getVersionString() </strong>from the Android
application's main thread at least once before calling other SoundTouch
processing routines. See the SoundTouch Android example application and comments
in the <strong>soundtouch-jni.cpp </strong>source code file for more details.</p>
<p>
<strong>SoundTouch performance in Android</strong></p>
<p>
See external blog articles for more discussion about the
<a href="http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices/">
SoundTouch OpenMP implementation</a> and the
<a href="http://www.softwarecoven.com/parallel-computing-with-openmp-in-android/">
SoundTouch performance benchmark tests in Android environment</a>.</p>
<hr />
<h2>
Calling SoundTouch native routines from Android application</h2>
<p>The NDK tools build the SoundTouch c++ routines into a native binary library, while
Android applications are written in Java language. To call the SoundTouch and other c/c++
routines from an Android java application code, you'll need to use Java Native
Interface (JNI).</p>
<p>
The SoundTouch source code package provides source code example how to
use JNI to call native c++ routines from a Java class, and provides source codes also for
a simple example Android application:<ul>
<li><b>ExampleActivity</b>: This is simple Android example application that
utilizes SoundTouch native routines for processing WAV audio files. To build the example
application, use Eclipse Android SDK environment to import the "ExampleActivity" project in the "Android-lib" folder into the Eclipse workspace.
<li><b>Android-lib/jni/soundtouch-jni.cpp</b>: This file contains c/c++ wrapper routines
for performing elementary audio file processing with adjusted tempo/pitch/speed parameters
from the Android application. The wrapper interface is not complete, but provides example
that is easy to extend when necessary. The NDK compiles this file along with the SoundTouch
routines into the native binary library.</li>
<li><b>Android-lib/src/net/surina/soundtouch/SoundTouch.java</b>: This file implements
the Java interface class that loasd & accesses the JNI routines in the natively compiled library.
The example Android application uses this class as interface for processing audio files
with SoundTouch.</li>
<li><b>Android-lib/build.gradle</b>: Top level build script file for Android Studio 3.1.4+</li>
</ul>
<p>
Feel free to examine and extend the provided cpp/java source code example file pair to
implement and integrate the desired SoundTouch library capabilities into your own Android application.</p>
<hr />
<h2>
Android floating-point performance considerations</h2>
<p>
The make process will build dedicated binaries for each supported Android CPU hardware platform type.
</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
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>
As floating point software-emulation is however several tens of times slower
than real hardware-level floating-point calculations, that would make running
floating-point-intensive applications such as SoundTouch infeasible in these low-end
devices. As workaround, the SoundTouch Android compilation builds the ARMv5 version using integer algorithm versions. The integer
algorithm version compromises the sound quality but provides good performance also
with low-end devices without hardware floating-point support in the CPU level.</p>
<p>When Android devices with more capable device is used, the device will automatically choose a proper library version for ideal sound quality.</p>
<hr />
<p style="text-align: center"><i>Copyright &copy; Olli Parviainen</i></p>
</body>
</html>

View File

@ -0,0 +1,55 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "net.surina.soundtouchexample"
minSdkVersion 14
targetSdkVersion 21
externalNativeBuild.ndkBuild {
arguments "NDK_APPLICATION=jni/Application.mk",
"APP_ALLOW_MISSING_DEPS:=true"
}
}
sourceSets {
main {
manifest.srcFile "./AndroidManifest.xml"
java.srcDirs = ["./src"]
res.srcDirs = ["res"]
}
}
externalNativeBuild {
ndkBuild {
path 'jni/Android.mk'
}
}
buildTypes {
release {
minifyEnabled false
}
}
}

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Sat Jan 13 09:12:34 PST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip

172
source/Android-lib/gradlew vendored Executable file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
source/Android-lib/gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1,37 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../include $(LOCAL_PATH)/../../SoundStretch
# *** 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 -fdata-sections -ffunction-sections -ffast-math
# 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)

View File

@ -0,0 +1,9 @@
#
# Build library bilaries for all supported architectures
#
APP_ABI := all #armeabi-v7a armeabi
APP_OPTIM := release
APP_STL := c++_static
APP_CPPFLAGS := -fexceptions # -D SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS

View File

@ -0,0 +1,258 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Example Interface class for SoundTouch native compilation
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// WWW : http://www.surina.net
///
////////////////////////////////////////////////////////////////////////////////
#include <jni.h>
#include <android/log.h>
#include <stdexcept>
#include <string>
using namespace std;
#include "../../../include/SoundTouch.h"
#include "../source/SoundStretch/WavFile.h"
#define LOGV(...) __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
//#define LOGV(...)
// String for keeping possible c++ exception error messages. Notice that this isn't
// thread-safe but it's expected that exceptions are special situations that won't
// occur in several threads in parallel.
static string _errMsg = "";
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
#define BUFF_SIZE 4096
using namespace soundtouch;
// Set error message to return
static void _setErrmsg(const char *msg)
{
_errMsg = msg;
}
#if 0 // apparently following workaround not needed any more with concurrent Android SDKs
#ifdef _OPENMP
#include <pthread.h>
extern pthread_key_t gomp_tls_key;
static void * _p_gomp_tls = nullptr;
/// Function to initialize threading for OpenMP.
///
/// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if
/// called from the Android App main thread because in the main thread the gomp_tls storage is
/// properly set, however, Android does not properly initialize gomp_tls storage for other threads.
/// Thus if OpenMP routines are invoked from some other thread than the main thread,
/// the OpenMP routine will crash the application due to nullptr access on uninitialized storage.
///
/// This workaround stores the gomp_tls storage from main thread, and copies to other threads.
/// In order this to work, the Application main thread needws to call at least "getVersionString"
/// routine.
static int _init_threading(bool warn)
{
void *ptr = pthread_getspecific(gomp_tls_key);
LOGV("JNI thread-specific TLS storage %ld", (long)ptr);
if (ptr == nullptr)
{
LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);
pthread_setspecific(gomp_tls_key, _p_gomp_tls);
}
else
{
LOGV("JNI store this TLS storage");
_p_gomp_tls = ptr;
}
// Where critical, show warning if storage still not properly initialized
if ((warn) && (_p_gomp_tls == nullptr))
{
_setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");
return -1;
}
return 0;
}
#else
static int _init_threading(bool warn)
{
// do nothing if not OpenMP build
return 0;
}
#endif
#endif
// Processes the sound file
static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
{
int nSamples;
int nChannels;
int buffSizeSamples;
SAMPLETYPE sampleBuffer[BUFF_SIZE];
// open input file
WavInFile inFile(inFileName);
int sampleRate = inFile.getSampleRate();
int bits = inFile.getNumBits();
nChannels = inFile.getNumChannels();
// create output file
WavOutFile outFile(outFileName, sampleRate, bits, nChannels);
pSoundTouch->setSampleRate(sampleRate);
pSoundTouch->setChannels(nChannels);
assert(nChannels > 0);
buffSizeSamples = BUFF_SIZE / nChannels;
// Process samples read from the input file
while (inFile.eof() == 0)
{
int num;
// Read a chunk of samples from the input file
num = inFile.read(sampleBuffer, BUFF_SIZE);
nSamples = num / nChannels;
// Feed the samples into SoundTouch processor
pSoundTouch->putSamples(sampleBuffer, nSamples);
// Read ready samples from SoundTouch processor & write them output file.
// NOTES:
// - 'receiveSamples' doesn't necessarily return any samples at all
// during some rounds!
// - On the other hand, during some round 'receiveSamples' may have more
// ready samples than would fit into 'sampleBuffer', and for this reason
// the 'receiveSamples' call is iterated for as many times as it
// outputs samples.
do
{
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0);
}
// Now the input file is processed, yet 'flush' few last samples that are
// hiding in the SoundTouch's internal processing pipeline.
pSoundTouch->flush();
do
{
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0);
}
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
{
const char *verStr;
LOGV("JNI call SoundTouch.getVersionString");
// Call example SoundTouch routine
verStr = SoundTouch::getVersionString();
// gomp_tls storage bug workaround - see comments in _init_threading() function!
// update: apparently this is not needed any more with concurrent Android SDKs
// _init_threading(false);
int threads = 0;
#pragma omp parallel
{
#pragma omp atomic
threads ++;
}
LOGV("JNI thread count %d", threads);
// return version as string
return env->NewStringUTF(verStr);
}
extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
{
return (jlong)(new SoundTouch());
}
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
{
SoundTouch *ptr = (SoundTouch*)handle;
delete ptr;
}
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
{
SoundTouch *ptr = (SoundTouch*)handle;
ptr->setTempo(tempo);
}
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
{
SoundTouch *ptr = (SoundTouch*)handle;
ptr->setPitchSemiTones(pitch);
}
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
{
SoundTouch *ptr = (SoundTouch*)handle;
ptr->setRate(speed);
}
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
{
jstring result = env->NewStringUTF(_errMsg.c_str());
_errMsg.clear();
return result;
}
extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
{
SoundTouch *ptr = (SoundTouch*)handle;
const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
const char *outputFile = env->GetStringUTFChars(joutputFile, 0);
LOGV("JNI process file %s", inputFile);
/// gomp_tls storage bug workaround - see comments in _init_threading() function!
// update: apparently this is not needed any more with concurrent Android SDKs
// if (_init_threading(true)) return -1;
try
{
_processFile(ptr, inputFile, outputFile);
}
catch (const runtime_error &e)
{
const char *err = e.what();
// An exception occurred during processing, return the error message
LOGV("JNI exception in SoundTouch::processFile: %s", err);
_setErrmsg(err);
return -1;
}
env->ReleaseStringUTFChars(jinputFile, inputFile);
env->ReleaseStringUTFChars(joutputFile, outputFile);
return 0;
}

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<lint>
</lint>

View File

@ -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 *;
#}

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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();
}
}
}

View File

@ -0,0 +1,79 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Example class that invokes native SoundTouch routines through the JNI
/// interface.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// WWW : http://www.surina.net
///
////////////////////////////////////////////////////////////////////////////////
package net.surina.soundtouch;
public final class SoundTouch
{
// Native interface function that returns SoundTouch version string.
// This invokes the native c++ routine defined in "soundtouch-jni.cpp".
public native final static String getVersionString();
private native final void setTempo(long handle, float tempo);
private native final void setPitchSemiTones(long handle, float pitch);
private native final void setSpeed(long handle, float speed);
private native final int processFile(long handle, String inputFile, String outputFile);
public native final static String getErrorString();
private native final static long newInstance();
private native final void deleteInstance(long handle);
long handle = 0;
public SoundTouch()
{
handle = newInstance();
}
public void close()
{
deleteInstance(handle);
handle = 0;
}
public void setTempo(float tempo)
{
setTempo(handle, tempo);
}
public void setPitchSemiTones(float pitch)
{
setPitchSemiTones(handle, pitch);
}
public void setSpeed(float speed)
{
setSpeed(handle, speed);
}
public int processFile(String inputFile, String outputFile)
{
return processFile(handle, inputFile, outputFile);
}
// Load the native library upon startup
static
{
System.loadLibrary("soundtouch");
}
}

View File

@ -1,28 +1,25 @@
## Process this file with automake to create Makefile.in
##
## $Id$
##
## Copyright (C) 2003 - David W. Durham
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk
SUBDIRS=SoundTouch SoundStretch
# set to something if you want other stuff to be included in the distribution tarball
#EXTRA_DIST=
## Process this file with automake to create Makefile.in
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk
if SOUNDTOUCH_FLOAT_SAMPLES
# build SoundTouchDLL only if float samples used
SUBDIRS=SoundTouch SoundStretch SoundTouchDLL
else
SUBDIRS=SoundTouch SoundStretch
endif

View File

@ -1,54 +1,50 @@
## Process this file with automake to create Makefile.in
##
## $Id$
##
## Copyright (C) 2003 - David W. Durham
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk
## bin_PROGRAMS is the macro that tells automake the name of the programs to
## install in the bin directory (/usr/local/bin) by default. By setting
## --prefix= at configure time the user can change this (eg: ./configure
## --prefix=/usr will install soundstretch under /usr/bin/soundstretch )
bin_PROGRAMS=soundstretch
noinst_HEADERS=RunParameters.h WavFile.h
# extra files to include in distrubution tarball
EXTRA_DIST=soundstretch.dsp soundstretch.dsw soundstretch.sln soundstretch.vcproj
## for every name listed under bin_PROGRAMS, you have a <prog>_SOURCES. This lists
## all the sources in the current directory that are used to build soundstretch.
soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp
## soundstretch_LDADD is a list of extras to pass at link time. All the objects
## created by the above soundstretch_SOURCES are automatically linked in, so here I
## list object files from other directories as well as flags passed to the
## linker.
soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm
## linker flags.
# OP 2011-7-17 Linker flags disabled to prevent stripping symbols by default
# soundstretch_LDFLAGS=-s
## additional compiler flags
soundstretch_CXXFLAGS=-O3
#clean-local:
# -rm -f additional-files-to-remove-on-make-clean
## Process this file with automake to create Makefile.in
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk
## bin_PROGRAMS is the macro that tells automake the name of the programs to
## install in the bin directory (/usr/local/bin) by default. By setting
## --prefix= at configure time the user can change this (eg: ./configure
## --prefix=/usr will install soundstretch under /usr/bin/soundstretch )
bin_PROGRAMS=soundstretch
noinst_HEADERS=RunParameters.h WavFile.h
# extra files to include in distribution tarball
EXTRA_DIST=soundstretch.sln soundstretch.vcxproj
## for every name listed under bin_PROGRAMS, you have a <prog>_SOURCES. This lists
## all the sources in the current directory that are used to build soundstretch.
soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp
## soundstretch_LDADD is a list of extras to pass at link time. All the objects
## created by the above soundstretch_SOURCES are automatically linked in, so here I
## list object files from other directories as well as flags passed to the
## linker.
soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm
## linker flags.
# Linker flag -s disabled to prevent stripping symbols by default
#soundstretch_LDFLAGS=-s
## additional compiler flags
soundstretch_CXXFLAGS=$(AM_CXXFLAGS)
#clean-local:
# -rm -f additional-files-to-remove-on-make-clean

View File

@ -1,301 +1,292 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A class for parsing the 'soundstretch' application command line parameters
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include <stdlib.h>
#include "RunParameters.h"
using namespace std;
// Program usage instructions
static const char licenseText[] =
" LICENSE:\n"
" ========\n"
" \n"
" SoundTouch sound processing library\n"
" Copyright (c) Olli Parviainen\n"
" \n"
" This library is free software; you can redistribute it and/or\n"
" modify it under the terms of the GNU Lesser General Public\n"
" License version 2.1 as published by the Free Software Foundation.\n"
" \n"
" This library is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
" Lesser General Public License for more details.\n"
" \n"
" You should have received a copy of the GNU Lesser General Public\n"
" License along with this library; if not, write to the Free Software\n"
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
" \n"
"This application is distributed with full source codes; however, if you\n"
"didn't receive them, please visit the author's homepage (see the link above).";
static const char whatText[] =
"This application processes WAV audio files by modifying the sound tempo,\n"
"pitch and playback rate properties independently from each other.\n"
"\n";
static const char usage[] =
"Usage :\n"
" soundstretch infilename outfilename [switches]\n"
"\n"
"To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"
"\n"
"Available switches are:\n"
" -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n"
" -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"
" -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n"
" -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n"
" If '=n' is omitted, just detects the BPM rate.\n"
" -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n"
" -naa : Don't use anti-alias filtering (gain speed, lose quality)\n"
" -speech : Tune algorithm for speech processing (default is for music)\n"
" -license : Display the program license text (LGPL)\n";
// Converts a char into lower case
static int _toLowerCase(int c)
{
if (c >= 'A' && c <= 'Z')
{
c += 'a' - 'A';
}
return c;
}
// Constructor
RunParameters::RunParameters(const int nParams, const char * const paramStr[])
{
int i;
int nFirstParam;
if (nParams < 3)
{
// Too few parameters
if (nParams > 1 && paramStr[1][0] == '-' &&
_toLowerCase(paramStr[1][1]) == 'l')
{
// '-license' switch
throwLicense();
}
string msg = whatText;
msg += usage;
ST_THROW_RT_ERROR(msg.c_str());
}
inFileName = NULL;
outFileName = NULL;
tempoDelta = 0;
pitchDelta = 0;
rateDelta = 0;
quick = 0;
noAntiAlias = 0;
goalBPM = 0;
speech = FALSE;
detectBPM = FALSE;
// Get input & output file names
inFileName = (char*)paramStr[1];
outFileName = (char*)paramStr[2];
if (outFileName[0] == '-')
{
// no outputfile name was given but parameters
outFileName = NULL;
nFirstParam = 2;
}
else
{
nFirstParam = 3;
}
// parse switch parameters
for (i = nFirstParam; i < nParams; i ++)
{
parseSwitchParam(paramStr[i]);
}
checkLimits();
}
// Checks parameter limits
void RunParameters::checkLimits()
{
if (tempoDelta < -95.0f)
{
tempoDelta = -95.0f;
}
else if (tempoDelta > 5000.0f)
{
tempoDelta = 5000.0f;
}
if (pitchDelta < -60.0f)
{
pitchDelta = -60.0f;
}
else if (pitchDelta > 60.0f)
{
pitchDelta = 60.0f;
}
if (rateDelta < -95.0f)
{
rateDelta = -95.0f;
}
else if (rateDelta > 5000.0f)
{
rateDelta = 5000.0f;
}
}
// Unknown switch parameter -- throws an exception with an error message
void RunParameters::throwIllegalParamExp(const string &str) const
{
string msg = "ERROR : Illegal parameter \"";
msg += str;
msg += "\".\n\n";
msg += usage;
ST_THROW_RT_ERROR(msg.c_str());
}
void RunParameters::throwLicense() const
{
ST_THROW_RT_ERROR(licenseText);
}
float RunParameters::parseSwitchValue(const string &str) const
{
int pos;
pos = (int)str.find_first_of('=');
if (pos < 0)
{
// '=' missing
throwIllegalParamExp(str);
}
// Read numerical parameter value after '='
return (float)atof(str.substr(pos + 1).c_str());
}
// Interprets a single switch parameter string of format "-switch=xx"
// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
// switch values into 'params' structure.
void RunParameters::parseSwitchParam(const string &str)
{
int upS;
if (str[0] != '-')
{
// leading hyphen missing => not a valid parameter
throwIllegalParamExp(str);
}
// Take the first character of switch name & change to lower case
upS = _toLowerCase(str[1]);
// interpret the switch name & operate accordingly
switch (upS)
{
case 't' :
// switch '-tempo=xx'
tempoDelta = parseSwitchValue(str);
break;
case 'p' :
// switch '-pitch=xx'
pitchDelta = parseSwitchValue(str);
break;
case 'r' :
// switch '-rate=xx'
rateDelta = parseSwitchValue(str);
break;
case 'b' :
// switch '-bpm=xx'
detectBPM = TRUE;
try
{
goalBPM = parseSwitchValue(str);
}
catch (const runtime_error)
{
// illegal or missing bpm value => just calculate bpm
goalBPM = 0;
}
break;
case 'q' :
// switch '-quick'
quick = 1;
break;
case 'n' :
// switch '-naa'
noAntiAlias = 1;
break;
case 'l' :
// switch '-license'
throwLicense();
break;
case 's' :
// switch '-speech'
speech = TRUE;
break;
default:
// unknown switch
throwIllegalParamExp(str);
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// A class for parsing the 'soundstretch' application command line parameters
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include <cstdlib>
#include "RunParameters.h"
using namespace std;
namespace soundstretch
{
// Program usage instructions
static const char licenseText[] =
" LICENSE:\n"
" ========\n"
" \n"
" SoundTouch sound processing library\n"
" Copyright (c) Olli Parviainen\n"
" \n"
" This library is free software; you can redistribute it and/or\n"
" modify it under the terms of the GNU Lesser General Public\n"
" License version 2.1 as published by the Free Software Foundation.\n"
" \n"
" This library is distributed in the hope that it will be useful,\n"
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
" Lesser General Public License for more details.\n"
" \n"
" You should have received a copy of the GNU Lesser General Public\n"
" License along with this library; if not, write to the Free Software\n"
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
" \n"
"This application is distributed with full source codes; however, if you\n"
"didn't receive them, please visit the author's homepage (see the link above).";
static const char whatText[] =
"This application processes WAV audio files by modifying the sound tempo,\n"
"pitch and playback rate properties independently from each other.\n"
"\n";
static const char usage[] =
"Usage :\n"
" soundstretch infilename outfilename [switches]\n"
"\n"
"To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"
"\n"
"Available switches are:\n"
" -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n"
" -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"
" -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n"
" -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n"
" If '=n' is omitted, just detects the BPM rate.\n"
" -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n"
" -naa : Don't use anti-alias filtering (gain speed, lose quality)\n"
" -speech : Tune algorithm for speech processing (default is for music)\n"
" -license : Display the program license text (LGPL)\n";
// Converts a char into lower case
static int _toLowerCase(int c)
{
if (c >= 'A' && c <= 'Z')
{
c += 'a' - 'A';
}
return c;
}
// Constructor
RunParameters::RunParameters(int nParams, const CHARTYPE* paramStr[])
{
int i;
int nFirstParam;
if (nParams < 3)
{
// Too few parameters
if (nParams > 1 && paramStr[1][0] == '-' &&
_toLowerCase(paramStr[1][1]) == 'l')
{
// '-license' switch
throwLicense();
}
string msg = whatText;
msg += usage;
throw(msg);
}
// Get input & output file names
inFileName = paramStr[1];
outFileName = paramStr[2];
if (outFileName[0] == '-')
{
// outputfile name was omitted but other parameter switches given instead
outFileName = STRING_CONST("");
nFirstParam = 2;
}
else
{
nFirstParam = 3;
}
// parse switch parameters
for (i = nFirstParam; i < nParams; i ++)
{
parseSwitchParam(paramStr[i]);
}
checkLimits();
}
// Checks parameter limits
void RunParameters::checkLimits()
{
if (tempoDelta < -95.0f)
{
tempoDelta = -95.0f;
}
else if (tempoDelta > 5000.0f)
{
tempoDelta = 5000.0f;
}
if (pitchDelta < -60.0f)
{
pitchDelta = -60.0f;
}
else if (pitchDelta > 60.0f)
{
pitchDelta = 60.0f;
}
if (rateDelta < -95.0f)
{
rateDelta = -95.0f;
}
else if (rateDelta > 5000.0f)
{
rateDelta = 5000.0f;
}
}
// Convert STRING to std::string. Actually needed only if STRING is std::wstring, but conversion penalty is negligible
std::string convertString(const STRING& str)
{
std::string res;
for (auto c : str)
{
res += (char)c;
}
return res;
}
// Unknown switch parameter -- throws an exception with an error message
void RunParameters::throwIllegalParamExp(const STRING &str) const
{
string msg = "ERROR : Illegal parameter \"";
msg += convertString(str);
msg += "\".\n\n";
msg += usage;
ST_THROW_RT_ERROR(msg);
}
void RunParameters::throwLicense() const
{
ST_THROW_RT_ERROR(licenseText);
}
double RunParameters::parseSwitchValue(const STRING& str) const
{
int pos;
pos = (int)str.find_first_of('=');
if (pos < 0)
{
// '=' missing
throwIllegalParamExp(str);
}
// Read numerical parameter value after '='
return stof(str.substr(pos + 1).c_str());
}
// Interprets a single switch parameter string of format "-switch=xx"
// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
// switch values into 'params' structure.
void RunParameters::parseSwitchParam(const STRING& str)
{
int upS;
if (str[0] != '-')
{
// leading hyphen missing => not a valid parameter
throwIllegalParamExp(str);
}
// Take the first character of switch name & change to lower case
upS = _toLowerCase(str[1]);
// interpret the switch name & operate accordingly
switch (upS)
{
case 't' :
// switch '-tempo=xx'
tempoDelta = parseSwitchValue(str);
break;
case 'p' :
// switch '-pitch=xx'
pitchDelta = parseSwitchValue(str);
break;
case 'r' :
// switch '-rate=xx'
rateDelta = parseSwitchValue(str);
break;
case 'b' :
// switch '-bpm=xx'
detectBPM = true;
try
{
goalBPM = parseSwitchValue(str);
}
catch (const runtime_error &)
{
// illegal or missing bpm value => just calculate bpm
goalBPM = 0;
}
break;
case 'q' :
// switch '-quick'
quick = 1;
break;
case 'n' :
// switch '-naa'
noAntiAlias = 1;
break;
case 'l' :
// switch '-license'
throwLicense();
break;
case 's' :
// switch '-speech'
speech = true;
break;
default:
// unknown switch
throwIllegalParamExp(str);
}
}
}

View File

@ -1,72 +1,70 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A class for parsing the 'soundstretch' application command line parameters
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef RUNPARAMETERS_H
#define RUNPARAMETERS_H
#include "STTypes.h"
#include <string>
using namespace std;
/// Parses command line parameters into program parameters
class RunParameters
{
private:
void throwIllegalParamExp(const string &str) const;
void throwLicense() const;
void parseSwitchParam(const string &str);
void checkLimits();
float parseSwitchValue(const string &str) const;
public:
char *inFileName;
char *outFileName;
float tempoDelta;
float pitchDelta;
float rateDelta;
int quick;
int noAntiAlias;
float goalBPM;
BOOL detectBPM;
BOOL speech;
RunParameters(const int nParams, const char * const paramStr[]);
};
#endif
////////////////////////////////////////////////////////////////////////////////
///
/// A class for parsing the 'soundstretch' application command line parameters
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef RUNPARAMETERS_H
#define RUNPARAMETERS_H
#include <string>
#include "STTypes.h"
#include "SS_CharTypes.h"
#include "WavFile.h"
namespace soundstretch
{
/// Parses command line parameters into program parameters
class RunParameters
{
private:
void throwIllegalParamExp(const STRING& str) const;
void throwLicense() const;
void parseSwitchParam(const STRING& str);
void checkLimits();
double parseSwitchValue(const STRING& tr) const;
public:
STRING inFileName;
STRING outFileName;
double tempoDelta{ 0 };
double pitchDelta{ 0 };
double rateDelta{ 0 };
int quick{ 0 };
int noAntiAlias{ 0 };
double goalBPM{ 0 };
bool detectBPM{ false };
bool speech{ false };
RunParameters(int nParams, const CHARTYPE* paramStr[]);
};
}
#endif

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,276 +1,281 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Classes for easy reading & writing of WAV sound files.
///
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
/// parse the WAV files with such processors.
///
/// Admittingly, more complete WAV reader routines may exist in public domain, but
/// the reason for 'yet another' one is that those generic WAV reader libraries are
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
/// something that's not already larger than rest of the SoundTouch/SoundStretch program...
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef WAVFILE_H
#define WAVFILE_H
#include <stdio.h>
#ifndef uint
typedef unsigned int uint;
#endif
/// WAV audio file 'riff' section header
typedef struct
{
char riff_char[4];
int package_len;
char wave[4];
} WavRiff;
/// WAV audio file 'format' section header
typedef struct
{
char fmt[4];
int format_len;
short fixed;
short channel_number;
int sample_rate;
int byte_rate;
short byte_per_sample;
short bits_per_sample;
} WavFormat;
/// WAV audio file 'data' section header
typedef struct
{
char data_field[4];
uint data_len;
} WavData;
/// WAV audio file header
typedef struct
{
WavRiff riff;
WavFormat format;
WavData data;
} WavHeader;
/// Base class for processing WAV audio files.
class WavFileBase
{
private:
/// Conversion working buffer;
char *convBuff;
int convBuffSize;
protected:
WavFileBase();
virtual ~WavFileBase();
/// Get pointer to conversion buffer of at min. given size
void *getConvBuffer(int sizeByte);
};
/// Class for reading WAV audio files.
class WavInFile : protected WavFileBase
{
private:
/// File pointer.
FILE *fptr;
/// Position within the audio stream
long position;
/// Counter of how many bytes of sample data have been read from the file.
long dataRead;
/// WAV header information
WavHeader header;
/// Init the WAV file stream
void init();
/// Read WAV file headers.
/// \return zero if all ok, nonzero if file format is invalid.
int readWavHeaders();
/// Checks WAV file header tags.
/// \return zero if all ok, nonzero if file format is invalid.
int checkCharTags() const;
/// Reads a single WAV file header block.
/// \return zero if all ok, nonzero if file format is invalid.
int readHeaderBlock();
/// Reads WAV file 'riff' block
int readRIFFBlock();
public:
/// Constructor: Opens the given WAV file. If the file can't be opened,
/// throws 'runtime_error' exception.
WavInFile(const char *filename);
WavInFile(FILE *file);
/// Destructor: Closes the file.
~WavInFile();
/// Rewind to beginning of the file
void rewind();
/// Get sample rate.
uint getSampleRate() const;
/// Get number of bits per sample, i.e. 8 or 16.
uint getNumBits() const;
/// Get sample data size in bytes. Ahem, this should return same information as
/// 'getBytesPerSample'...
uint getDataSizeInBytes() const;
/// Get total number of samples in file.
uint getNumSamples() const;
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
uint getBytesPerSample() const;
/// Get number of audio channels in the file (1=mono, 2=stereo)
uint getNumChannels() const;
/// Get the audio file length in milliseconds
uint getLengthMS() const;
/// Returns how many milliseconds of audio have so far been read from the file
///
/// \return elapsed duration in milliseconds
uint getElapsedMS() const;
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
/// Reads given number of elements from the file or if end-of-file reached, as many
/// elements as are left in the file.
///
/// \return Number of 8-bit integers read from the file.
int read(unsigned char *buffer, int maxElems);
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
/// of elements from the file or if end-of-file reached, as many elements as are
/// left in the file.
///
/// \return Number of 16-bit integers read from the file.
int read(short *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements).
);
/// Reads audio samples from the WAV file to floating point format, converting
/// sample values to range [-1,1[. Reads given number of elements from the file
/// or if end-of-file reached, as many elements as are left in the file.
/// Notice that reading in float format supports 8/16/24/32bit sample formats.
///
/// \return Number of elements read from the file.
int read(float *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements).
);
/// Check end-of-file.
///
/// \return Nonzero if end-of-file reached.
int eof() const;
};
/// Class for writing WAV audio files.
class WavOutFile : protected WavFileBase
{
private:
/// Pointer to the WAV file
FILE *fptr;
/// WAV file header data.
WavHeader header;
/// Counter of how many bytes have been written to the file so far.
int bytesWritten;
/// Fills in WAV file header information.
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
/// Finishes the WAV file header by supplementing information of amount of
/// data written to file etc
void finishHeader();
/// Writes the WAV file header.
void writeHeader();
public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails.
WavOutFile(const char *fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo)
);
WavOutFile(FILE *file, int sampleRate, int bits, int channels);
/// Destructor: Finalizes & closes the WAV file.
~WavOutFile();
/// Write data to WAV file. This function works only with 8bit samples.
/// Throws a 'runtime_error' exception if writing to file fails.
void write(const unsigned char *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to
/// file fails.
void write(const short *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
/// Write data to WAV file in floating point format, saturating sample values to range
/// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails.
void write(const float *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
};
#endif
////////////////////////////////////////////////////////////////////////////////
///
/// Classes for easy reading & writing of WAV sound files.
///
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
/// parse the WAV files with such processors.
///
/// Admittingly, more complete WAV reader routines may exist in public domain, but
/// the reason for 'yet another' one is that those generic WAV reader libraries are
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
/// something that's not already larger than rest of the SoundTouch/SoundStretch program...
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef WAVFILE_H
#define WAVFILE_H
#include <cstdio>
#include <string>
#include "SS_CharTypes.h"
namespace soundstretch
{
#ifndef uint
typedef unsigned int uint;
#endif
/// WAV audio file 'riff' section header
typedef struct
{
char riff_char[4];
uint package_len;
char wave[4];
} WavRiff;
/// WAV audio file 'format' section header
typedef struct
{
char fmt[4];
unsigned int format_len;
unsigned short fixed;
unsigned short channel_number;
unsigned int sample_rate;
unsigned int byte_rate;
unsigned short byte_per_sample;
unsigned short bits_per_sample;
} WavFormat;
/// WAV audio file 'fact' section header
typedef struct
{
char fact_field[4];
uint fact_len;
uint fact_sample_len;
} WavFact;
/// WAV audio file 'data' section header
typedef struct
{
char data_field[4];
uint data_len;
} WavData;
/// WAV audio file header
typedef struct
{
WavRiff riff;
WavFormat format;
WavFact fact;
WavData data;
} WavHeader;
/// Base class for processing WAV audio files.
class WavFileBase
{
private:
/// Conversion working buffer;
char *convBuff;
int convBuffSize;
protected:
WavFileBase();
virtual ~WavFileBase();
/// Get pointer to conversion buffer of at min. given size
void *getConvBuffer(int sizeByte);
};
/// Class for reading WAV audio files.
class WavInFile : protected WavFileBase
{
private:
/// File pointer.
FILE *fptr;
/// Counter of how many bytes of sample data have been read from the file.
long dataRead;
/// WAV header information
WavHeader header;
/// Init the WAV file stream
void init();
/// Read WAV file headers.
/// \return zero if all ok, nonzero if file format is invalid.
int readWavHeaders();
/// Checks WAV file header tags.
/// \return zero if all ok, nonzero if file format is invalid.
int checkCharTags() const;
/// Reads a single WAV file header block.
/// \return zero if all ok, nonzero if file format is invalid.
int readHeaderBlock();
/// Reads WAV file 'riff' block
int readRIFFBlock();
public:
/// Constructor: Opens the given WAV file. If the file can't be opened,
/// throws 'runtime_error' exception.
WavInFile(const STRING& filename);
WavInFile(FILE *file);
/// Destructor: Closes the file.
~WavInFile();
/// Rewind to beginning of the file
void rewind();
/// Get sample rate.
uint getSampleRate() const;
/// Get number of bits per sample, i.e. 8 or 16.
uint getNumBits() const;
/// Get sample data size in bytes. Ahem, this should return same information as
/// 'getBytesPerSample'...
uint getDataSizeInBytes() const;
/// Get total number of samples in file.
uint getNumSamples() const;
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
uint getBytesPerSample() const;
/// Get number of audio channels in the file (1=mono, 2=stereo)
uint getNumChannels() const;
/// Get the audio file length in milliseconds
uint getLengthMS() const;
/// Returns how many milliseconds of audio have so far been read from the file
///
/// \return elapsed duration in milliseconds
uint getElapsedMS() const;
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
/// Reads given number of elements from the file or if end-of-file reached, as many
/// elements as are left in the file.
///
/// \return Number of 8-bit integers read from the file.
int read(unsigned char *buffer, int maxElems);
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
/// of elements from the file or if end-of-file reached, as many elements as are
/// left in the file.
///
/// \return Number of 16-bit integers read from the file.
int read(short *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements).
);
/// Reads audio samples from the WAV file to floating point format, converting
/// sample values to range [-1,1[. Reads given number of elements from the file
/// or if end-of-file reached, as many elements as are left in the file.
/// Notice that reading in float format supports 8/16/24/32bit sample formats.
///
/// \return Number of elements read from the file.
int read(float *buffer, ///< Pointer to buffer where to read data.
int maxElems ///< Size of 'buffer' array (number of array elements).
);
/// Check end-of-file.
///
/// \return Nonzero if end-of-file reached.
int eof() const;
};
/// Class for writing WAV audio files.
class WavOutFile : protected WavFileBase
{
private:
/// Pointer to the WAV file
FILE *fptr;
/// WAV file header data.
WavHeader header;
/// Counter of how many bytes have been written to the file so far.
int bytesWritten;
/// Fills in WAV file header information.
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
/// Finishes the WAV file header by supplementing information of amount of
/// data written to file etc
void finishHeader();
/// Writes the WAV file header.
void writeHeader();
public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails.
WavOutFile(const STRING& fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo)
);
WavOutFile(FILE *file, int sampleRate, int bits, int channels);
/// Destructor: Finalizes & closes the WAV file.
~WavOutFile();
/// Write data to WAV file. This function works only with 8bit samples.
/// Throws a 'runtime_error' exception if writing to file fails.
void write(const unsigned char *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to
/// file fails.
void write(const short *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
/// Write data to WAV file in floating point format, saturating sample values to range
/// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails.
void write(const float *buffer, ///< Pointer to sample data buffer.
int numElems ///< How many array items are to be written to file.
);
};
}
#endif

View File

@ -1,333 +1,321 @@
////////////////////////////////////////////////////////////////////////////////
///
/// SoundStretch main routine.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <stdexcept>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "RunParameters.h"
#include "WavFile.h"
#include "SoundTouch.h"
#include "BPMDetect.h"
using namespace soundtouch;
using namespace std;
// Processing chunk size
#define BUFF_SIZE 2048
#if _WIN32
#include <io.h>
#include <fcntl.h>
// Macro for Win32 standard input/output stream support: Sets a file stream into binary mode
#define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY))
#else
// Not needed for GNU environment...
#define SET_STREAM_TO_BIN_MODE(f) {}
#endif
static const char _helloText[] =
"\n"
" SoundStretch v%s - Written by Olli Parviainen 2001 - 2012\n"
"==================================================================\n"
"author e-mail: <oparviai"
"@"
"iki.fi> - WWW: http://www.surina.net/soundtouch\n"
"\n"
"This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"
"more information.\n"
"\n";
static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParameters *params)
{
int bits, samplerate, channels;
if (strcmp(params->inFileName, "stdin") == 0)
{
// used 'stdin' as input file
SET_STREAM_TO_BIN_MODE(stdin);
*inFile = new WavInFile(stdin);
}
else
{
// open input file...
*inFile = new WavInFile(params->inFileName);
}
// ... open output file with same sound parameters
bits = (int)(*inFile)->getNumBits();
samplerate = (int)(*inFile)->getSampleRate();
channels = (int)(*inFile)->getNumChannels();
if (params->outFileName)
{
if (strcmp(params->outFileName, "stdout") == 0)
{
SET_STREAM_TO_BIN_MODE(stdout);
*outFile = new WavOutFile(stdout, samplerate, bits, channels);
}
else
{
*outFile = new WavOutFile(params->outFileName, samplerate, bits, channels);
}
}
else
{
*outFile = NULL;
}
}
// Sets the 'SoundTouch' object up according to input file sound format &
// command line parameters
static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunParameters *params)
{
int sampleRate;
int channels;
sampleRate = (int)inFile->getSampleRate();
channels = (int)inFile->getNumChannels();
pSoundTouch->setSampleRate(sampleRate);
pSoundTouch->setChannels(channels);
pSoundTouch->setTempoChange(params->tempoDelta);
pSoundTouch->setPitchSemiTones(params->pitchDelta);
pSoundTouch->setRateChange(params->rateDelta);
pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, params->quick);
pSoundTouch->setSetting(SETTING_USE_AA_FILTER, !(params->noAntiAlias));
if (params->speech)
{
// use settings for speech processing
pSoundTouch->setSetting(SETTING_SEQUENCE_MS, 40);
pSoundTouch->setSetting(SETTING_SEEKWINDOW_MS, 15);
pSoundTouch->setSetting(SETTING_OVERLAP_MS, 8);
fprintf(stderr, "Tune processing parameters for speech processing.\n");
}
// print processing information
if (params->outFileName)
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
#else
#ifndef SOUNDTOUCH_FLOAT_SAMPLES
#error "Sampletype not defined"
#endif
fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");
#endif
// print processing information only if outFileName given i.e. some processing will happen
fprintf(stderr, "Processing the file with the following changes:\n");
fprintf(stderr, " tempo change = %+g %%\n", params->tempoDelta);
fprintf(stderr, " pitch change = %+g semitones\n", params->pitchDelta);
fprintf(stderr, " rate change = %+g %%\n\n", params->rateDelta);
fprintf(stderr, "Working...");
}
else
{
// outFileName not given
fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n");
}
fflush(stderr);
}
// Processes the sound
static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outFile)
{
int nSamples;
int nChannels;
int buffSizeSamples;
SAMPLETYPE sampleBuffer[BUFF_SIZE];
if ((inFile == NULL) || (outFile == NULL)) return; // nothing to do.
nChannels = (int)inFile->getNumChannels();
assert(nChannels > 0);
buffSizeSamples = BUFF_SIZE / nChannels;
// Process samples read from the input file
while (inFile->eof() == 0)
{
int num;
// Read a chunk of samples from the input file
num = inFile->read(sampleBuffer, BUFF_SIZE);
nSamples = num / (int)inFile->getNumChannels();
// Feed the samples into SoundTouch processor
pSoundTouch->putSamples(sampleBuffer, nSamples);
// Read ready samples from SoundTouch processor & write them output file.
// NOTES:
// - 'receiveSamples' doesn't necessarily return any samples at all
// during some rounds!
// - On the other hand, during some round 'receiveSamples' may have more
// ready samples than would fit into 'sampleBuffer', and for this reason
// the 'receiveSamples' call is iterated for as many times as it
// outputs samples.
do
{
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
outFile->write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0);
}
// Now the input file is processed, yet 'flush' few last samples that are
// hiding in the SoundTouch's internal processing pipeline.
pSoundTouch->flush();
do
{
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
outFile->write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0);
}
// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary
static void detectBPM(WavInFile *inFile, RunParameters *params)
{
float bpmValue;
int nChannels;
BPMDetect bpm(inFile->getNumChannels(), inFile->getSampleRate());
SAMPLETYPE sampleBuffer[BUFF_SIZE];
// detect bpm rate
fprintf(stderr, "Detecting BPM rate...");
fflush(stderr);
nChannels = (int)inFile->getNumChannels();
assert(BUFF_SIZE % nChannels == 0);
// Process the 'inFile' in small blocks, repeat until whole file has
// been processed
while (inFile->eof() == 0)
{
int num, samples;
// Read sample data from input file
num = inFile->read(sampleBuffer, BUFF_SIZE);
// Enter the new samples to the bpm analyzer class
samples = num / nChannels;
bpm.inputSamples(sampleBuffer, samples);
}
// Now the whole song data has been analyzed. Read the resulting bpm.
bpmValue = bpm.getBpm();
fprintf(stderr, "Done!\n");
// rewind the file after bpm detection
inFile->rewind();
if (bpmValue > 0)
{
fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue);
}
else
{
fprintf(stderr, "Couldn't detect BPM rate.\n\n");
return;
}
if (params->goalBPM > 0)
{
// adjust tempo to given bpm
params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f;
fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params->goalBPM);
}
}
int main(const int nParams, const char * const paramStr[])
{
WavInFile *inFile;
WavOutFile *outFile;
RunParameters *params;
SoundTouch soundTouch;
fprintf(stderr, _helloText, SoundTouch::getVersionString());
try
{
// Parse command line parameters
params = new RunParameters(nParams, paramStr);
// Open input & output files
openFiles(&inFile, &outFile, params);
if (params->detectBPM == TRUE)
{
// detect sound BPM (and adjust processing parameters
// accordingly if necessary)
detectBPM(inFile, params);
}
// Setup the 'SoundTouch' object for processing the sound
setup(&soundTouch, inFile, params);
// clock_t cs = clock(); // for benchmarking processing duration
// Process the sound
process(&soundTouch, inFile, outFile);
// clock_t ce = clock(); // for benchmarking processing duration
// printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC);
// Close WAV file handles & dispose of the objects
delete inFile;
delete outFile;
delete params;
fprintf(stderr, "Done!\n");
}
catch (const runtime_error &e)
{
// An exception occurred during processing, display an error message
fprintf(stderr, "%s\n", e.what());
return -1;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
///
/// SoundStretch main routine.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <cstdio>
#include <ctime>
#include "RunParameters.h"
#include "WavFile.h"
#include "SoundTouch.h"
#include "BPMDetect.h"
using namespace soundtouch;
using namespace std;
namespace soundstretch
{
// Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...)
#define BUFF_SIZE 6720
#if _WIN32
#include <io.h>
#include <fcntl.h>
// Macro for Win32 standard input/output stream support: Sets a file stream into binary mode
#define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY))
#else
// Not needed for GNU environment...
#define SET_STREAM_TO_BIN_MODE(f) {}
#endif
static const char _helloText[] =
"\n"
" SoundStretch v%s - Copyright (c) Olli Parviainen\n"
"=========================================================\n"
"author e-mail: <oparviai"
"@"
"iki.fi> - WWW: http://www.surina.net/soundtouch\n"
"\n"
"This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"
"more information.\n"
"\n";
static void openFiles(unique_ptr<WavInFile>& inFile, unique_ptr<WavOutFile>& outFile, const RunParameters& params)
{
if (params.inFileName == STRING_CONST("stdin"))
{
// used 'stdin' as input file
SET_STREAM_TO_BIN_MODE(stdin);
inFile = make_unique<WavInFile>(stdin);
}
else
{
// open input file...
inFile = make_unique<WavInFile>(params.inFileName.c_str());
}
// ... open output file with same sound parameters
const int bits = (int)inFile->getNumBits();
const int samplerate = (int)inFile->getSampleRate();
const int channels = (int)inFile->getNumChannels();
if (!params.outFileName.empty())
{
if (params.outFileName == STRING_CONST("stdout"))
{
SET_STREAM_TO_BIN_MODE(stdout);
outFile = make_unique<WavOutFile>(stdout, samplerate, bits, channels);
}
else
{
outFile = make_unique<WavOutFile>(params.outFileName.c_str(), samplerate, bits, channels);
}
}
}
// Sets the 'SoundTouch' object up according to input file sound format &
// command line parameters
static void setup(SoundTouch& soundTouch, const WavInFile& inFile, const RunParameters& params)
{
const int sampleRate = (int)inFile.getSampleRate();
const int channels = (int)inFile.getNumChannels();
soundTouch.setSampleRate(sampleRate);
soundTouch.setChannels(channels);
soundTouch.setTempoChange(params.tempoDelta);
soundTouch.setPitchSemiTones(params.pitchDelta);
soundTouch.setRateChange(params.rateDelta);
soundTouch.setSetting(SETTING_USE_QUICKSEEK, params.quick);
soundTouch.setSetting(SETTING_USE_AA_FILTER, !(params.noAntiAlias));
if (params.speech)
{
// use settings for speech processing
soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
soundTouch.setSetting(SETTING_OVERLAP_MS, 8);
fprintf(stderr, "Tune processing parameters for speech processing.\n");
}
// print processing information
if (!params.outFileName.empty())
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
#else
#ifndef SOUNDTOUCH_FLOAT_SAMPLES
#error "Sampletype not defined"
#endif
fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");
#endif
// print processing information only if outFileName given i.e. some processing will happen
fprintf(stderr, "Processing the file with the following changes:\n");
fprintf(stderr, " tempo change = %+lg %%\n", params.tempoDelta);
fprintf(stderr, " pitch change = %+lg semitones\n", params.pitchDelta);
fprintf(stderr, " rate change = %+lg %%\n\n", params.rateDelta);
fprintf(stderr, "Working...");
}
else
{
// outFileName not given
fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n");
}
fflush(stderr);
}
// Processes the sound
static void process(SoundTouch& soundTouch, WavInFile& inFile, WavOutFile& outFile)
{
SAMPLETYPE sampleBuffer[BUFF_SIZE];
int nSamples;
const int nChannels = (int)inFile.getNumChannels();
assert(nChannels > 0);
const int buffSizeSamples = BUFF_SIZE / nChannels;
// Process samples read from the input file
while (inFile.eof() == 0)
{
// Read a chunk of samples from the input file
const int num = inFile.read(sampleBuffer, BUFF_SIZE);
int nSamples = num / (int)inFile.getNumChannels();
// Feed the samples into SoundTouch processor
soundTouch.putSamples(sampleBuffer, nSamples);
// Read ready samples from SoundTouch processor & write them output file.
// NOTES:
// - 'receiveSamples' doesn't necessarily return any samples at all
// during some rounds!
// - On the other hand, during some round 'receiveSamples' may have more
// ready samples than would fit into 'sampleBuffer', and for this reason
// the 'receiveSamples' call is iterated for as many times as it
// outputs samples.
do
{
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0);
}
// Now the input file is processed, yet 'flush' few last samples that are
// hiding in the SoundTouch's internal processing pipeline.
soundTouch.flush();
do
{
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0);
}
// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary
static void detectBPM(WavInFile& inFile, RunParameters& params)
{
BPMDetect bpm(inFile.getNumChannels(), inFile.getSampleRate());
SAMPLETYPE sampleBuffer[BUFF_SIZE];
// detect bpm rate
fprintf(stderr, "Detecting BPM rate...");
fflush(stderr);
const int nChannels = (int)inFile.getNumChannels();
int readSize = BUFF_SIZE - BUFF_SIZE % nChannels; // round read size down to multiple of num.channels
// Process the 'inFile' in small blocks, repeat until whole file has
// been processed
while (inFile.eof() == 0)
{
// Read sample data from input file
const int num = inFile.read(sampleBuffer, readSize);
// Enter the new samples to the bpm analyzer class
const int samples = num / nChannels;
bpm.inputSamples(sampleBuffer, samples);
}
// Now the whole song data has been analyzed. Read the resulting bpm.
const float bpmValue = bpm.getBpm();
fprintf(stderr, "Done!\n");
// rewind the file after bpm detection
inFile.rewind();
if (bpmValue > 0)
{
fprintf(stderr, "Detected BPM rate %.1lf\n\n", bpmValue);
}
else
{
fprintf(stderr, "Couldn't detect BPM rate.\n\n");
return;
}
if (params.goalBPM > 0)
{
// adjust tempo to given bpm
params.tempoDelta = (params.goalBPM / bpmValue - 1.0f) * 100.0f;
fprintf(stderr, "The file will be converted to %.1lf BPM\n\n", params.goalBPM);
}
}
void printHelloText()
{
SoundTouch soundTouch;
fprintf(stderr, _helloText, soundTouch.getVersionString());
}
void ss_main(RunParameters& params)
{
unique_ptr<WavInFile> inFile;
unique_ptr<WavOutFile> outFile;
SoundTouch soundTouch;
// Open input & output files
openFiles(inFile, outFile, params);
if (params.detectBPM == true)
{
// detect sound BPM (and adjust processing parameters
// accordingly if necessary)
detectBPM(*inFile, params);
}
// Setup the 'SoundTouch' object for processing the sound
setup(soundTouch, *inFile, params);
// clock_t cs = clock(); // for benchmarking processing duration
// Process the sound
if (inFile && outFile)
{
process(soundTouch, *inFile, *outFile);
}
// clock_t ce = clock(); // for benchmarking processing duration
// printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC);
fprintf(stderr, "Done!\n");
}
}
#if _WIN32
int wmain(int argc, const wchar_t* args[])
#else
int main(int argc, const char* args[])
#endif
{
try
{
soundstretch::printHelloText();
soundstretch::RunParameters params(argc, args);
soundstretch::ss_main(params);
}
catch (const runtime_error& e)
{
fprintf(stderr, "%s\n", e.what());
return -1;
}
catch (const string& e)
{
fprintf(stderr, "%s\n", e.c_str());
return -1;
}
return 0;
}

View File

@ -1,137 +0,0 @@
# Microsoft Developer Studio Project File - Name="soundstretch" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=soundstretch - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "soundstretch.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "soundstretch.mak" CFG="soundstretch - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "soundstretch - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "soundstretch - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "soundstretch - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x40b /d "NDEBUG"
# ADD RSC /l 0x40b /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 SoundTouch.lib /nologo /subsystem:console /profile /map /debug /machine:I386 /libpath:"..\..\lib"
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Cmds=copy Release\soundstretch.exe ..\..\bin\
# End Special Build Tool
!ELSEIF "$(CFG)" == "soundstretch - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /Zp16 /W3 /Gm /GX /ZI /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x40b /d "_DEBUG"
# ADD RSC /l 0x40b /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 SoundTouchD.lib /nologo /subsystem:console /map /debug /machine:I386 /nodefaultlib:"libc" /out:"Debug/soundstretchD.exe" /pdbtype:sept /libpath:"..\..\lib"
# SUBTRACT LINK32 /pdb:none
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Cmds=copy Debug\soundstretchD.exe ..\..\bin\
# End Special Build Tool
!ENDIF
# Begin Target
# Name "soundstretch - Win32 Release"
# Name "soundstretch - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\main.cpp
# End Source File
# Begin Source File
SOURCE=.\RunParameters.cpp
# End Source File
# Begin Source File
SOURCE=.\WavFile.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\RunParameters.h
# End Source File
# Begin Source File
SOURCE=..\..\..\include\SoundTouch.h
# End Source File
# Begin Source File
SOURCE=..\..\..\include\STTypes.h
# End Source File
# Begin Source File
SOURCE=.\WavFile.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View File

@ -1,44 +0,0 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "SoundTouch"=..\SoundTouch\SoundTouch.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "soundstretch"=.\soundstretch.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name SoundTouch
End Project Dependency
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@ -1,32 +1,37 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "soundstretch", "soundstretch.vcproj", "{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}"
ProjectSection(ProjectDependencies) = postProject
{68A5DD20-7057-448B-8FE0-B6AC8D205509} = {68A5DD20-7057-448B-8FE0-B6AC8D205509}
EndProjectSection
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "soundstretch", "soundstretch.vcxproj", "{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "..\SoundTouch\SoundTouch.vcproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "..\SoundTouch\SoundTouch.vcxproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectDependencies) = postSolution
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|Win32.ActiveCfg = Debug|Win32
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|Win32.Build.0 = Debug|Win32
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|x64.ActiveCfg = Debug|x64
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|x64.Build.0 = Debug|x64
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|Win32.ActiveCfg = Release|Win32
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|Win32.Build.0 = Release|Win32
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|x64.ActiveCfg = Release|x64
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|x64.Build.0 = Release|x64
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.ActiveCfg = Debug|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.Build.0 = Debug|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.ActiveCfg = Debug|x64
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.Build.0 = Debug|x64
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.ActiveCfg = Release|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.Build.0 = Release|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.ActiveCfg = Release|x64
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug.ActiveCfg = Debug|Win32
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug.Build.0 = Debug|Win32
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release.ActiveCfg = Release|Win32
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release.Build.0 = Release|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug.ActiveCfg = Debug|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug.Build.0 = Debug|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release.ActiveCfg = Release|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,235 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="soundstretch"
SccProjectName=""
SccLocalPath="">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
StructMemberAlignment="5"
PrecompiledHeaderFile=".\Debug/soundstretch.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="SoundTouchD.lib"
OutputFile="Debug/soundstretchD.exe"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="..\..\lib"
IgnoreDefaultLibraryNames="libc"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile=".\Debug/soundstretchD.pdb"
GenerateMapFile="TRUE"
MapFileName=".\Debug/soundstretchD.map"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Debug/soundstretch.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy Debug\soundstretchD.exe ..\..\bin\"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1035"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="1"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="FALSE"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
PrecompiledHeaderFile=".\Release/soundstretch.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="0"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="SoundTouch.lib"
OutputFile=".\Release/soundstretch.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="..\..\lib"
GenerateDebugInformation="FALSE"
GenerateMapFile="TRUE"
MapFileName=".\Release/soundstretch.map"
SubSystem="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
TypeLibraryName=".\Release/soundstretch.tlb"
HeaderFileName=""/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy Release\soundstretch.exe ..\..\bin\"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1035"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath="main.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
</File>
<File
RelativePath="RunParameters.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
</File>
<File
RelativePath="WavFile.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
<File
RelativePath="RunParameters.h">
</File>
<File
RelativePath="WavFile.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,333 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}</ProjectGuid>
<RootNamespace>soundstretch</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>$(ProjectName)D</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<TargetName>$(ProjectName)D_x64</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>false</LinkIncremental>
<TargetName>$(ProjectName)_x64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Midl>
<TypeLibraryName>.\Debug/soundstretch.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>16Bytes</StructMemberAlignment>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem>
<DataExecutionPrevention />
</Link>
<PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Midl>
<TypeLibraryName>.\Release/soundstretch.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Full</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat />
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem>
<DataExecutionPrevention />
</Link>
<PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Debug/soundstretch.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>16Bytes</StructMemberAlignment>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>
</EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
<GenerateDebugInformation>true</GenerateDebugInformation>
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem>
<DataExecutionPrevention />
</Link>
<PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
<TypeLibraryName>.\Release/soundstretch.tlb</TypeLibraryName>
<HeaderFileName />
</Midl>
<ClCompile>
<Optimization>Full</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat />
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>
</EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Link>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>false</GenerateDebugInformation>
<GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem>
<DataExecutionPrevention />
</Link>
<PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="RunParameters.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="WavFile.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="RunParameters.h" />
<ClInclude Include="SS_CharTypes.h" />
<ClInclude Include="WavFile.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SoundTouch\SoundTouch.vcxproj">
<Project>{68a5dd20-7057-448b-8fe0-b6ac8d205509}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -1,184 +1,222 @@
////////////////////////////////////////////////////////////////////////////////
///
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
/// MMX optimization.
///
/// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "AAFilter.h"
#include "FIRFilter.h"
using namespace soundtouch;
#define PI 3.141592655357989
#define TWOPI (2 * PI)
/*****************************************************************************
*
* Implementation of the class 'AAFilter'
*
*****************************************************************************/
AAFilter::AAFilter(uint len)
{
pFIR = FIRFilter::newInstance();
cutoffFreq = 0.5;
setLength(len);
}
AAFilter::~AAFilter()
{
delete pFIR;
}
// Sets new anti-alias filter cut-off edge frequency, scaled to
// sampling frequency (nyquist frequency = 0.5).
// The filter will cut frequencies higher than the given frequency.
void AAFilter::setCutoffFreq(double newCutoffFreq)
{
cutoffFreq = newCutoffFreq;
calculateCoeffs();
}
// Sets number of FIR filter taps
void AAFilter::setLength(uint newLength)
{
length = newLength;
calculateCoeffs();
}
// Calculates coefficients for a low-pass FIR filter using Hamming window
void AAFilter::calculateCoeffs()
{
uint i;
double cntTemp, temp, tempCoeff,h, w;
double fc2, wc;
double scaleCoeff, sum;
double *work;
SAMPLETYPE *coeffs;
assert(length >= 2);
assert(length % 4 == 0);
assert(cutoffFreq >= 0);
assert(cutoffFreq <= 0.5);
work = new double[length];
coeffs = new SAMPLETYPE[length];
fc2 = 2.0 * cutoffFreq;
wc = PI * fc2;
tempCoeff = TWOPI / (double)length;
sum = 0;
for (i = 0; i < length; i ++)
{
cntTemp = (double)i - (double)(length / 2);
temp = cntTemp * wc;
if (temp != 0)
{
h = fc2 * sin(temp) / temp; // sinc function
}
else
{
h = 1.0;
}
w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
temp = w * h;
work[i] = temp;
// calc net sum of coefficients
sum += temp;
}
// ensure the sum of coefficients is larger than zero
assert(sum > 0);
// ensure we've really designed a lowpass filter...
assert(work[length/2] > 0);
assert(work[length/2 + 1] > -1e-6);
assert(work[length/2 - 1] > -1e-6);
// Calculate a scaling coefficient in such a way that the result can be
// divided by 16384
scaleCoeff = 16384.0f / sum;
for (i = 0; i < length; i ++)
{
// scale & round to nearest integer
temp = work[i] * scaleCoeff;
temp += (temp >= 0) ? 0.5 : -0.5;
// ensure no overfloods
assert(temp >= -32768 && temp <= 32767);
coeffs[i] = (SAMPLETYPE)temp;
}
// Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
pFIR->setCoefficients(coeffs, length, 14);
delete[] work;
delete[] coeffs;
}
// Applies the filter to the given sequence of samples.
// Note : The amount of outputted samples is by value of 'filter length'
// smaller than the amount of input samples.
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
{
return pFIR->evaluate(dest, src, numSamples, numChannels);
}
uint AAFilter::getLength() const
{
return pFIR->getLength();
}
////////////////////////////////////////////////////////////////////////////////
///
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
/// MMX optimization.
///
/// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "AAFilter.h"
#include "FIRFilter.h"
using namespace soundtouch;
#define PI 3.14159265358979323846
#define TWOPI (2 * PI)
// define this to save AA filter coefficients to a file
// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1
#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS
#include <stdio.h>
static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)
{
FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");
if (fptr == nullptr) return;
for (int i = 0; i < len; i ++)
{
double temp = coeffs[i];
fprintf(fptr, "%lf\n", temp);
}
fclose(fptr);
}
#else
#define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
#endif
/*****************************************************************************
*
* Implementation of the class 'AAFilter'
*
*****************************************************************************/
AAFilter::AAFilter(uint len)
{
pFIR = FIRFilter::newInstance();
cutoffFreq = 0.5;
setLength(len);
}
AAFilter::~AAFilter()
{
delete pFIR;
}
// Sets new anti-alias filter cut-off edge frequency, scaled to
// sampling frequency (nyquist frequency = 0.5).
// The filter will cut frequencies higher than the given frequency.
void AAFilter::setCutoffFreq(double newCutoffFreq)
{
cutoffFreq = newCutoffFreq;
calculateCoeffs();
}
// Sets number of FIR filter taps
void AAFilter::setLength(uint newLength)
{
length = newLength;
calculateCoeffs();
}
// Calculates coefficients for a low-pass FIR filter using Hamming window
void AAFilter::calculateCoeffs()
{
uint i;
double cntTemp, temp, tempCoeff,h, w;
double wc;
double scaleCoeff, sum;
double *work;
SAMPLETYPE *coeffs;
assert(length >= 2);
assert(length % 4 == 0);
assert(cutoffFreq >= 0);
assert(cutoffFreq <= 0.5);
work = new double[length];
coeffs = new SAMPLETYPE[length];
wc = 2.0 * PI * cutoffFreq;
tempCoeff = TWOPI / (double)length;
sum = 0;
for (i = 0; i < length; i ++)
{
cntTemp = (double)i - (double)(length / 2);
temp = cntTemp * wc;
if (temp != 0)
{
h = sin(temp) / temp; // sinc function
}
else
{
h = 1.0;
}
w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
temp = w * h;
work[i] = temp;
// calc net sum of coefficients
sum += temp;
}
// ensure the sum of coefficients is larger than zero
assert(sum > 0);
// ensure we've really designed a lowpass filter...
assert(work[length/2] > 0);
assert(work[length/2 + 1] > -1e-6);
assert(work[length/2 - 1] > -1e-6);
// Calculate a scaling coefficient in such a way that the result can be
// divided by 16384
scaleCoeff = 16384.0f / sum;
for (i = 0; i < length; i ++)
{
temp = work[i] * scaleCoeff;
// scale & round to nearest integer
temp += (temp >= 0) ? 0.5 : -0.5;
// ensure no overfloods
assert(temp >= -32768 && temp <= 32767);
coeffs[i] = (SAMPLETYPE)temp;
}
// Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
pFIR->setCoefficients(coeffs, length, 14);
_DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);
delete[] work;
delete[] coeffs;
}
// Applies the filter to the given sequence of samples.
// Note : The amount of outputted samples is by value of 'filter length'
// smaller than the amount of input samples.
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
{
return pFIR->evaluate(dest, src, numSamples, numChannels);
}
/// Applies the filter to the given src & dest pipes, so that processed amount of
/// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples.
uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
{
SAMPLETYPE *pdest;
const SAMPLETYPE *psrc;
uint numSrcSamples;
uint result;
int numChannels = src.getChannels();
assert(numChannels == dest.getChannels());
numSrcSamples = src.numSamples();
psrc = src.ptrBegin();
pdest = dest.ptrEnd(numSrcSamples);
result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);
src.receiveSamples(result);
dest.putSamples(result);
return result;
}
uint AAFilter::getLength() const
{
return pFIR->getLength();
}

View File

@ -1,91 +1,93 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks.
///
/// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef AAFilter_H
#define AAFilter_H
#include "STTypes.h"
namespace soundtouch
{
class AAFilter
{
protected:
class FIRFilter *pFIR;
/// Low-pass filter cut-off frequency, negative = invalid
double cutoffFreq;
/// num of filter taps
uint length;
/// Calculate the FIR coefficients realizing the given cutoff-frequency
void calculateCoeffs();
public:
AAFilter(uint length);
~AAFilter();
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
/// frequency (nyquist frequency = 0.5). The filter will cut off the
/// frequencies than that.
void setCutoffFreq(double newCutoffFreq);
/// Sets number of FIR filter taps, i.e. ~filter complexity
void setLength(uint newLength);
uint getLength() const;
/// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples.
uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples,
uint numChannels) const;
};
}
#endif
////////////////////////////////////////////////////////////////////////////////
///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks.
///
/// Anti-alias filter is used to prevent folding of high frequencies when
/// transposing the sample rate with interpolation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef AAFilter_H
#define AAFilter_H
#include "STTypes.h"
#include "FIFOSampleBuffer.h"
namespace soundtouch
{
class AAFilter
{
protected:
class FIRFilter *pFIR;
/// Low-pass filter cut-off frequency, negative = invalid
double cutoffFreq;
/// num of filter taps
uint length;
/// Calculate the FIR coefficients realizing the given cutoff-frequency
void calculateCoeffs();
public:
AAFilter(uint length);
~AAFilter();
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
/// frequency (nyquist frequency = 0.5). The filter will cut off the
/// frequencies than that.
void setCutoffFreq(double newCutoffFreq);
/// Sets number of FIR filter taps, i.e. ~filter complexity
void setLength(uint newLength);
uint getLength() const;
/// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples.
uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples,
uint numChannels) const;
/// Applies the filter to the given src & dest pipes, so that processed amount of
/// samples get removed from src, and produced amount added to dest
/// Note : The amount of outputted samples is by value of 'filter length'
/// smaller than the amount of input samples.
uint evaluate(FIFOSampleBuffer &dest,
FIFOSampleBuffer &src) const;
};
}
#endif

View File

@ -1,370 +1,571 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Beats-per-minute (BPM) detection routine.
///
/// The beat detection algorithm works as follows:
/// - Use function 'inputSamples' to input a chunks of samples to the class for
/// analysis. It's a good idea to enter a large sound file or stream in smallish
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden,
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
/// Simple averaging is used for anti-alias filtering because the resulting signal
/// quality isn't of that high importance.
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
/// taking absolute value that's smoothed by sliding average. Signal levels that
/// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
/// function, calculates it's precise location and converts this reading to bpm's.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <math.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include "FIFOSampleBuffer.h"
#include "PeakFinder.h"
#include "BPMDetect.h"
using namespace soundtouch;
#define INPUT_BLOCK_SAMPLES 2048
#define DECIMATED_BLOCK_SAMPLES 256
/// decay constant for calculating RMS volume sliding average approximation
/// (time constant is about 10 sec)
const float avgdecay = 0.99986f;
/// Normalization coefficient for calculating RMS sliding average approximation.
const float avgnorm = (1 - avgdecay);
////////////////////////////////////////////////////////////////////////////////
// Enable following define to create bpm analysis file:
// #define _CREATE_BPM_DEBUG_FILE
#ifdef _CREATE_BPM_DEBUG_FILE
#define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt"
static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff)
{
FILE *fptr = fopen(DEBUGFILE_NAME, "wt");
int i;
if (fptr)
{
printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n");
for (i = minpos; i < maxpos; i ++)
{
fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]);
}
fclose(fptr);
}
}
#else
#define _SaveDebugData(a,b,c,d)
#endif
////////////////////////////////////////////////////////////////////////////////
BPMDetect::BPMDetect(int numChannels, int aSampleRate)
{
this->sampleRate = aSampleRate;
this->channels = numChannels;
decimateSum = 0;
decimateCount = 0;
envelopeAccu = 0;
// Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's
// safe initial RMS signal level value for song data. This value is then adapted
// to the actual level during processing.
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// integer samples
RMSVolumeAccu = (1500 * 1500) / avgnorm;
#else
// float samples, scaled to range [-1..+1[
RMSVolumeAccu = (0.045f * 0.045f) / avgnorm;
#endif
// choose decimation factor so that result is approx. 1000 Hz
decimateBy = sampleRate / 1000;
assert(decimateBy > 0);
assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES);
// Calculate window length & starting item according to desired min & max bpms
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM);
assert(windowLen > windowStart);
// allocate new working objects
xcorr = new float[windowLen];
memset(xcorr, 0, windowLen * sizeof(float));
// allocate processing buffer
buffer = new FIFOSampleBuffer();
// we do processing in mono mode
buffer->setChannels(1);
buffer->clear();
}
BPMDetect::~BPMDetect()
{
delete[] xcorr;
delete buffer;
}
/// convert to mono, low-pass filter & decimate to about 500 Hz.
/// return number of outputted samples.
///
/// Decimation is used to remove the unnecessary frequencies and thus to reduce
/// the amount of data needed to be processed as calculating autocorrelation
/// function is a very-very heavy operation.
///
/// Anti-alias filtering is done simply by averaging the samples. This is really a
/// poor-man's anti-alias filtering, but it's not so critical in this kind of application
/// (it'd also be difficult to design a high-quality filter with steep cut-off at very
/// narrow band)
int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
{
int count, outcount;
LONG_SAMPLETYPE out;
assert(channels > 0);
assert(decimateBy > 0);
outcount = 0;
for (count = 0; count < numsamples; count ++)
{
int j;
// convert to mono and accumulate
for (j = 0; j < channels; j ++)
{
decimateSum += src[j];
}
src += j;
decimateCount ++;
if (decimateCount >= decimateBy)
{
// Store every Nth sample only
out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels));
decimateSum = 0;
decimateCount = 0;
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// check ranges for sure (shouldn't actually be necessary)
if (out > 32767)
{
out = 32767;
}
else if (out < -32768)
{
out = -32768;
}
#endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[outcount] = (SAMPLETYPE)out;
outcount ++;
}
}
return outcount;
}
// Calculates autocorrelation function of the sample history buffer
void BPMDetect::updateXCorr(int process_samples)
{
int offs;
SAMPLETYPE *pBuffer;
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
pBuffer = buffer->ptrBegin();
for (offs = windowStart; offs < windowLen; offs ++)
{
LONG_SAMPLETYPE sum;
int i;
sum = 0;
for (i = 0; i < process_samples; i ++)
{
sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
}
// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients
// if it's desired that the system adapts automatically to
// various bpms, e.g. in processing continouos music stream.
// The 'xcorr_decay' should be a value that's smaller than but
// close to one, and should also depend on 'process_samples' value.
xcorr[offs] += (float)sum;
}
}
// Calculates envelope of the sample data
void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
{
const static double decay = 0.7f; // decay constant for smoothing the envelope
const static double norm = (1 - decay);
int i;
LONG_SAMPLETYPE out;
double val;
for (i = 0; i < numsamples; i ++)
{
// calc average RMS volume
RMSVolumeAccu *= avgdecay;
val = (float)fabs((float)samples[i]);
RMSVolumeAccu += val * val;
// cut amplitudes that are below cutoff ~2 times RMS volume
// (we're interested in peak values, not the silent moments)
if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm))
{
val = 0;
}
// smooth amplitude envelope
envelopeAccu *= decay;
envelopeAccu += val;
out = (LONG_SAMPLETYPE)(envelopeAccu * norm);
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// cut peaks (shouldn't be necessary though)
if (out > 32767) out = 32767;
#endif // SOUNDTOUCH_INTEGER_SAMPLES
samples[i] = (SAMPLETYPE)out;
}
}
void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
{
SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES];
// iterate so that max INPUT_BLOCK_SAMPLES processed per iteration
while (numSamples > 0)
{
int block;
int decSamples;
block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples;
// decimate. note that converts to mono at the same time
decSamples = decimate(decimated, samples, block);
samples += block * channels;
numSamples -= block;
// envelope new samples and add them to buffer
calcEnvelope(decimated, decSamples);
buffer->putSamples(decimated, decSamples);
}
// when the buffer has enought samples for processing...
if ((int)buffer->numSamples() > windowLen)
{
int processLength;
// how many samples are processed
processLength = (int)buffer->numSamples() - windowLen;
// ... calculate autocorrelations for oldest samples...
updateXCorr(processLength);
// ... and remove them from the buffer
buffer->receiveSamples(processLength);
}
}
void BPMDetect::removeBias()
{
int i;
float minval = 1e12f; // arbitrary large number
for (i = windowStart; i < windowLen; i ++)
{
if (xcorr[i] < minval)
{
minval = xcorr[i];
}
}
for (i = windowStart; i < windowLen; i ++)
{
xcorr[i] -= minval;
}
}
float BPMDetect::getBpm()
{
double peakPos;
double coeff;
PeakFinder peakFinder;
coeff = 60.0 * ((double)sampleRate / (double)decimateBy);
// save bpm debug analysis data if debug data enabled
_SaveDebugData(xcorr, windowStart, windowLen, coeff);
// remove bias from xcorr data
removeBias();
// find peak position
peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen);
assert(decimateBy != 0);
if (peakPos < 1e-9) return 0.0; // detection failed.
// calculate BPM
return (float) (coeff / peakPos);
}
////////////////////////////////////////////////////////////////////////////////
///
/// Beats-per-minute (BPM) detection routine.
///
/// The beat detection algorithm works as follows:
/// - Use function 'inputSamples' to input a chunks of samples to the class for
/// analysis. It's a good idea to enter a large sound file or stream in smallish
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden,
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
/// Simple averaging is used for anti-alias filtering because the resulting signal
/// quality isn't of that high importance.
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
/// taking absolute value that's smoothed by sliding average. Signal levels that
/// are below a couple of times the general RMS amplitude level are cut away to
/// leave only notable peaks there.
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
/// autocorrelation function of the enveloped signal.
/// - After whole sound data file has been analyzed as above, the bpm level is
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
/// function, calculates it's precise location and converts this reading to bpm's.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#define _USE_MATH_DEFINES
#include <math.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <cfloat>
#include "FIFOSampleBuffer.h"
#include "PeakFinder.h"
#include "BPMDetect.h"
using namespace soundtouch;
// algorithm input sample block size
static const int INPUT_BLOCK_SIZE = 2048;
// decimated sample block size
static const int DECIMATED_BLOCK_SIZE = 256;
/// Target sample rate after decimation
static const int TARGET_SRATE = 1000;
/// XCorr update sequence size, update in about 200msec chunks
static const int XCORR_UPDATE_SEQUENCE = (int)(TARGET_SRATE / 5);
/// Moving average N size
static const int MOVING_AVERAGE_N = 15;
/// XCorr decay time constant, decay to half in 30 seconds
/// If it's desired to have the system adapt quicker to beat rate
/// changes within a continuing music stream, then the
/// 'xcorr_decay_time_constant' value can be reduced, yet that
/// can increase possibility of glitches in bpm detection.
static const double XCORR_DECAY_TIME_CONSTANT = 30.0;
/// Data overlap factor for beat detection algorithm
static const int OVERLAP_FACTOR = 4;
static const double TWOPI = (2 * M_PI);
////////////////////////////////////////////////////////////////////////////////
// Enable following define to create bpm analysis file:
//#define _CREATE_BPM_DEBUG_FILE
#ifdef _CREATE_BPM_DEBUG_FILE
static void _SaveDebugData(const char *name, const float *data, int minpos, int maxpos, double coeff)
{
FILE *fptr = fopen(name, "wt");
int i;
if (fptr)
{
printf("\nWriting BPM debug data into file %s\n", name);
for (i = minpos; i < maxpos; i ++)
{
fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]);
}
fclose(fptr);
}
}
void _SaveDebugBeatPos(const char *name, const std::vector<BEAT> &beats)
{
printf("\nWriting beat detections data into file %s\n", name);
FILE *fptr = fopen(name, "wt");
if (fptr)
{
for (uint i = 0; i < beats.size(); i++)
{
BEAT b = beats[i];
fprintf(fptr, "%lf\t%lf\n", b.pos, b.strength);
}
fclose(fptr);
}
}
#else
#define _SaveDebugData(name, a,b,c,d)
#define _SaveDebugBeatPos(name, b)
#endif
// Hamming window
void hamming(float *w, int N)
{
for (int i = 0; i < N; i++)
{
w[i] = (float)(0.54 - 0.46 * cos(TWOPI * i / (N - 1)));
}
}
////////////////////////////////////////////////////////////////////////////////
//
// IIR2_filter - 2nd order IIR filter
IIR2_filter::IIR2_filter(const double *lpf_coeffs)
{
memcpy(coeffs, lpf_coeffs, 5 * sizeof(double));
memset(prev, 0, sizeof(prev));
}
float IIR2_filter::update(float x)
{
prev[0] = x;
double y = x * coeffs[0];
for (int i = 4; i >= 1; i--)
{
y += coeffs[i] * prev[i];
prev[i] = prev[i - 1];
}
prev[3] = y;
return (float)y;
}
// IIR low-pass filter coefficients, calculated with matlab/octave cheby2(2,40,0.05)
const double _LPF_coeffs[5] = { 0.00996655391939, -0.01944529148401, 0.00996655391939, 1.96867605796247, -0.96916387431724 };
////////////////////////////////////////////////////////////////////////////////
BPMDetect::BPMDetect(int numChannels, int aSampleRate) :
beat_lpf(_LPF_coeffs)
{
beats.reserve(250); // initial reservation to prevent frequent reallocation
this->sampleRate = aSampleRate;
this->channels = numChannels;
decimateSum = 0;
decimateCount = 0;
// choose decimation factor so that result is approx. 1000 Hz
decimateBy = sampleRate / TARGET_SRATE;
if ((decimateBy <= 0) || (decimateBy * DECIMATED_BLOCK_SIZE < INPUT_BLOCK_SIZE))
{
ST_THROW_RT_ERROR("Too small samplerate");
}
// Calculate window length & starting item according to desired min & max bpms
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM_RANGE);
assert(windowLen > windowStart);
// allocate new working objects
xcorr = new float[windowLen];
memset(xcorr, 0, windowLen * sizeof(float));
pos = 0;
peakPos = 0;
peakVal = 0;
init_scaler = 1;
beatcorr_ringbuffpos = 0;
beatcorr_ringbuff = new float[windowLen];
memset(beatcorr_ringbuff, 0, windowLen * sizeof(float));
// allocate processing buffer
buffer = new FIFOSampleBuffer();
// we do processing in mono mode
buffer->setChannels(1);
buffer->clear();
// calculate hamming windows
hamw = new float[XCORR_UPDATE_SEQUENCE];
hamming(hamw, XCORR_UPDATE_SEQUENCE);
hamw2 = new float[XCORR_UPDATE_SEQUENCE / 2];
hamming(hamw2, XCORR_UPDATE_SEQUENCE / 2);
}
BPMDetect::~BPMDetect()
{
delete[] xcorr;
delete[] beatcorr_ringbuff;
delete[] hamw;
delete[] hamw2;
delete buffer;
}
/// convert to mono, low-pass filter & decimate to about 500 Hz.
/// return number of outputted samples.
///
/// Decimation is used to remove the unnecessary frequencies and thus to reduce
/// the amount of data needed to be processed as calculating autocorrelation
/// function is a very-very heavy operation.
///
/// Anti-alias filtering is done simply by averaging the samples. This is really a
/// poor-man's anti-alias filtering, but it's not so critical in this kind of application
/// (it'd also be difficult to design a high-quality filter with steep cut-off at very
/// narrow band)
int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
{
int count, outcount;
LONG_SAMPLETYPE out;
assert(channels > 0);
assert(decimateBy > 0);
outcount = 0;
for (count = 0; count < numsamples; count ++)
{
int j;
// convert to mono and accumulate
for (j = 0; j < channels; j ++)
{
decimateSum += src[j];
}
src += j;
decimateCount ++;
if (decimateCount >= decimateBy)
{
// Store every Nth sample only
out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels));
decimateSum = 0;
decimateCount = 0;
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// check ranges for sure (shouldn't actually be necessary)
if (out > 32767)
{
out = 32767;
}
else if (out < -32768)
{
out = -32768;
}
#endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[outcount] = (SAMPLETYPE)out;
outcount ++;
}
}
return outcount;
}
// Calculates autocorrelation function of the sample history buffer
void BPMDetect::updateXCorr(int process_samples)
{
int offs;
SAMPLETYPE *pBuffer;
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
assert(process_samples == XCORR_UPDATE_SEQUENCE);
pBuffer = buffer->ptrBegin();
// calculate decay factor for xcorr filtering
float xcorr_decay = (float)pow(0.5, process_samples / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE));
// prescale pbuffer
float tmp[XCORR_UPDATE_SEQUENCE];
for (int i = 0; i < process_samples; i++)
{
tmp[i] = hamw[i] * hamw[i] * pBuffer[i];
}
#pragma omp parallel for
for (offs = windowStart; offs < windowLen; offs ++)
{
float sum;
int i;
sum = 0;
for (i = 0; i < process_samples; i ++)
{
sum += tmp[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
}
xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable time constant.
xcorr[offs] += (float)fabs(sum);
}
}
// Detect individual beat positions
void BPMDetect::updateBeatPos(int process_samples)
{
SAMPLETYPE *pBuffer;
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
pBuffer = buffer->ptrBegin();
assert(process_samples == XCORR_UPDATE_SEQUENCE / 2);
// static double thr = 0.0003;
double posScale = (double)this->decimateBy / (double)this->sampleRate;
int resetDur = (int)(0.12 / posScale + 0.5);
// prescale pbuffer
float tmp[XCORR_UPDATE_SEQUENCE / 2];
for (int i = 0; i < process_samples; i++)
{
tmp[i] = hamw2[i] * hamw2[i] * pBuffer[i];
}
#pragma omp parallel for
for (int offs = windowStart; offs < windowLen; offs++)
{
float sum = 0;
for (int i = 0; i < process_samples; i++)
{
sum += tmp[i] * pBuffer[offs + i];
}
beatcorr_ringbuff[(beatcorr_ringbuffpos + offs) % windowLen] += (float)((sum > 0) ? sum : 0); // accumulate only positive correlations
}
int skipstep = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;
// compensate empty buffer at beginning by scaling coefficient
float scale = (float)windowLen / (float)(skipstep * init_scaler);
if (scale > 1.0f)
{
init_scaler++;
}
else
{
scale = 1.0f;
}
// detect beats
for (int i = 0; i < skipstep; i++)
{
float sum = beatcorr_ringbuff[beatcorr_ringbuffpos];
sum -= beat_lpf.update(sum);
if (sum > peakVal)
{
// found new local largest value
peakVal = sum;
peakPos = pos;
}
if (pos > peakPos + resetDur)
{
// largest value not updated for 200msec => accept as beat
peakPos += skipstep;
if (peakVal > 0)
{
// add detected beat to end of "beats" vector
BEAT temp = { (float)(peakPos * posScale), (float)(peakVal * scale) };
beats.push_back(temp);
}
peakVal = 0;
peakPos = pos;
}
beatcorr_ringbuff[beatcorr_ringbuffpos] = 0;
pos++;
beatcorr_ringbuffpos = (beatcorr_ringbuffpos + 1) % windowLen;
}
}
#define max(x,y) ((x) > (y) ? (x) : (y))
void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
{
SAMPLETYPE decimated[DECIMATED_BLOCK_SIZE];
// iterate so that max INPUT_BLOCK_SAMPLES processed per iteration
while (numSamples > 0)
{
int block;
int decSamples;
block = (numSamples > INPUT_BLOCK_SIZE) ? INPUT_BLOCK_SIZE : numSamples;
// decimate. note that converts to mono at the same time
decSamples = decimate(decimated, samples, block);
samples += block * channels;
numSamples -= block;
buffer->putSamples(decimated, decSamples);
}
// when the buffer has enough samples for processing...
int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE);
while ((int)buffer->numSamples() >= req)
{
// ... update autocorrelations...
updateXCorr(XCORR_UPDATE_SEQUENCE);
// ...update beat position calculation...
updateBeatPos(XCORR_UPDATE_SEQUENCE / 2);
// ... and remove proceessed samples from the buffer
int n = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;
buffer->receiveSamples(n);
}
}
void BPMDetect::removeBias()
{
int i;
// Remove linear bias: calculate linear regression coefficient
// 1. calc mean of 'xcorr' and 'i'
double mean_i = 0;
double mean_x = 0;
for (i = windowStart; i < windowLen; i++)
{
mean_x += xcorr[i];
}
mean_x /= (windowLen - windowStart);
mean_i = 0.5 * (windowLen - 1 + windowStart);
// 2. calculate linear regression coefficient
double b = 0;
double div = 0;
for (i = windowStart; i < windowLen; i++)
{
double xt = xcorr[i] - mean_x;
double xi = i - mean_i;
b += xt * xi;
div += xi * xi;
}
b /= div;
// subtract linear regression and resolve min. value bias
float minval = FLT_MAX; // arbitrary large number
for (i = windowStart; i < windowLen; i ++)
{
xcorr[i] -= (float)(b * i);
if (xcorr[i] < minval)
{
minval = xcorr[i];
}
}
// subtract min.value
for (i = windowStart; i < windowLen; i ++)
{
xcorr[i] -= minval;
}
}
// Calculate N-point moving average for "source" values
void MAFilter(float *dest, const float *source, int start, int end, int N)
{
for (int i = start; i < end; i++)
{
int i1 = i - N / 2;
int i2 = i + N / 2 + 1;
if (i1 < start) i1 = start;
if (i2 > end) i2 = end;
double sum = 0;
for (int j = i1; j < i2; j ++)
{
sum += source[j];
}
dest[i] = (float)(sum / (i2 - i1));
}
}
float BPMDetect::getBpm()
{
double peakPos;
double coeff;
PeakFinder peakFinder;
// remove bias from xcorr data
removeBias();
coeff = 60.0 * ((double)sampleRate / (double)decimateBy);
// save bpm debug data if debug data writing enabled
_SaveDebugData("soundtouch-bpm-xcorr.txt", xcorr, windowStart, windowLen, coeff);
// Smoothen by N-point moving-average
float *data = new float[windowLen];
memset(data, 0, sizeof(float) * windowLen);
MAFilter(data, xcorr, windowStart, windowLen, MOVING_AVERAGE_N);
// find peak position
peakPos = peakFinder.detectPeak(data, windowStart, windowLen);
// save bpm debug data if debug data writing enabled
_SaveDebugData("soundtouch-bpm-smoothed.txt", data, windowStart, windowLen, coeff);
delete[] data;
assert(decimateBy != 0);
if (peakPos < 1e-9) return 0.0; // detection failed.
_SaveDebugBeatPos("soundtouch-detected-beats.txt", beats);
// calculate BPM
float bpm = (float)(coeff / peakPos);
return (bpm >= MIN_BPM && bpm <= MAX_BPM_VALID) ? bpm : 0;
}
/// Get beat position arrays. Note: The array includes also really low beat detection values
/// in absence of clear strong beats. Consumer may wish to filter low values away.
/// - "pos" receive array of beat positions
/// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array.
///
/// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
///
/// \return number of beats in the arrays.
int BPMDetect::getBeats(float *pos, float *values, int max_num)
{
int num = (int)beats.size();
if ((!pos) || (!values)) return num; // pos or values nullptr, return just size
for (int i = 0; (i < num) && (i < max_num); i++)
{
pos[i] = beats[i].pos;
values[i] = beats[i].strength;
}
return num;
}

View File

@ -1,274 +1,275 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe.
///
/// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the
/// outputted samples from the buffer, as well as grows the buffer size
/// whenever necessary.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include "FIFOSampleBuffer.h"
using namespace soundtouch;
// Constructor
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
{
assert(numChannels > 0);
sizeInBytes = 0; // reasonable initial value
buffer = NULL;
bufferUnaligned = NULL;
samplesInBuffer = 0;
bufferPos = 0;
channels = (uint)numChannels;
ensureCapacity(32); // allocate initial capacity
}
// destructor
FIFOSampleBuffer::~FIFOSampleBuffer()
{
delete[] bufferUnaligned;
bufferUnaligned = NULL;
buffer = NULL;
}
// Sets number of channels, 1 = mono, 2 = stereo
void FIFOSampleBuffer::setChannels(int numChannels)
{
uint usedBytes;
assert(numChannels > 0);
usedBytes = channels * samplesInBuffer;
channels = (uint)numChannels;
samplesInBuffer = usedBytes / channels;
}
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
// zeroes this pointer by copying samples from the 'bufferPos' pointer
// location on to the beginning of the buffer.
void FIFOSampleBuffer::rewind()
{
if (buffer && bufferPos)
{
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
bufferPos = 0;
}
}
// Adds 'numSamples' pcs of samples from the 'samples' memory position to
// the sample buffer.
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
{
memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
samplesInBuffer += nSamples;
}
// Increases the number of samples in the buffer without copying any actual
// samples.
//
// This function is used to update the number of samples in the sample buffer
// when accessing the buffer directly with 'ptrEnd' function. Please be
// careful though!
void FIFOSampleBuffer::putSamples(uint nSamples)
{
uint req;
req = samplesInBuffer + nSamples;
ensureCapacity(req);
samplesInBuffer += nSamples;
}
// Returns a pointer to the end of the used part of the sample buffer (i.e.
// where the new samples are to be inserted). This function may be used for
// inserting new samples into the sample buffer directly. Please be careful!
//
// Parameter 'slackCapacity' tells the function how much free capacity (in
// terms of samples) there _at least_ should be, in order to the caller to
// succesfully insert all the required samples to the buffer. When necessary,
// the function grows the buffer size to comply with this requirement.
//
// When using this function as means for inserting new samples, also remember
// to increase the sample count afterwards, by calling the
// 'putSamples(numSamples)' function.
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
{
ensureCapacity(samplesInBuffer + slackCapacity);
return buffer + samplesInBuffer * channels;
}
// Returns a pointer to the beginning of the currently non-outputted samples.
// This function is provided for accessing the output samples directly.
// Please be careful!
//
// When using this function to output samples, also remember to 'remove' the
// outputted samples from the buffer by calling the
// 'receiveSamples(numSamples)' function
SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
{
assert(buffer);
return buffer + bufferPos * channels;
}
// Ensures that the buffer has enought capacity, i.e. space for _at least_
// 'capacityRequirement' number of samples. The buffer is grown in steps of
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
// as well as to round the buffer size up to the virtual memory page size.
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
{
SAMPLETYPE *tempUnaligned, *temp;
if (capacityRequirement > getCapacity())
{
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
assert(sizeInBytes % 2 == 0);
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
if (tempUnaligned == NULL)
{
ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
}
// Align the buffer to begin at 16byte cache line boundary for optimal performance
temp = (SAMPLETYPE *)(((ulong)tempUnaligned + 15) & (ulong)-16);
if (samplesInBuffer)
{
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
}
delete[] bufferUnaligned;
buffer = temp;
bufferUnaligned = tempUnaligned;
bufferPos = 0;
}
else
{
// simply rewind the buffer (if necessary)
rewind();
}
}
// Returns the current buffer capacity in terms of samples
uint FIFOSampleBuffer::getCapacity() const
{
return sizeInBytes / (channels * sizeof(SAMPLETYPE));
}
// Returns the number of samples currently in the buffer
uint FIFOSampleBuffer::numSamples() const
{
return samplesInBuffer;
}
// Output samples from beginning of the sample buffer. Copies demanded number
// of samples to output and removes them from the sample buffer. If there
// are less than 'numsample' samples in the buffer, returns all available.
//
// Returns number of samples copied.
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
{
uint num;
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
return receiveSamples(num);
}
// Removes samples from the beginning of the sample buffer without copying them
// anywhere. Used to reduce the number of samples in the buffer, when accessing
// the sample buffer with the 'ptrBegin' function.
uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
{
if (maxSamples >= samplesInBuffer)
{
uint temp;
temp = samplesInBuffer;
samplesInBuffer = 0;
return temp;
}
samplesInBuffer -= maxSamples;
bufferPos += maxSamples;
return maxSamples;
}
// Returns nonzero if the sample buffer is empty
int FIFOSampleBuffer::isEmpty() const
{
return (samplesInBuffer == 0) ? 1 : 0;
}
// Clears the sample buffer
void FIFOSampleBuffer::clear()
{
samplesInBuffer = 0;
bufferPos = 0;
}
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
{
if (numSamples < samplesInBuffer)
{
samplesInBuffer = numSamples;
}
return samplesInBuffer;
}
////////////////////////////////////////////////////////////////////////////////
///
/// A buffer class for temporarily storaging sound samples, operates as a
/// first-in-first-out pipe.
///
/// Samples are added to the end of the sample buffer with the 'putSamples'
/// function, and are received from the beginning of the buffer by calling
/// the 'receiveSamples' function. The class automatically removes the
/// outputted samples from the buffer, as well as grows the buffer size
/// whenever necessary.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>
#include "FIFOSampleBuffer.h"
using namespace soundtouch;
// Constructor
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
{
assert(numChannels > 0);
sizeInBytes = 0; // reasonable initial value
buffer = nullptr;
bufferUnaligned = nullptr;
samplesInBuffer = 0;
bufferPos = 0;
channels = (uint)numChannels;
ensureCapacity(32); // allocate initial capacity
}
// destructor
FIFOSampleBuffer::~FIFOSampleBuffer()
{
delete[] bufferUnaligned;
bufferUnaligned = nullptr;
buffer = nullptr;
}
// Sets number of channels, 1 = mono, 2 = stereo
void FIFOSampleBuffer::setChannels(int numChannels)
{
uint usedBytes;
if (!verifyNumberOfChannels(numChannels)) return;
usedBytes = channels * samplesInBuffer;
channels = (uint)numChannels;
samplesInBuffer = usedBytes / channels;
}
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
// zeroes this pointer by copying samples from the 'bufferPos' pointer
// location on to the beginning of the buffer.
void FIFOSampleBuffer::rewind()
{
if (buffer && bufferPos)
{
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
bufferPos = 0;
}
}
// Adds 'numSamples' pcs of samples from the 'samples' memory position to
// the sample buffer.
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
{
memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
samplesInBuffer += nSamples;
}
// Increases the number of samples in the buffer without copying any actual
// samples.
//
// This function is used to update the number of samples in the sample buffer
// when accessing the buffer directly with 'ptrEnd' function. Please be
// careful though!
void FIFOSampleBuffer::putSamples(uint nSamples)
{
uint req;
req = samplesInBuffer + nSamples;
ensureCapacity(req);
samplesInBuffer += nSamples;
}
// Returns a pointer to the end of the used part of the sample buffer (i.e.
// where the new samples are to be inserted). This function may be used for
// inserting new samples into the sample buffer directly. Please be careful!
//
// Parameter 'slackCapacity' tells the function how much free capacity (in
// terms of samples) there _at least_ should be, in order to the caller to
// successfully insert all the required samples to the buffer. When necessary,
// the function grows the buffer size to comply with this requirement.
//
// When using this function as means for inserting new samples, also remember
// to increase the sample count afterwards, by calling the
// 'putSamples(numSamples)' function.
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
{
ensureCapacity(samplesInBuffer + slackCapacity);
return buffer + samplesInBuffer * channels;
}
// Returns a pointer to the beginning of the currently non-outputted samples.
// This function is provided for accessing the output samples directly.
// Please be careful!
//
// When using this function to output samples, also remember to 'remove' the
// outputted samples from the buffer by calling the
// 'receiveSamples(numSamples)' function
SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
{
assert(buffer);
return buffer + bufferPos * channels;
}
// Ensures that the buffer has enough capacity, i.e. space for _at least_
// 'capacityRequirement' number of samples. The buffer is grown in steps of
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
// as well as to round the buffer size up to the virtual memory page size.
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
{
SAMPLETYPE *tempUnaligned, *temp;
if (capacityRequirement > getCapacity())
{
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
assert(sizeInBytes % 2 == 0);
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
if (tempUnaligned == nullptr)
{
ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
}
// Align the buffer to begin at 16byte cache line boundary for optimal performance
temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned);
if (samplesInBuffer)
{
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
}
delete[] bufferUnaligned;
buffer = temp;
bufferUnaligned = tempUnaligned;
bufferPos = 0;
}
else
{
// simply rewind the buffer (if necessary)
rewind();
}
}
// Returns the current buffer capacity in terms of samples
uint FIFOSampleBuffer::getCapacity() const
{
return sizeInBytes / (channels * sizeof(SAMPLETYPE));
}
// Returns the number of samples currently in the buffer
uint FIFOSampleBuffer::numSamples() const
{
return samplesInBuffer;
}
// Output samples from beginning of the sample buffer. Copies demanded number
// of samples to output and removes them from the sample buffer. If there
// are less than 'numsample' samples in the buffer, returns all available.
//
// Returns number of samples copied.
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
{
uint num;
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
return receiveSamples(num);
}
// Removes samples from the beginning of the sample buffer without copying them
// anywhere. Used to reduce the number of samples in the buffer, when accessing
// the sample buffer with the 'ptrBegin' function.
uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
{
if (maxSamples >= samplesInBuffer)
{
uint temp;
temp = samplesInBuffer;
samplesInBuffer = 0;
return temp;
}
samplesInBuffer -= maxSamples;
bufferPos += maxSamples;
return maxSamples;
}
// Returns nonzero if the sample buffer is empty
int FIFOSampleBuffer::isEmpty() const
{
return (samplesInBuffer == 0) ? 1 : 0;
}
// Clears the sample buffer
void FIFOSampleBuffer::clear()
{
samplesInBuffer = 0;
bufferPos = 0;
}
/// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples
uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
{
if (numSamples < samplesInBuffer)
{
samplesInBuffer = numSamples;
}
return samplesInBuffer;
}
/// Add silence to end of buffer
void FIFOSampleBuffer::addSilent(uint nSamples)
{
memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels);
samplesInBuffer += nSamples;
}

View File

@ -1,259 +1,314 @@
////////////////////////////////////////////////////////////////////////////////
///
/// General FIR digital filter routines with MMX optimization.
///
/// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "FIRFilter.h"
#include "cpu_detect.h"
using namespace soundtouch;
/*****************************************************************************
*
* Implementation of the class 'FIRFilter'
*
*****************************************************************************/
FIRFilter::FIRFilter()
{
resultDivFactor = 0;
resultDivider = 0;
length = 0;
lengthDiv8 = 0;
filterCoeffs = NULL;
}
FIRFilter::~FIRFilter()
{
delete[] filterCoeffs;
}
// Usual C-version of the filter routine for stereo sound
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
uint i, j, end;
LONG_SAMPLETYPE suml, sumr;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0);
assert(src != NULL);
assert(dest != NULL);
assert(filterCoeffs != NULL);
end = 2 * (numSamples - length);
for (j = 0; j < end; j += 2)
{
const SAMPLETYPE *ptr;
suml = sumr = 0;
ptr = src + j;
for (i = 0; i < length; i += 4)
{
// loop is unrolled by factor of 4 here for efficiency
suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +
ptr[2 * i + 2] * filterCoeffs[i + 1] +
ptr[2 * i + 4] * filterCoeffs[i + 2] +
ptr[2 * i + 6] * filterCoeffs[i + 3];
sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +
ptr[2 * i + 3] * filterCoeffs[i + 1] +
ptr[2 * i + 5] * filterCoeffs[i + 2] +
ptr[2 * i + 7] * filterCoeffs[i + 3];
}
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
suml >>= resultDivFactor;
sumr >>= resultDivFactor;
// saturate to 16 bit integer limits
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
// saturate to 16 bit integer limits
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
#else
suml *= dScaler;
sumr *= dScaler;
#endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)suml;
dest[j + 1] = (SAMPLETYPE)sumr;
}
return numSamples - length;
}
// Usual C-version of the filter routine for mono sound
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
uint i, j, end;
LONG_SAMPLETYPE sum;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0);
end = numSamples - length;
for (j = 0; j < end; j ++)
{
sum = 0;
for (i = 0; i < length; i += 4)
{
// loop is unrolled by factor of 4 here for efficiency
sum += src[i + 0] * filterCoeffs[i + 0] +
src[i + 1] * filterCoeffs[i + 1] +
src[i + 2] * filterCoeffs[i + 2] +
src[i + 3] * filterCoeffs[i + 3];
}
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
sum >>= resultDivFactor;
// saturate to 16 bit integer limits
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
#else
sum *= dScaler;
#endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)sum;
src ++;
}
return end;
}
// Set filter coeffiecients and length.
//
// Throws an exception if filter length isn't divisible by 8
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
{
assert(newLength > 0);
if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8");
lengthDiv8 = newLength / 8;
length = lengthDiv8 * 8;
assert(length == newLength);
resultDivFactor = uResultDivFactor;
resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);
delete[] filterCoeffs;
filterCoeffs = new SAMPLETYPE[length];
memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
}
uint FIRFilter::getLength() const
{
return length;
}
// Applies the filter to the given sequence of samples.
//
// Note : The amount of outputted samples is by value of 'filter_length'
// smaller than the amount of input samples.
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
{
assert(numChannels == 1 || numChannels == 2);
assert(length > 0);
assert(lengthDiv8 * 8 == length);
if (numSamples < length) return 0;
if (numChannels == 2)
{
return evaluateFilterStereo(dest, src, numSamples);
} else {
return evaluateFilterMono(dest, src, numSamples);
}
}
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX-capable CPU available or not.
void * FIRFilter::operator new(size_t s)
{
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
return newInstance();
}
FIRFilter * FIRFilter::newInstance()
{
uint uExtensions;
uExtensions = detectCPUextensions();
// Check if MMX/SSE instruction set extensions supported by CPU
#ifdef SOUNDTOUCH_ALLOW_MMX
// MMX routines available only with integer sample types
if (uExtensions & SUPPORT_MMX)
{
return ::new FIRFilterMMX;
}
else
#endif // SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE
if (uExtensions & SUPPORT_SSE)
{
// SSE support
return ::new FIRFilterSSE;
}
else
#endif // SOUNDTOUCH_ALLOW_SSE
{
// ISA optimizations not supported, use plain C version
return ::new FIRFilter;
}
}
////////////////////////////////////////////////////////////////////////////////
///
/// General FIR digital filter routines with MMX optimization.
///
/// Notes : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// This source file contains OpenMP optimizations that allow speeding up the
/// corss-correlation algorithm by executing it in several threads / CPU cores
/// in parallel. See the following article link for more detailed discussion
/// about SoundTouch OpenMP optimizations:
/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include "FIRFilter.h"
#include "cpu_detect.h"
using namespace soundtouch;
/*****************************************************************************
*
* Implementation of the class 'FIRFilter'
*
*****************************************************************************/
FIRFilter::FIRFilter()
{
resultDivFactor = 0;
length = 0;
lengthDiv8 = 0;
filterCoeffs = nullptr;
filterCoeffsStereo = nullptr;
}
FIRFilter::~FIRFilter()
{
delete[] filterCoeffs;
delete[] filterCoeffsStereo;
}
// Usual C-version of the filter routine for stereo sound
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
int j, end;
// hint compiler autovectorization that loop length is divisible by 8
uint ilength = length & -8;
assert((length != 0) && (length == ilength) && (src != nullptr) && (dest != nullptr) && (filterCoeffs != nullptr));
assert(numSamples > ilength);
end = 2 * (numSamples - ilength);
#pragma omp parallel for
for (j = 0; j < end; j += 2)
{
const SAMPLETYPE *ptr;
LONG_SAMPLETYPE suml, sumr;
suml = sumr = 0;
ptr = src + j;
for (uint i = 0; i < ilength; i ++)
{
suml += ptr[2 * i] * filterCoeffsStereo[2 * i];
sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1];
}
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
suml >>= resultDivFactor;
sumr >>= resultDivFactor;
// saturate to 16 bit integer limits
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
// saturate to 16 bit integer limits
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
#endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)suml;
dest[j + 1] = (SAMPLETYPE)sumr;
}
return numSamples - ilength;
}
// Usual C-version of the filter routine for mono sound
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{
int j, end;
// hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8;
assert(ilength != 0);
end = numSamples - ilength;
#pragma omp parallel for
for (j = 0; j < end; j ++)
{
const SAMPLETYPE *pSrc = src + j;
LONG_SAMPLETYPE sum;
int i;
sum = 0;
for (i = 0; i < ilength; i ++)
{
sum += pSrc[i] * filterCoeffs[i];
}
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
sum >>= resultDivFactor;
// saturate to 16 bit integer limits
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
#endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)sum;
}
return end;
}
uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
{
int j, end;
assert(length != 0);
assert(src != nullptr);
assert(dest != nullptr);
assert(filterCoeffs != nullptr);
assert(numChannels <= SOUNDTOUCH_MAX_CHANNELS);
// hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8;
end = numChannels * (numSamples - ilength);
#pragma omp parallel for
for (j = 0; j < end; j += numChannels)
{
const SAMPLETYPE *ptr;
LONG_SAMPLETYPE sums[16];
uint c;
int i;
for (c = 0; c < numChannels; c ++)
{
sums[c] = 0;
}
ptr = src + j;
for (i = 0; i < ilength; i ++)
{
SAMPLETYPE coef=filterCoeffs[i];
for (c = 0; c < numChannels; c ++)
{
sums[c] += ptr[0] * coef;
ptr ++;
}
}
for (c = 0; c < numChannels; c ++)
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
sums[c] >>= resultDivFactor;
#endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j+c] = (SAMPLETYPE)sums[c];
}
}
return numSamples - ilength;
}
// Set filter coeffiecients and length.
//
// Throws an exception if filter length isn't divisible by 8
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
{
assert(newLength > 0);
if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8");
lengthDiv8 = newLength / 8;
length = lengthDiv8 * 8;
assert(length == newLength);
resultDivFactor = uResultDivFactor;
delete[] filterCoeffs;
filterCoeffs = new SAMPLETYPE[length];
delete[] filterCoeffsStereo;
filterCoeffsStereo = new SAMPLETYPE[length*2];
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// scale coefficients already here if using floating samples
const double scale = ::pow(0.5, (int)resultDivFactor);;
#else
const short scale = 1;
#endif
for (uint i = 0; i < length; i ++)
{
filterCoeffs[i] = (SAMPLETYPE)(coeffs[i] * scale);
// create also stereo set of filter coefficients: this allows compiler
// to autovectorize filter evaluation much more efficiently
filterCoeffsStereo[2 * i] = (SAMPLETYPE)(coeffs[i] * scale);
filterCoeffsStereo[2 * i + 1] = (SAMPLETYPE)(coeffs[i] * scale);
}
}
uint FIRFilter::getLength() const
{
return length;
}
// Applies the filter to the given sequence of samples.
//
// Note : The amount of outputted samples is by value of 'filter_length'
// smaller than the amount of input samples.
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
{
assert(length > 0);
assert(lengthDiv8 * 8 == length);
if (numSamples < length) return 0;
#ifndef USE_MULTICH_ALWAYS
if (numChannels == 1)
{
return evaluateFilterMono(dest, src, numSamples);
}
else if (numChannels == 2)
{
return evaluateFilterStereo(dest, src, numSamples);
}
else
#endif // USE_MULTICH_ALWAYS
{
assert(numChannels > 0);
return evaluateFilterMulti(dest, src, numSamples, numChannels);
}
}
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX-capable CPU available or not.
void * FIRFilter::operator new(size_t)
{
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
return newInstance();
}
FIRFilter * FIRFilter::newInstance()
{
uint uExtensions;
uExtensions = detectCPUextensions();
(void)uExtensions;
// Check if MMX/SSE instruction set extensions supported by CPU
#ifdef SOUNDTOUCH_ALLOW_MMX
// MMX routines available only with integer sample types
if (uExtensions & SUPPORT_MMX)
{
return ::new FIRFilterMMX;
}
else
#endif // SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE
if (uExtensions & SUPPORT_SSE)
{
// SSE support
return ::new FIRFilterSSE;
}
else
#endif // SOUNDTOUCH_ALLOW_SSE
{
// ISA optimizations not supported, use plain C version
return ::new FIRFilter;
}
}

View File

@ -1,145 +1,137 @@
////////////////////////////////////////////////////////////////////////////////
///
/// General FIR digital filter routines with MMX optimization.
///
/// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIRFilter_H
#define FIRFilter_H
#include <stddef.h>
#include "STTypes.h"
namespace soundtouch
{
class FIRFilter
{
protected:
// Number of FIR filter taps
uint length;
// Number of FIR filter taps divided by 8
uint lengthDiv8;
// Result divider factor in 2^k format
uint resultDivFactor;
// Result divider value.
SAMPLETYPE resultDivider;
// Memory for filter coefficients
SAMPLETYPE *filterCoeffs;
virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) const;
virtual uint evaluateFilterMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) const;
public:
FIRFilter();
virtual ~FIRFilter();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX-capable CPU available or not.
static void * operator new(size_t s);
static FIRFilter *newInstance();
/// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter_length'
/// smaller than the amount of input samples.
///
/// \return Number of samples copied to 'dest'.
uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples,
uint numChannels) const;
uint getLength() const;
virtual void setCoefficients(const SAMPLETYPE *coeffs,
uint newLength,
uint uResultDivFactor);
};
// Optional subclasses that implement CPU-specific optimizations:
#ifdef SOUNDTOUCH_ALLOW_MMX
/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
class FIRFilterMMX : public FIRFilter
{
protected:
short *filterCoeffsUnalign;
short *filterCoeffsAlign;
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const;
public:
FIRFilterMMX();
~FIRFilterMMX();
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor);
};
#endif // SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE
/// Class that implements SSE optimized functions exclusive for floating point samples type.
class FIRFilterSSE : public FIRFilter
{
protected:
float *filterCoeffsUnalign;
float *filterCoeffsAlign;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
public:
FIRFilterSSE();
~FIRFilterSSE();
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
};
#endif // SOUNDTOUCH_ALLOW_SSE
}
#endif // FIRFilter_H
////////////////////////////////////////////////////////////////////////////////
///
/// General FIR digital filter routines with MMX optimization.
///
/// Note : MMX optimized functions reside in a separate, platform-specific file,
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef FIRFilter_H
#define FIRFilter_H
#include <stddef.h>
#include "STTypes.h"
namespace soundtouch
{
class FIRFilter
{
protected:
// Number of FIR filter taps
uint length;
// Number of FIR filter taps divided by 8
uint lengthDiv8;
// Result divider factor in 2^k format
uint resultDivFactor;
// Memory for filter coefficients
SAMPLETYPE *filterCoeffs;
SAMPLETYPE *filterCoeffsStereo;
virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) const;
virtual uint evaluateFilterMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) const;
virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels);
public:
FIRFilter();
virtual ~FIRFilter();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX-capable CPU available or not.
static void * operator new(size_t s);
static FIRFilter *newInstance();
/// Applies the filter to the given sequence of samples.
/// Note : The amount of outputted samples is by value of 'filter_length'
/// smaller than the amount of input samples.
///
/// \return Number of samples copied to 'dest'.
uint evaluate(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples,
uint numChannels);
uint getLength() const;
virtual void setCoefficients(const SAMPLETYPE *coeffs,
uint newLength,
uint uResultDivFactor);
};
// Optional subclasses that implement CPU-specific optimizations:
#ifdef SOUNDTOUCH_ALLOW_MMX
/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
class FIRFilterMMX : public FIRFilter
{
protected:
short *filterCoeffsUnalign;
short *filterCoeffsAlign;
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const override;
public:
FIRFilterMMX();
~FIRFilterMMX();
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) override;
};
#endif // SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE
/// Class that implements SSE optimized functions exclusive for floating point samples type.
class FIRFilterSSE : public FIRFilter
{
protected:
float *filterCoeffsUnalign;
float *filterCoeffsAlign;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const override;
public:
FIRFilterSSE();
~FIRFilterSSE();
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) override;
};
#endif // SOUNDTOUCH_ALLOW_SSE
}
#endif // FIRFilter_H

View File

@ -0,0 +1,196 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Cubic interpolation routine.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <stddef.h>
#include <math.h>
#include "InterpolateCubic.h"
#include "STTypes.h"
using namespace soundtouch;
// cubic interpolation coefficients
static const float _coeffs[]=
{ -0.5f, 1.0f, -0.5f, 0.0f,
1.5f, -2.5f, 0.0f, 1.0f,
-1.5f, 2.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f, 0.0f};
InterpolateCubic::InterpolateCubic()
{
fract = 0;
}
void InterpolateCubic::resetRegisters()
{
fract = 0;
}
/// Transpose mono audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeMono(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc,
int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 4;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
float out;
const float x3 = 1.0f;
const float x2 = (float)fract; // x
const float x1 = x2*x2; // x^2
const float x0 = x1*x2; // x^3
float y0, y1, y2, y3;
assert(fract < 1.0);
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3;
y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3;
y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;
y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;
out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3];
pdest[i] = (SAMPLETYPE)out;
i ++;
// update position fraction
fract += rate;
// update whole positions
int whole = (int)fract;
fract -= whole;
psrc += whole;
srcCount += whole;
}
srcSamples = srcCount;
return i;
}
/// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc,
int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 4;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
const float x3 = 1.0f;
const float x2 = (float)fract; // x
const float x1 = x2*x2; // x^2
const float x0 = x1*x2; // x^3
float y0, y1, y2, y3;
float out0, out1;
assert(fract < 1.0);
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3;
y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3;
y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;
y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;
out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6];
out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7];
pdest[2*i] = (SAMPLETYPE)out0;
pdest[2*i+1] = (SAMPLETYPE)out1;
i ++;
// update position fraction
fract += rate;
// update whole positions
int whole = (int)fract;
fract -= whole;
psrc += 2*whole;
srcCount += whole;
}
srcSamples = srcCount;
return i;
}
/// Transpose multi-channel audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples
int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc,
int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 4;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
const float x3 = 1.0f;
const float x2 = (float)fract; // x
const float x1 = x2*x2; // x^2
const float x0 = x1*x2; // x^3
float y0, y1, y2, y3;
assert(fract < 1.0);
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3;
y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3;
y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;
y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;
for (int c = 0; c < numChannels; c ++)
{
float out;
out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels];
pdest[0] = (SAMPLETYPE)out;
pdest ++;
}
i ++;
// update position fraction
fract += rate;
// update whole positions
int whole = (int)fract;
fract -= whole;
psrc += numChannels*whole;
srcCount += whole;
}
srcSamples = srcCount;
return i;
}

View File

@ -0,0 +1,69 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Cubic interpolation routine.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _InterpolateCubic_H_
#define _InterpolateCubic_H_
#include "RateTransposer.h"
#include "STTypes.h"
namespace soundtouch
{
class InterpolateCubic : public TransposerBase
{
protected:
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
double fract;
public:
InterpolateCubic();
virtual void resetRegisters() override;
virtual int getLatency() const override
{
return 1;
}
};
}
#endif

View File

@ -0,0 +1,296 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Linear interpolation algorithm.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <assert.h>
#include <stdlib.h>
#include "InterpolateLinear.h"
using namespace soundtouch;
//////////////////////////////////////////////////////////////////////////////
//
// InterpolateLinearInteger - integer arithmetic implementation
//
/// fixed-point interpolation routine precision
#define SCALE 65536
// Constructor
InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase()
{
// Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions.
resetRegisters();
setRate(1.0f);
}
void InterpolateLinearInteger::resetRegisters()
{
iFract = 0;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 1;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
LONG_SAMPLETYPE temp;
assert(iFract < SCALE);
temp = (SCALE - iFract) * src[0] + iFract * src[1];
dest[i] = (SAMPLETYPE)(temp / SCALE);
i++;
iFract += iRate;
int iWhole = iFract / SCALE;
iFract -= iWhole * SCALE;
srcCount += iWhole;
src += iWhole;
}
srcSamples = srcCount;
return i;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Stereo' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 1;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
LONG_SAMPLETYPE temp0;
LONG_SAMPLETYPE temp1;
assert(iFract < SCALE);
temp0 = (SCALE - iFract) * src[0] + iFract * src[2];
temp1 = (SCALE - iFract) * src[1] + iFract * src[3];
dest[0] = (SAMPLETYPE)(temp0 / SCALE);
dest[1] = (SAMPLETYPE)(temp1 / SCALE);
dest += 2;
i++;
iFract += iRate;
int iWhole = iFract / SCALE;
iFract -= iWhole * SCALE;
srcCount += iWhole;
src += 2*iWhole;
}
srcSamples = srcCount;
return i;
}
int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 1;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
LONG_SAMPLETYPE temp, vol1;
assert(iFract < SCALE);
vol1 = (LONG_SAMPLETYPE)(SCALE - iFract);
for (int c = 0; c < numChannels; c ++)
{
temp = vol1 * src[c] + iFract * src[c + numChannels];
dest[0] = (SAMPLETYPE)(temp / SCALE);
dest ++;
}
i++;
iFract += iRate;
int iWhole = iFract / SCALE;
iFract -= iWhole * SCALE;
srcCount += iWhole;
src += iWhole * numChannels;
}
srcSamples = srcCount;
return i;
}
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates.
void InterpolateLinearInteger::setRate(double newRate)
{
iRate = (int)(newRate * SCALE + 0.5);
TransposerBase::setRate(newRate);
}
//////////////////////////////////////////////////////////////////////////////
//
// InterpolateLinearFloat - floating point arithmetic implementation
//
//////////////////////////////////////////////////////////////////////////////
// Constructor
InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase()
{
// Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions.
resetRegisters();
setRate(1.0);
}
void InterpolateLinearFloat::resetRegisters()
{
fract = 0;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 1;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
double out;
assert(fract < 1.0);
out = (1.0 - fract) * src[0] + fract * src[1];
dest[i] = (SAMPLETYPE)out;
i ++;
// update position fraction
fract += rate;
// update whole positions
int whole = (int)fract;
fract -= whole;
src += whole;
srcCount += whole;
}
srcSamples = srcCount;
return i;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 1;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
double out0, out1;
assert(fract < 1.0);
out0 = (1.0 - fract) * src[0] + fract * src[2];
out1 = (1.0 - fract) * src[1] + fract * src[3];
dest[2*i] = (SAMPLETYPE)out0;
dest[2*i+1] = (SAMPLETYPE)out1;
i ++;
// update position fraction
fract += rate;
// update whole positions
int whole = (int)fract;
fract -= whole;
src += 2*whole;
srcCount += whole;
}
srcSamples = srcCount;
return i;
}
int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 1;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
float temp, vol1, fract_float;
vol1 = (float)(1.0 - fract);
fract_float = (float)fract;
for (int c = 0; c < numChannels; c ++)
{
temp = vol1 * src[c] + fract_float * src[c + numChannels];
*dest = (SAMPLETYPE)temp;
dest ++;
}
i++;
fract += rate;
int iWhole = (int)fract;
fract -= iWhole;
srcCount += iWhole;
src += iWhole * numChannels;
}
srcSamples = srcCount;
return i;
}

View File

@ -0,0 +1,98 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Linear interpolation routine.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _InterpolateLinear_H_
#define _InterpolateLinear_H_
#include "RateTransposer.h"
#include "STTypes.h"
namespace soundtouch
{
/// Linear transposer class that uses integer arithmetic
class InterpolateLinearInteger : public TransposerBase
{
protected:
int iFract;
int iRate;
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override;
public:
InterpolateLinearInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(double newRate) override;
virtual void resetRegisters() override;
virtual int getLatency() const override
{
return 0;
}
};
/// Linear transposer class that uses floating point arithmetic
class InterpolateLinearFloat : public TransposerBase
{
protected:
double fract;
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples);
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);
public:
InterpolateLinearFloat();
virtual void resetRegisters();
int getLatency() const
{
return 0;
}
};
}
#endif

View File

@ -0,0 +1,181 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation
/// with kaiser window.
///
/// Notice. This algorithm is remarkably much heavier than linear or cubic
/// interpolation, and not remarkably better than cubic algorithm. Thus mostly
/// for experimental purposes
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <math.h>
#include "InterpolateShannon.h"
#include "STTypes.h"
using namespace soundtouch;
/// Kaiser window with beta = 2.0
/// Values scaled down by 5% to avoid overflows
static const double _kaiser8[8] =
{
0.41778693317814,
0.64888025049173,
0.83508562409944,
0.93887857733412,
0.93887857733412,
0.83508562409944,
0.64888025049173,
0.41778693317814
};
InterpolateShannon::InterpolateShannon()
{
fract = 0;
}
void InterpolateShannon::resetRegisters()
{
fract = 0;
}
#define PI 3.1415926536
#define sinc(x) (sin(PI * (x)) / (PI * (x)))
/// Transpose mono audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeMono(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc,
int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 8;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
double out;
assert(fract < 1.0);
out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0];
out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1];
out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2];
if (fract < 1e-6)
{
out += psrc[3] * _kaiser8[3]; // sinc(0) = 1
}
else
{
out += psrc[3] * sinc(- fract) * _kaiser8[3];
}
out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4];
out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5];
out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6];
out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7];
pdest[i] = (SAMPLETYPE)out;
i ++;
// update position fraction
fract += rate;
// update whole positions
int whole = (int)fract;
fract -= whole;
psrc += whole;
srcCount += whole;
}
srcSamples = srcCount;
return i;
}
/// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest,
const SAMPLETYPE *psrc,
int &srcSamples)
{
int i;
int srcSampleEnd = srcSamples - 8;
int srcCount = 0;
i = 0;
while (srcCount < srcSampleEnd)
{
double out0, out1, w;
assert(fract < 1.0);
w = sinc(-3.0 - fract) * _kaiser8[0];
out0 = psrc[0] * w; out1 = psrc[1] * w;
w = sinc(-2.0 - fract) * _kaiser8[1];
out0 += psrc[2] * w; out1 += psrc[3] * w;
w = sinc(-1.0 - fract) * _kaiser8[2];
out0 += psrc[4] * w; out1 += psrc[5] * w;
w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1
out0 += psrc[6] * w; out1 += psrc[7] * w;
w = sinc( 1.0 - fract) * _kaiser8[4];
out0 += psrc[8] * w; out1 += psrc[9] * w;
w = sinc( 2.0 - fract) * _kaiser8[5];
out0 += psrc[10] * w; out1 += psrc[11] * w;
w = sinc( 3.0 - fract) * _kaiser8[6];
out0 += psrc[12] * w; out1 += psrc[13] * w;
w = sinc( 4.0 - fract) * _kaiser8[7];
out0 += psrc[14] * w; out1 += psrc[15] * w;
pdest[2*i] = (SAMPLETYPE)out0;
pdest[2*i+1] = (SAMPLETYPE)out1;
i ++;
// update position fraction
fract += rate;
// update whole positions
int whole = (int)fract;
fract -= whole;
psrc += 2*whole;
srcCount += whole;
}
srcSamples = srcCount;
return i;
}
/// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeMulti(SAMPLETYPE *,
const SAMPLETYPE *,
int &)
{
// not implemented
assert(false);
return 0;
}

View File

@ -0,0 +1,74 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation
/// with kaiser window.
///
/// Notice. This algorithm is remarkably much heavier than linear or cubic
/// interpolation, and not remarkably better than cubic algorithm. Thus mostly
/// for experimental purposes
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _InterpolateShannon_H_
#define _InterpolateShannon_H_
#include "RateTransposer.h"
#include "STTypes.h"
namespace soundtouch
{
class InterpolateShannon : public TransposerBase
{
protected:
int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) override;
double fract;
public:
InterpolateShannon();
void resetRegisters() override;
virtual int getLatency() const override
{
return 3;
}
};
}
#endif

View File

@ -1,71 +1,74 @@
## Process this file with automake to create Makefile.in
##
## $Id$
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk
# set to something if you want other stuff to be included in the distribution tarball
EXTRA_DIST=SoundTouch.dsp SoundTouch.dsw SoundTouch.sln SoundTouch.vcproj
noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h
lib_LTLIBRARIES=libSoundTouch.la
#
libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp BPMDetect.cpp PeakFinder.cpp
# Compiler flags
AM_CXXFLAGS=-O3 -fcheck-new -I../../include
# Compile the files that need MMX and SSE individually.
libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la
noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la
libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp
libSoundTouchSSE_la_SOURCES=sse_optimized.cpp
# We enable optimizations by default.
# If MMX is supported compile with -mmmx.
# Do not assume -msse is also supported.
if HAVE_MMX
libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS)
else
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
endif
# We enable optimizations by default.
# If SSE is supported compile with -msse.
if HAVE_SSE
libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS)
else
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
endif
# Let the user disable optimizations if he wishes to.
if !X86_OPTIMIZATIONS
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
endif
# other linking flags to add
# noinst_LTLIBRARIES = libSoundTouchOpt.la
# libSoundTouch_la_LIBADD = libSoundTouchOpt.la
# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp
# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include
## Process this file with automake to create Makefile.in
##
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
##
## SoundTouch is free software; you can redistribute it and/or modify it under the
## terms of the GNU General Public License as published by the Free Software
## Foundation; either version 2 of the License, or (at your option) any later
## version.
##
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along with
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
## Place - Suite 330, Boston, MA 02111-1307, USA
include $(top_srcdir)/config/am_include.mk
# set to something if you want other stuff to be included in the distribution tarball
EXTRA_DIST=SoundTouch.sln SoundTouch.vcxproj
noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h \
InterpolateCubic.h InterpolateLinear.h InterpolateShannon.h
lib_LTLIBRARIES=libSoundTouch.la
#
libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp \
RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp \
BPMDetect.cpp PeakFinder.cpp InterpolateLinear.cpp InterpolateCubic.cpp \
InterpolateShannon.cpp
# Compiler flags
#AM_CXXFLAGS+=
# Compile the files that need MMX and SSE individually.
libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la
noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la
libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp
libSoundTouchSSE_la_SOURCES=sse_optimized.cpp
# We enable optimizations by default.
# If MMX is supported compile with -mmmx.
# Do not assume -msse is also supported.
if HAVE_MMX
libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS)
else
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
endif
# We enable optimizations by default.
# If SSE is supported compile with -msse.
if HAVE_SSE
libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS)
else
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
endif
# Let the user disable optimizations if he wishes to.
if !X86_OPTIMIZATIONS
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
endif
# Modify the default 0.0.0 to LIB_SONAME.0.0
libSoundTouch_la_LDFLAGS=-version-info @LIB_SONAME@
# other linking flags to add
# noinst_LTLIBRARIES = libSoundTouchOpt.la
# libSoundTouch_la_LIBADD = libSoundTouchOpt.la
# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp
# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include

View File

@ -1,278 +1,277 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Peak detection routine.
///
/// The routine detects highest value on an array of values and calculates the
/// precise peak location as a mass-center of the 'hump' around the peak value.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <math.h>
#include <assert.h>
#include "PeakFinder.h"
using namespace soundtouch;
#define max(x, y) (((x) > (y)) ? (x) : (y))
PeakFinder::PeakFinder()
{
minPos = maxPos = 0;
}
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
int PeakFinder::findTop(const float *data, int peakpos) const
{
int i;
int start, end;
float refvalue;
refvalue = data[peakpos];
// seek within ±10 points
start = peakpos - 10;
if (start < minPos) start = minPos;
end = peakpos + 10;
if (end > maxPos) end = maxPos;
for (i = start; i <= end; i ++)
{
if (data[i] > refvalue)
{
peakpos = i;
refvalue = data[i];
}
}
// failure if max value is at edges of seek range => it's not peak, it's at slope.
if ((peakpos == start) || (peakpos == end)) return 0;
return peakpos;
}
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding
// to direction defined by 'direction' until next 'hump' after minimum value will
// begin
int PeakFinder::findGround(const float *data, int peakpos, int direction) const
{
int lowpos;
int pos;
int climb_count;
float refvalue;
float delta;
climb_count = 0;
refvalue = data[peakpos];
lowpos = peakpos;
pos = peakpos;
while ((pos > minPos+1) && (pos < maxPos-1))
{
int prevpos;
prevpos = pos;
pos += direction;
// calculate derivate
delta = data[pos] - data[prevpos];
if (delta <= 0)
{
// going downhill, ok
if (climb_count)
{
climb_count --; // decrease climb count
}
// check if new minimum found
if (data[pos] < refvalue)
{
// new minimum found
lowpos = pos;
refvalue = data[pos];
}
}
else
{
// going uphill, increase climbing counter
climb_count ++;
if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit
}
}
return lowpos;
}
// Find offset where the value crosses the given level, when starting from 'peakpos' and
// proceeds to direction defined in 'direction'
int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const
{
float peaklevel;
int pos;
peaklevel = data[peakpos];
assert(peaklevel >= level);
pos = peakpos;
while ((pos >= minPos) && (pos < maxPos))
{
if (data[pos + direction] < level) return pos; // crossing found
pos += direction;
}
return -1; // not found
}
// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos'
double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const
{
int i;
float sum;
float wsum;
sum = 0;
wsum = 0;
for (i = firstPos; i <= lastPos; i ++)
{
sum += (float)i * data[i];
wsum += data[i];
}
if (wsum < 1e-6) return 0;
return sum / wsum;
}
/// get exact center of peak near given position by calculating local mass of center
double PeakFinder::getPeakCenter(const float *data, int peakpos) const
{
float peakLevel; // peak level
int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level
float cutLevel; // cutting value
float groundLevel; // ground level of the peak
int gp1, gp2; // bottom positions of the peak 'hump'
// find ground positions.
gp1 = findGround(data, peakpos, -1);
gp2 = findGround(data, peakpos, 1);
groundLevel = 0.5f * (data[gp1] + data[gp2]);
peakLevel = data[peakpos];
// calculate 70%-level of the peak
cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
// find mid-level crossings
crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);
crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);
if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak..
// calculate mass center of the peak surroundings
return calcMassCenter(data, crosspos1, crosspos2);
}
double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
{
int i;
int peakpos; // position of peak level
double highPeak, peak;
this->minPos = aminPos;
this->maxPos = amaxPos;
// find absolute peak
peakpos = minPos;
peak = data[minPos];
for (i = minPos + 1; i < maxPos; i ++)
{
if (data[i] > peak)
{
peak = data[i];
peakpos = i;
}
}
// Calculate exact location of the highest peak mass center
highPeak = getPeakCenter(data, peakpos);
peak = highPeak;
// Now check if the highest peak were in fact harmonic of the true base beat peak
// - sometimes the highest peak can be Nth harmonic of the true base peak yet
// just a slightly higher than the true base
int hp = (int)(highPeak + 0.5);
for (i = 3; i < 10; i ++)
{
double peaktmp, harmonic;
int i1,i2;
harmonic = (double)i * 0.5;
peakpos = (int)(highPeak / harmonic + 0.5f);
if (peakpos < minPos) break;
peakpos = findTop(data, peakpos); // seek true local maximum index
if (peakpos == 0) continue; // no local max here
// calculate mass-center of possible harmonic peak
peaktmp = getPeakCenter(data, peakpos);
// accept harmonic peak if
// (a) it is found
// (b) is within ±4% of the expected harmonic interval
// (c) has at least half x-corr value of the max. peak
double diff = harmonic * peaktmp / highPeak;
if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected
// now compare to highest detected peak
i1 = (int)(highPeak + 0.5);
i2 = (int)(peaktmp + 0.5);
if (data[i2] >= 0.4*data[i1])
{
// The harmonic is at least half as high primary peak,
// thus use the harmonic peak instead
peak = peaktmp;
}
}
return peak;
}
////////////////////////////////////////////////////////////////////////////////
///
/// Peak detection routine.
///
/// The routine detects highest value on an array of values and calculates the
/// precise peak location as a mass-center of the 'hump' around the peak value.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <math.h>
#include <assert.h>
#include "PeakFinder.h"
using namespace soundtouch;
#define max(x, y) (((x) > (y)) ? (x) : (y))
PeakFinder::PeakFinder()
{
minPos = maxPos = 0;
}
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
int PeakFinder::findTop(const float *data, int peakpos) const
{
int i;
int start, end;
float refvalue;
refvalue = data[peakpos];
// seek within ±10 points
start = peakpos - 10;
if (start < minPos) start = minPos;
end = peakpos + 10;
if (end > maxPos) end = maxPos;
for (i = start; i <= end; i ++)
{
if (data[i] > refvalue)
{
peakpos = i;
refvalue = data[i];
}
}
// failure if max value is at edges of seek range => it's not peak, it's at slope.
if ((peakpos == start) || (peakpos == end)) return 0;
return peakpos;
}
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding
// to direction defined by 'direction' until next 'hump' after minimum value will
// begin
int PeakFinder::findGround(const float *data, int peakpos, int direction) const
{
int lowpos;
int pos;
int climb_count;
float refvalue;
float delta;
climb_count = 0;
refvalue = data[peakpos];
lowpos = peakpos;
pos = peakpos;
while ((pos > minPos+1) && (pos < maxPos-1))
{
int prevpos;
prevpos = pos;
pos += direction;
// calculate derivate
delta = data[pos] - data[prevpos];
if (delta <= 0)
{
// going downhill, ok
if (climb_count)
{
climb_count --; // decrease climb count
}
// check if new minimum found
if (data[pos] < refvalue)
{
// new minimum found
lowpos = pos;
refvalue = data[pos];
}
}
else
{
// going uphill, increase climbing counter
climb_count ++;
if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit
}
}
return lowpos;
}
// Find offset where the value crosses the given level, when starting from 'peakpos' and
// proceeds to direction defined in 'direction'
int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const
{
float peaklevel;
int pos;
peaklevel = data[peakpos];
assert(peaklevel >= level);
pos = peakpos;
while ((pos >= minPos) && (pos + direction < maxPos))
{
if (data[pos + direction] < level) return pos; // crossing found
pos += direction;
}
return -1; // not found
}
// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos'
double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const
{
int i;
float sum;
float wsum;
sum = 0;
wsum = 0;
for (i = firstPos; i <= lastPos; i ++)
{
sum += (float)i * data[i];
wsum += data[i];
}
if (wsum < 1e-6) return 0;
return sum / wsum;
}
/// get exact center of peak near given position by calculating local mass of center
double PeakFinder::getPeakCenter(const float *data, int peakpos) const
{
float peakLevel; // peak level
int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level
float cutLevel; // cutting value
float groundLevel; // ground level of the peak
int gp1, gp2; // bottom positions of the peak 'hump'
// find ground positions.
gp1 = findGround(data, peakpos, -1);
gp2 = findGround(data, peakpos, 1);
peakLevel = data[peakpos];
if (gp1 == gp2)
{
// avoid rounding errors when all are equal
assert(gp1 == peakpos);
cutLevel = groundLevel = peakLevel;
} else {
// get average of the ground levels
groundLevel = 0.5f * (data[gp1] + data[gp2]);
// calculate 70%-level of the peak
cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
}
// find mid-level crossings
crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);
crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);
if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak..
// calculate mass center of the peak surroundings
return calcMassCenter(data, crosspos1, crosspos2);
}
double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
{
int i;
int peakpos; // position of peak level
double highPeak, peak;
this->minPos = aminPos;
this->maxPos = amaxPos;
// find absolute peak
peakpos = minPos;
peak = data[minPos];
for (i = minPos + 1; i < maxPos; i ++)
{
if (data[i] > peak)
{
peak = data[i];
peakpos = i;
}
}
// Calculate exact location of the highest peak mass center
highPeak = getPeakCenter(data, peakpos);
peak = highPeak;
// Now check if the highest peak were in fact harmonic of the true base beat peak
// - sometimes the highest peak can be Nth harmonic of the true base peak yet
// just a slightly higher than the true base
for (i = 1; i < 3; i ++)
{
double peaktmp, harmonic;
int i1,i2;
harmonic = (double)pow(2.0, i);
peakpos = (int)(highPeak / harmonic + 0.5f);
if (peakpos < minPos) break;
peakpos = findTop(data, peakpos); // seek true local maximum index
if (peakpos == 0) continue; // no local max here
// calculate mass-center of possible harmonic peak
peaktmp = getPeakCenter(data, peakpos);
// accept harmonic peak if
// (a) it is found
// (b) is within ±4% of the expected harmonic interval
// (c) has at least half x-corr value of the max. peak
double diff = harmonic * peaktmp / highPeak;
if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected
// now compare to highest detected peak
i1 = (int)(highPeak + 0.5);
i2 = (int)(peaktmp + 0.5);
if (data[i2] >= 0.4*data[i1])
{
// The harmonic is at least half as high primary peak,
// thus use the harmonic peak instead
peak = peaktmp;
}
}
return peak;
}

View File

@ -1,97 +1,90 @@
////////////////////////////////////////////////////////////////////////////////
///
/// The routine detects highest value on an array of values and calculates the
/// precise peak location as a mass-center of the 'hump' around the peak value.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _PeakFinder_H_
#define _PeakFinder_H_
namespace soundtouch
{
class PeakFinder
{
protected:
/// Min, max allowed peak positions within the data vector
int minPos, maxPos;
/// Calculates the mass center between given vector items.
double calcMassCenter(const float *data, ///< Data vector.
int firstPos, ///< Index of first vector item beloging to the peak.
int lastPos ///< Index of last vector item beloging to the peak.
) const;
/// Finds the data vector index where the monotoniously decreasing signal crosses the
/// given level.
int findCrossingLevel(const float *data, ///< Data vector.
float level, ///< Goal crossing level.
int peakpos, ///< Peak position index within the data vector.
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
) const;
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
int findTop(const float *data, int peakpos) const;
/// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
/// or left-hand side of the given peak position.
int findGround(const float *data, /// Data vector.
int peakpos, /// Peak position index within the data vector.
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
) const;
/// get exact center of peak near given position by calculating local mass of center
double getPeakCenter(const float *data, int peakpos) const;
public:
/// Constructor.
PeakFinder();
/// Detect exact peak position of the data vector by finding the largest peak 'hump'
/// and calculating the mass-center location of the peak hump.
///
/// \return The location of the largest base harmonic peak hump.
double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has
/// to be at least 'maxPos' items long.
int minPos, ///< Min allowed peak location within the vector data.
int maxPos ///< Max allowed peak location within the vector data.
);
};
}
#endif // _PeakFinder_H_
////////////////////////////////////////////////////////////////////////////////
///
/// The routine detects highest value on an array of values and calculates the
/// precise peak location as a mass-center of the 'hump' around the peak value.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _PeakFinder_H_
#define _PeakFinder_H_
namespace soundtouch
{
class PeakFinder
{
protected:
/// Min, max allowed peak positions within the data vector
int minPos, maxPos;
/// Calculates the mass center between given vector items.
double calcMassCenter(const float *data, ///< Data vector.
int firstPos, ///< Index of first vector item belonging to the peak.
int lastPos ///< Index of last vector item belonging to the peak.
) const;
/// Finds the data vector index where the monotoniously decreasing signal crosses the
/// given level.
int findCrossingLevel(const float *data, ///< Data vector.
float level, ///< Goal crossing level.
int peakpos, ///< Peak position index within the data vector.
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
) const;
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
int findTop(const float *data, int peakpos) const;
/// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
/// or left-hand side of the given peak position.
int findGround(const float *data, /// Data vector.
int peakpos, /// Peak position index within the data vector.
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
) const;
/// get exact center of peak near given position by calculating local mass of center
double getPeakCenter(const float *data, int peakpos) const;
public:
/// Constructor.
PeakFinder();
/// Detect exact peak position of the data vector by finding the largest peak 'hump'
/// and calculating the mass-center location of the peak hump.
///
/// \return The location of the largest base harmonic peak hump.
double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has
/// to be at least 'maxPos' items long.
int minPos, ///< Min allowed peak location within the vector data.
int maxPos ///< Max allowed peak location within the vector data.
);
};
}
#endif // _PeakFinder_H_

View File

@ -1,626 +1,313 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application)
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "RateTransposer.h"
#include "AAFilter.h"
using namespace soundtouch;
/// A linear samplerate transposer class that uses integer arithmetics.
/// for the transposing.
class RateTransposerInteger : public RateTransposer
{
protected:
int iSlopeCount;
int iRate;
SAMPLETYPE sPrevSampleL, sPrevSampleR;
virtual void resetRegisters();
virtual uint transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
virtual uint transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposerInteger();
virtual ~RateTransposerInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(float newRate);
};
/// A linear samplerate transposer class that uses floating point arithmetics
/// for the transposing.
class RateTransposerFloat : public RateTransposer
{
protected:
float fSlopeCount;
SAMPLETYPE sPrevSampleL, sPrevSampleR;
virtual void resetRegisters();
virtual uint transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
virtual uint transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposerFloat();
virtual ~RateTransposerFloat();
};
// Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX/SSE/etc-capable CPU available or not.
void * RateTransposer::operator new(size_t s)
{
ST_THROW_RT_ERROR("Error in RateTransoser::new: don't use \"new TDStretch\" directly, use \"newInstance\" to create a new instance instead!");
return newInstance();
}
RateTransposer *RateTransposer::newInstance()
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
return ::new RateTransposerInteger;
#else
return ::new RateTransposerFloat;
#endif
}
// Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{
numChannels = 2;
bUseAAFilter = TRUE;
fRate = 0;
// Instantiates the anti-alias filter with default tap length
// of 32
pAAFilter = new AAFilter(32);
}
RateTransposer::~RateTransposer()
{
delete pAAFilter;
}
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void RateTransposer::enableAAFilter(BOOL newMode)
{
bUseAAFilter = newMode;
}
/// Returns nonzero if anti-alias filter is enabled.
BOOL RateTransposer::isAAFilterEnabled() const
{
return bUseAAFilter;
}
AAFilter *RateTransposer::getAAFilter()
{
return pAAFilter;
}
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates.
void RateTransposer::setRate(float newRate)
{
double fCutoff;
fRate = newRate;
// design a new anti-alias filter
if (newRate > 1.0f)
{
fCutoff = 0.5f / newRate;
}
else
{
fCutoff = 0.5f * newRate;
}
pAAFilter->setCutoffFreq(fCutoff);
}
// Outputs as many samples of the 'outputBuffer' as possible, and if there's
// any room left, outputs also as many of the incoming samples as possible.
// The goal is to drive the outputBuffer empty.
//
// It's allowed for 'output' and 'input' parameters to point to the same
// memory position.
/*
void RateTransposer::flushStoreBuffer()
{
if (storeBuffer.isEmpty()) return;
outputBuffer.moveSamples(storeBuffer);
}
*/
// Adds 'nSamples' pcs of samples from the 'samples' memory position into
// the input of the object.
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
{
processSamples(samples, nSamples);
}
// Transposes up the sample rate, causing the observed playback 'rate' of the
// sound to decrease
void RateTransposer::upsample(const SAMPLETYPE *src, uint nSamples)
{
uint count, sizeTemp, num;
// If the parameter 'uRate' value is smaller than 'SCALE', first transpose
// the samples and then apply the anti-alias filter to remove aliasing.
// First check that there's enough room in 'storeBuffer'
// (+16 is to reserve some slack in the destination buffer)
sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
// Transpose the samples, store the result into the end of "storeBuffer"
count = transpose(storeBuffer.ptrEnd(sizeTemp), src, nSamples);
storeBuffer.putSamples(count);
// Apply the anti-alias filter to samples in "store output", output the
// result to "dest"
num = storeBuffer.numSamples();
count = pAAFilter->evaluate(outputBuffer.ptrEnd(num),
storeBuffer.ptrBegin(), num, (uint)numChannels);
outputBuffer.putSamples(count);
// Remove the processed samples from "storeBuffer"
storeBuffer.receiveSamples(count);
}
// Transposes down the sample rate, causing the observed playback 'rate' of the
// sound to increase
void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples)
{
uint count, sizeTemp;
// If the parameter 'uRate' value is larger than 'SCALE', first apply the
// anti-alias filter to remove high frequencies (prevent them from folding
// over the lover frequencies), then transpose.
// Add the new samples to the end of the storeBuffer
storeBuffer.putSamples(src, nSamples);
// Anti-alias filter the samples to prevent folding and output the filtered
// data to tempBuffer. Note : because of the FIR filter length, the
// filtering routine takes in 'filter_length' more samples than it outputs.
assert(tempBuffer.isEmpty());
sizeTemp = storeBuffer.numSamples();
count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp),
storeBuffer.ptrBegin(), sizeTemp, (uint)numChannels);
if (count == 0) return;
// Remove the filtered samples from 'storeBuffer'
storeBuffer.receiveSamples(count);
// Transpose the samples (+16 is to reserve some slack in the destination buffer)
sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count);
outputBuffer.putSamples(count);
}
// Transposes sample rate by applying anti-alias filter to prevent folding.
// Returns amount of samples returned in the "dest" buffer.
// The maximum amount of samples that can be returned at a time is set by
// the 'set_returnBuffer_size' function.
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
{
uint count;
uint sizeReq;
if (nSamples == 0) return;
assert(pAAFilter);
// If anti-alias filter is turned off, simply transpose without applying
// the filter
if (bUseAAFilter == FALSE)
{
sizeReq = (uint)((float)nSamples / fRate + 1.0f);
count = transpose(outputBuffer.ptrEnd(sizeReq), src, nSamples);
outputBuffer.putSamples(count);
return;
}
// Transpose with anti-alias filter
if (fRate < 1.0f)
{
upsample(src, nSamples);
}
else
{
downsample(src, nSamples);
}
}
// Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer
inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
if (numChannels == 2)
{
return transposeStereo(dest, src, nSamples);
}
else
{
return transposeMono(dest, src, nSamples);
}
}
// Sets the number of channels, 1 = mono, 2 = stereo
void RateTransposer::setChannels(int nChannels)
{
assert(nChannels > 0);
if (numChannels == nChannels) return;
assert(nChannels == 1 || nChannels == 2);
numChannels = nChannels;
storeBuffer.setChannels(numChannels);
tempBuffer.setChannels(numChannels);
outputBuffer.setChannels(numChannels);
// Inits the linear interpolation registers
resetRegisters();
}
// Clears all the samples in the object
void RateTransposer::clear()
{
outputBuffer.clear();
storeBuffer.clear();
}
// Returns nonzero if there aren't any samples available for outputting.
int RateTransposer::isEmpty() const
{
int res;
res = FIFOProcessor::isEmpty();
if (res == 0) return 0;
return storeBuffer.isEmpty();
}
//////////////////////////////////////////////////////////////////////////////
//
// RateTransposerInteger - integer arithmetic implementation
//
/// fixed-point interpolation routine precision
#define SCALE 65536
// Constructor
RateTransposerInteger::RateTransposerInteger() : RateTransposer()
{
// Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions.
RateTransposerInteger::resetRegisters();
RateTransposerInteger::setRate(1.0f);
}
RateTransposerInteger::~RateTransposerInteger()
{
}
void RateTransposerInteger::resetRegisters()
{
iSlopeCount = 0;
sPrevSampleL =
sPrevSampleR = 0;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
unsigned int i, used;
LONG_SAMPLETYPE temp, vol1;
if (nSamples == 0) return 0; // no samples, no work
used = 0;
i = 0;
// Process the last sample saved from the previous call first...
while (iSlopeCount <= SCALE)
{
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
dest[i] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += iRate;
}
// now always (iSlopeCount > SCALE)
iSlopeCount -= SCALE;
while (1)
{
while (iSlopeCount > SCALE)
{
iSlopeCount -= SCALE;
used ++;
if (used >= nSamples - 1) goto end;
}
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = src[used] * vol1 + iSlopeCount * src[used + 1];
dest[i] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += iRate;
}
end:
// Store the last sample for the next round
sPrevSampleL = src[nSamples - 1];
return i;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Stereo' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
unsigned int srcPos, i, used;
LONG_SAMPLETYPE temp, vol1;
if (nSamples == 0) return 0; // no samples, no work
used = 0;
i = 0;
// Process the last sample saved from the sPrevSampleLious call first...
while (iSlopeCount <= SCALE)
{
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
temp = vol1 * sPrevSampleR + iSlopeCount * src[1];
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += iRate;
}
// now always (iSlopeCount > SCALE)
iSlopeCount -= SCALE;
while (1)
{
while (iSlopeCount > SCALE)
{
iSlopeCount -= SCALE;
used ++;
if (used >= nSamples - 1) goto end;
}
srcPos = 2 * used;
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2];
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3];
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
i++;
iSlopeCount += iRate;
}
end:
// Store the last sample for the next round
sPrevSampleL = src[2 * nSamples - 2];
sPrevSampleR = src[2 * nSamples - 1];
return i;
}
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates.
void RateTransposerInteger::setRate(float newRate)
{
iRate = (int)(newRate * SCALE + 0.5f);
RateTransposer::setRate(newRate);
}
//////////////////////////////////////////////////////////////////////////////
//
// RateTransposerFloat - floating point arithmetic implementation
//
//////////////////////////////////////////////////////////////////////////////
// Constructor
RateTransposerFloat::RateTransposerFloat() : RateTransposer()
{
// Notice: use local function calling syntax for sake of clarity,
// to indicate the fact that C++ constructor can't call virtual functions.
RateTransposerFloat::resetRegisters();
RateTransposerFloat::setRate(1.0f);
}
RateTransposerFloat::~RateTransposerFloat()
{
}
void RateTransposerFloat::resetRegisters()
{
fSlopeCount = 0;
sPrevSampleL =
sPrevSampleR = 0;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
unsigned int i, used;
used = 0;
i = 0;
// Process the last sample saved from the previous call first...
while (fSlopeCount <= 1.0f)
{
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
i++;
fSlopeCount += fRate;
}
fSlopeCount -= 1.0f;
if (nSamples > 1)
{
while (1)
{
while (fSlopeCount > 1.0f)
{
fSlopeCount -= 1.0f;
used ++;
if (used >= nSamples - 1) goto end;
}
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]);
i++;
fSlopeCount += fRate;
}
}
end:
// Store the last sample for the next round
sPrevSampleL = src[nSamples - 1];
return i;
}
// Transposes the sample rate of the given samples using linear interpolation.
// 'Mono' version of the routine. Returns the number of samples returned in
// the "dest" buffer
uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
{
unsigned int srcPos, i, used;
if (nSamples == 0) return 0; // no samples, no work
used = 0;
i = 0;
// Process the last sample saved from the sPrevSampleLious call first...
while (fSlopeCount <= 1.0f)
{
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]);
i++;
fSlopeCount += fRate;
}
// now always (iSlopeCount > 1.0f)
fSlopeCount -= 1.0f;
if (nSamples > 1)
{
while (1)
{
while (fSlopeCount > 1.0f)
{
fSlopeCount -= 1.0f;
used ++;
if (used >= nSamples - 1) goto end;
}
srcPos = 2 * used;
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos]
+ fSlopeCount * src[srcPos + 2]);
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1]
+ fSlopeCount * src[srcPos + 3]);
i++;
fSlopeCount += fRate;
}
}
end:
// Store the last sample for the next round
sPrevSampleL = src[2 * nSamples - 2];
sPrevSampleR = src[2 * nSamples - 1];
return i;
}
////////////////////////////////////////////////////////////////////////////////
///
/// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application)
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include <memory.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "RateTransposer.h"
#include "InterpolateLinear.h"
#include "InterpolateCubic.h"
#include "InterpolateShannon.h"
#include "AAFilter.h"
using namespace soundtouch;
// Define default interpolation algorithm here
TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
// Constructor
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
{
bUseAAFilter =
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
true;
#else
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
false;
#endif
// Instantiates the anti-alias filter
pAAFilter = new AAFilter(64);
pTransposer = TransposerBase::newInstance();
clear();
}
RateTransposer::~RateTransposer()
{
delete pAAFilter;
delete pTransposer;
}
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void RateTransposer::enableAAFilter(bool newMode)
{
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
bUseAAFilter = newMode;
clear();
#endif
}
/// Returns nonzero if anti-alias filter is enabled.
bool RateTransposer::isAAFilterEnabled() const
{
return bUseAAFilter;
}
AAFilter *RateTransposer::getAAFilter()
{
return pAAFilter;
}
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
// iRate, larger faster iRates.
void RateTransposer::setRate(double newRate)
{
double fCutoff;
pTransposer->setRate(newRate);
// design a new anti-alias filter
if (newRate > 1.0)
{
fCutoff = 0.5 / newRate;
}
else
{
fCutoff = 0.5 * newRate;
}
pAAFilter->setCutoffFreq(fCutoff);
}
// Adds 'nSamples' pcs of samples from the 'samples' memory position into
// the input of the object.
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
{
processSamples(samples, nSamples);
}
// Transposes sample rate by applying anti-alias filter to prevent folding.
// Returns amount of samples returned in the "dest" buffer.
// The maximum amount of samples that can be returned at a time is set by
// the 'set_returnBuffer_size' function.
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
{
if (nSamples == 0) return;
// Store samples to input buffer
inputBuffer.putSamples(src, nSamples);
// If anti-alias filter is turned off, simply transpose without applying
// the filter
if (bUseAAFilter == false)
{
(void)pTransposer->transpose(outputBuffer, inputBuffer);
return;
}
assert(pAAFilter);
// Transpose with anti-alias filter
if (pTransposer->rate < 1.0f)
{
// If the parameter 'Rate' value is smaller than 1, first transpose
// the samples and then apply the anti-alias filter to remove aliasing.
// Transpose the samples, store the result to end of "midBuffer"
pTransposer->transpose(midBuffer, inputBuffer);
// Apply the anti-alias filter for transposed samples in midBuffer
pAAFilter->evaluate(outputBuffer, midBuffer);
}
else
{
// If the parameter 'Rate' value is larger than 1, first apply the
// anti-alias filter to remove high frequencies (prevent them from folding
// over the lover frequencies), then transpose.
// Apply the anti-alias filter for samples in inputBuffer
pAAFilter->evaluate(midBuffer, inputBuffer);
// Transpose the AA-filtered samples in "midBuffer"
pTransposer->transpose(outputBuffer, midBuffer);
}
}
// Sets the number of channels, 1 = mono, 2 = stereo
void RateTransposer::setChannels(int nChannels)
{
if (!verifyNumberOfChannels(nChannels) ||
(pTransposer->numChannels == nChannels)) return;
pTransposer->setChannels(nChannels);
inputBuffer.setChannels(nChannels);
midBuffer.setChannels(nChannels);
outputBuffer.setChannels(nChannels);
}
// Clears all the samples in the object
void RateTransposer::clear()
{
outputBuffer.clear();
midBuffer.clear();
inputBuffer.clear();
pTransposer->resetRegisters();
// prefill buffer to avoid losing first samples at beginning of stream
int prefill = getLatency();
inputBuffer.addSilent(prefill);
}
// Returns nonzero if there aren't any samples available for outputting.
int RateTransposer::isEmpty() const
{
int res;
res = FIFOProcessor::isEmpty();
if (res == 0) return 0;
return inputBuffer.isEmpty();
}
/// Return approximate initial input-output latency
int RateTransposer::getLatency() const
{
return pTransposer->getLatency() +
((bUseAAFilter) ? (pAAFilter->getLength() / 2) : 0);
}
//////////////////////////////////////////////////////////////////////////////
//
// TransposerBase - Base class for interpolation
//
// static function to set interpolation algorithm
void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
{
TransposerBase::algorithm = a;
}
// Transposes the sample rate of the given samples using linear interpolation.
// Returns the number of samples returned in the "dest" buffer
int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
{
int numSrcSamples = src.numSamples();
int sizeDemand = (int)((double)numSrcSamples / rate) + 8;
int numOutput;
SAMPLETYPE *psrc = src.ptrBegin();
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
#ifndef USE_MULTICH_ALWAYS
if (numChannels == 1)
{
numOutput = transposeMono(pdest, psrc, numSrcSamples);
}
else if (numChannels == 2)
{
numOutput = transposeStereo(pdest, psrc, numSrcSamples);
}
else
#endif // USE_MULTICH_ALWAYS
{
assert(numChannels > 0);
numOutput = transposeMulti(pdest, psrc, numSrcSamples);
}
dest.putSamples(numOutput);
src.receiveSamples(numSrcSamples);
return numOutput;
}
TransposerBase::TransposerBase()
{
numChannels = 0;
rate = 1.0f;
}
TransposerBase::~TransposerBase()
{
}
void TransposerBase::setChannels(int channels)
{
numChannels = channels;
resetRegisters();
}
void TransposerBase::setRate(double newRate)
{
rate = newRate;
}
// static factory function
TransposerBase *TransposerBase::newInstance()
{
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
// Notice: For integer arithmetic support only linear algorithm (due to simplest calculus)
return ::new InterpolateLinearInteger;
#else
switch (algorithm)
{
case LINEAR:
return new InterpolateLinearFloat;
case CUBIC:
return new InterpolateCubic;
case SHANNON:
return new InterpolateShannon;
default:
assert(false);
return nullptr;
}
#endif
}

View File

@ -1,159 +1,164 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application).
///
/// Use either of the derived classes of 'RateTransposerInteger' or
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
/// algorithm implementation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef RateTransposer_H
#define RateTransposer_H
#include <stddef.h>
#include "AAFilter.h"
#include "FIFOSamplePipe.h"
#include "FIFOSampleBuffer.h"
#include "STTypes.h"
namespace soundtouch
{
/// A common linear samplerate transposer class.
///
/// Note: Use function "RateTransposer::newInstance()" to create a new class
/// instance instead of the "new" operator; that function automatically
/// chooses a correct implementation depending on if integer or floating
/// arithmetics are to be used.
class RateTransposer : public FIFOProcessor
{
protected:
/// Anti-alias filter object
AAFilter *pAAFilter;
float fRate;
int numChannels;
/// Buffer for collecting samples to feed the anti-alias filter between
/// two batches
FIFOSampleBuffer storeBuffer;
/// Buffer for keeping samples between transposing & anti-alias filter
FIFOSampleBuffer tempBuffer;
/// Output sample buffer
FIFOSampleBuffer outputBuffer;
BOOL bUseAAFilter;
virtual void resetRegisters() = 0;
virtual uint transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
virtual uint transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples) = 0;
inline uint transpose(SAMPLETYPE *dest,
const SAMPLETYPE *src,
uint numSamples);
void downsample(const SAMPLETYPE *src,
uint numSamples);
void upsample(const SAMPLETYPE *src,
uint numSamples);
/// Transposes sample rate by applying anti-alias filter to prevent folding.
/// Returns amount of samples returned in the "dest" buffer.
/// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function.
void processSamples(const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposer();
virtual ~RateTransposer();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we're to use integer or floating point arithmetics.
static void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct implementation, depending on if
/// integer ot floating point arithmetics are to be used.
static RateTransposer *newInstance();
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the store buffer object
FIFOSamplePipe *getStore() { return &storeBuffer; };
/// Return anti-alias filter object
AAFilter *getAAFilter();
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void enableAAFilter(BOOL newMode);
/// Returns nonzero if anti-alias filter is enabled.
BOOL isAAFilterEnabled() const;
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(float newRate);
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(int channels);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object.
void putSamples(const SAMPLETYPE *samples, uint numSamples);
/// Clears all the samples in the object
void clear();
/// Returns nonzero if there aren't any samples available for outputting.
int isEmpty() const;
};
}
#endif
////////////////////////////////////////////////////////////////////////////////
///
/// Sample rate transposer. Changes sample rate by using linear interpolation
/// together with anti-alias filtering (first order interpolation with anti-
/// alias filtering should be quite adequate for this application).
///
/// Use either of the derived classes of 'RateTransposerInteger' or
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
/// algorithm implementation.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef RateTransposer_H
#define RateTransposer_H
#include <stddef.h>
#include "AAFilter.h"
#include "FIFOSamplePipe.h"
#include "FIFOSampleBuffer.h"
#include "STTypes.h"
namespace soundtouch
{
/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc)
class TransposerBase
{
public:
enum ALGORITHM {
LINEAR = 0,
CUBIC,
SHANNON
};
protected:
virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) = 0;
virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) = 0;
virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src,
int &srcSamples) = 0;
static ALGORITHM algorithm;
public:
double rate;
int numChannels;
TransposerBase();
virtual ~TransposerBase();
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);
virtual void setRate(double newRate);
virtual void setChannels(int channels);
virtual int getLatency() const = 0;
virtual void resetRegisters() = 0;
// static factory function
static TransposerBase *newInstance();
// static function to set interpolation algorithm
static void setAlgorithm(ALGORITHM a);
};
/// A common linear samplerate transposer class.
///
class RateTransposer : public FIFOProcessor
{
protected:
/// Anti-alias filter object
AAFilter *pAAFilter;
TransposerBase *pTransposer;
/// Buffer for collecting samples to feed the anti-alias filter between
/// two batches
FIFOSampleBuffer inputBuffer;
/// Buffer for keeping samples between transposing & anti-alias filter
FIFOSampleBuffer midBuffer;
/// Output sample buffer
FIFOSampleBuffer outputBuffer;
bool bUseAAFilter;
/// Transposes sample rate by applying anti-alias filter to prevent folding.
/// Returns amount of samples returned in the "dest" buffer.
/// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function.
void processSamples(const SAMPLETYPE *src,
uint numSamples);
public:
RateTransposer();
virtual ~RateTransposer() override;
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Return anti-alias filter object
AAFilter *getAAFilter();
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
void enableAAFilter(bool newMode);
/// Returns nonzero if anti-alias filter is enabled.
bool isAAFilterEnabled() const;
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates.
virtual void setRate(double newRate);
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(int channels);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object.
void putSamples(const SAMPLETYPE *samples, uint numSamples) override;
/// Clears all the samples in the object
void clear() override;
/// Returns nonzero if there aren't any samples available for outputting.
int isEmpty() const override;
/// Return approximate initial input-output latency
int getLatency() const;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,188 +0,0 @@
# Microsoft Developer Studio Project File - Name="SoundTouch" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=SoundTouch - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "SoundTouch.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "SoundTouch.mak" CFG="SoundTouch - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "SoundTouch - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "SoundTouch - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "SoundTouch - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD BASE RSC /l 0x40b /d "NDEBUG"
# ADD RSC /l 0x40b /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Cmds=copy .\Release\SoundTouch.lib ..\..\lib\
# End Special Build Tool
!ELSEIF "$(CFG)" == "SoundTouch - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c
# ADD BASE RSC /l 0x40b /d "_DEBUG"
# ADD RSC /l 0x40b /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"Debug\SoundTouchD.lib"
# Begin Special Build Tool
SOURCE="$(InputPath)"
PostBuild_Cmds=copy .\Debug\SoundTouchD.lib ..\..\lib\
# End Special Build Tool
!ENDIF
# Begin Target
# Name "SoundTouch - Win32 Release"
# Name "SoundTouch - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Group "bpm"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\BPMDetect.cpp
# End Source File
# Begin Source File
SOURCE=.\PeakFinder.cpp
# End Source File
# End Group
# Begin Source File
SOURCE=.\3dnow_win.cpp
# End Source File
# Begin Source File
SOURCE=.\AAFilter.cpp
# End Source File
# Begin Source File
SOURCE=.\cpu_detect_x86_win.cpp
# End Source File
# Begin Source File
SOURCE=.\FIFOSampleBuffer.cpp
# End Source File
# Begin Source File
SOURCE=.\FIRFilter.cpp
# End Source File
# Begin Source File
SOURCE=.\mmx_optimized.cpp
# End Source File
# Begin Source File
SOURCE=.\RateTransposer.cpp
# End Source File
# Begin Source File
SOURCE=.\SoundTouch.cpp
# End Source File
# Begin Source File
SOURCE=.\sse_optimized.cpp
# End Source File
# Begin Source File
SOURCE=.\TDStretch.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\AAFilter.h
# End Source File
# Begin Source File
SOURCE=.\cpu_detect.h
# End Source File
# Begin Source File
SOURCE=..\..\include\FIFOSampleBuffer.h
# End Source File
# Begin Source File
SOURCE=..\..\include\FIFOSamplePipe.h
# End Source File
# Begin Source File
SOURCE=.\FIRFilter.h
# End Source File
# Begin Source File
SOURCE=.\RateTransposer.h
# End Source File
# Begin Source File
SOURCE=..\..\include\SoundTouch.h
# End Source File
# Begin Source File
SOURCE=..\..\include\STTypes.h
# End Source File
# Begin Source File
SOURCE=.\TDStretch.h
# End Source File
# End Group
# End Target
# End Project

View File

@ -1,31 +0,0 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
#
# $Id$
###############################################################################
Project: "SoundTouch"=.\SoundTouch.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@ -1,21 +1,29 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "SoundTouch.vcproj", "{0A626C77-0515-4131-AA80-E0BFFC479FEB}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "SoundTouch.vcxproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32
Release|x64 = Release|x64
ReleaseX64|Win32 = ReleaseX64|Win32
ReleaseX64|x64 = ReleaseX64|x64
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Debug.ActiveCfg = Debug|Win32
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Debug.Build.0 = Debug|Win32
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Release.ActiveCfg = Release|Win32
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Release.Build.0 = Release|Win32
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.ActiveCfg = Debug|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.ActiveCfg = Debug|x64
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.ActiveCfg = Release|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.ActiveCfg = Release|x64
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|Win32.ActiveCfg = ReleaseX64|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|Win32.Build.0 = ReleaseX64|Win32
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|x64.ActiveCfg = ReleaseX64|x64
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|x64.Build.0 = ReleaseX64|x64
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,315 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="SoundTouch"
ProjectGUID="{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
SccProjectName=""
SccLocalPath="">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory=".\Release"
IntermediateDirectory=".\Release"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
StringPooling="TRUE"
RuntimeLibrary="4"
EnableFunctionLevelLinking="TRUE"
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Release/SoundTouch.pch"
AssemblerListingLocation=".\Release/"
ObjectFile=".\Release/"
ProgramDataBaseFileName=".\Release/"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="0"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile=".\Release\SoundTouch.lib"
SuppressStartupBanner="TRUE"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy .\Release\SoundTouch.lib ..\..\lib\"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1035"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Debug|Win32"
OutputDirectory=".\Debug"
IntermediateDirectory=".\Debug"
ConfigurationType="4"
UseOfMFC="0"
ATLMinimizesCRunTimeLibraryUsage="FALSE"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="..\..\include"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
BasicRuntimeChecks="3"
RuntimeLibrary="5"
UsePrecompiledHeader="2"
PrecompiledHeaderFile=".\Debug/SoundTouch.pch"
AssemblerListingLocation=".\Debug/"
ObjectFile=".\Debug/"
ProgramDataBaseFileName=".\Debug/"
BrowseInformation="1"
WarningLevel="3"
SuppressStartupBanner="TRUE"
DebugInformationFormat="4"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="Debug\SoundTouchD.lib"
SuppressStartupBanner="TRUE"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy .\Debug\SoundTouchD.lib ..\..\lib\"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1035"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
<File
RelativePath="AAFilter.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\cpu_detect_x86.cpp">
</File>
<File
RelativePath="FIFOSampleBuffer.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="FIRFilter.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\mmx_optimized.cpp">
</File>
<File
RelativePath="RateTransposer.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath="SoundTouch.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\sse_optimized.cpp">
</File>
<File
RelativePath="TDStretch.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""/>
</FileConfiguration>
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=""
PreprocessorDefinitions=""
BasicRuntimeChecks="3"
BrowseInformation="1"/>
</FileConfiguration>
</File>
<Filter
Name="bpm"
Filter="">
<File
RelativePath=".\BPMDetect.cpp">
</File>
<File
RelativePath=".\PeakFinder.cpp">
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl">
<File
RelativePath="AAFilter.h">
</File>
<File
RelativePath="..\..\include\BPMDetect.h">
</File>
<File
RelativePath="cpu_detect.h">
</File>
<File
RelativePath="..\..\include\FIFOSampleBuffer.h">
</File>
<File
RelativePath="..\..\include\FIFOSamplePipe.h">
</File>
<File
RelativePath="FIRFilter.h">
</File>
<File
RelativePath=".\PeakFinder.h">
</File>
<File
RelativePath="RateTransposer.h">
</File>
<File
RelativePath="..\..\include\SoundTouch.h">
</File>
<File
RelativePath="..\..\include\STTypes.h">
</File>
<File
RelativePath="TDStretch.h">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,342 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{68A5DD20-7057-448B-8FE0-B6AC8D205509}</ProjectGuid>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)_x64</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)D</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)D_x64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<Optimization>Full</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeader />
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat />
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
<PostBuildEvent>
<Command>if not exist ..\..\lib mkdir ..\..\lib
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Full</Optimization>
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>true</StringPooling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<FunctionLevelLinking>true</FunctionLevelLinking>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeader />
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat />
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>
</EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
<PostBuildEvent>
<Command>if not exist ..\..\lib mkdir ..\..\lib
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeader />
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
<PostBuildEvent>
<Command>if not exist ..\..\lib mkdir ..\..\lib
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl>
<TargetEnvironment>X64</TargetEnvironment>
</Midl>
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<FloatingPointModel>Fast</FloatingPointModel>
<PrecompiledHeader />
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>
</EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<Culture>0x040b</Culture>
</ResourceCompile>
<Lib>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner>
</Lib>
<PostBuildEvent>
<Command>if not exist ..\..\lib mkdir ..\..\lib
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AAFilter.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="BPMDetect.cpp">
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4996</DisableSpecificWarnings>
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4996</DisableSpecificWarnings>
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4996</DisableSpecificWarnings>
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4996</DisableSpecificWarnings>
</ClCompile>
<ClCompile Include="cpu_detect_x86.cpp" />
<ClCompile Include="FIFOSampleBuffer.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="FIRFilter.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="InterpolateCubic.cpp" />
<ClCompile Include="InterpolateLinear.cpp" />
<ClCompile Include="InterpolateShannon.cpp" />
<ClCompile Include="mmx_optimized.cpp" />
<ClCompile Include="PeakFinder.cpp" />
<ClCompile Include="RateTransposer.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="SoundTouch.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
<ClCompile Include="sse_optimized.cpp" />
<ClCompile Include="TDStretch.cpp">
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\BPMDetect.h" />
<ClInclude Include="..\..\include\FIFOSampleBuffer.h" />
<ClInclude Include="..\..\include\FIFOSamplePipe.h" />
<ClInclude Include="..\..\include\SoundTouch.h" />
<ClInclude Include="..\..\include\STTypes.h" />
<ClInclude Include="AAFilter.h" />
<ClInclude Include="cpu_detect.h" />
<ClInclude Include="FIRFilter.h" />
<ClInclude Include="InterpolateCubic.h" />
<ClInclude Include="InterpolateLinear.h" />
<ClInclude Include="InterpolateShannon.h" />
<ClInclude Include="PeakFinder.h" />
<ClInclude Include="RateTransposer.h" />
<ClInclude Include="TDStretch.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@ -1,268 +1,279 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks.
///
/// Note : MMX/SSE optimized functions reside in separate, platform-specific files
/// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef TDStretch_H
#define TDStretch_H
#include <stddef.h>
#include "STTypes.h"
#include "RateTransposer.h"
#include "FIFOSamplePipe.h"
namespace soundtouch
{
/// Default values for sound processing parameters:
/// Notice that the default parameters are tuned for contemporary popular music
/// processing. For speech processing applications these parameters suit better:
/// #define DEFAULT_SEQUENCE_MS 40
/// #define DEFAULT_SEEKWINDOW_MS 15
/// #define DEFAULT_OVERLAP_MS 8
///
/// Default length of a single processing sequence, in milliseconds. This determines to how
/// long sequences the original sound is chopped in the time-stretch algorithm.
///
/// The larger this value is, the lesser sequences are used in processing. In principle
/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
/// and vice versa.
///
/// Increasing this value reduces computational burden & vice versa.
//#define DEFAULT_SEQUENCE_MS 40
#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN
/// Giving this value for the sequence length sets automatic parameter value
/// according to tempo setting (recommended)
#define USE_AUTO_SEQUENCE_LEN 0
/// Seeking window default length in milliseconds for algorithm that finds the best possible
/// overlapping location. This determines from how wide window the algorithm may look for an
/// optimal joining location when mixing the sound sequences back together.
///
/// The bigger this window setting is, the higher the possibility to find a better mixing
/// position will become, but at the same time large values may cause a "drifting" artifact
/// because consequent sequences will be taken at more uneven intervals.
///
/// If there's a disturbing artifact that sounds as if a constant frequency was drifting
/// around, try reducing this setting.
///
/// Increasing this value increases computational burden & vice versa.
//#define DEFAULT_SEEKWINDOW_MS 15
#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN
/// Giving this value for the seek window length sets automatic parameter value
/// according to tempo setting (recommended)
#define USE_AUTO_SEEKWINDOW_LEN 0
/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together,
/// to form a continuous sound stream, this parameter defines over how long period the two
/// consecutive sequences are let to overlap each other.
///
/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting
/// by a large amount, you might wish to try a smaller value on this.
///
/// Increasing this value increases computational burden & vice versa.
#define DEFAULT_OVERLAP_MS 8
/// Class that does the time-stretch (tempo change) effect for the processed
/// sound.
class TDStretch : public FIFOProcessor
{
protected:
int channels;
int sampleReq;
float tempo;
SAMPLETYPE *pMidBuffer;
SAMPLETYPE *pMidBufferUnaligned;
int overlapLength;
int seekLength;
int seekWindowLength;
int overlapDividerBits;
int slopingDivider;
float nominalSkip;
float skipFract;
FIFOSampleBuffer outputBuffer;
FIFOSampleBuffer inputBuffer;
BOOL bQuickSeek;
int sampleRate;
int sequenceMs;
int seekWindowMs;
int overlapMs;
BOOL bAutoSeqSetting;
BOOL bAutoSeekSetting;
void acceptNewOverlapLength(int newOverlapLength);
virtual void clearCrossCorrState();
void calculateOverlapLength(int overlapMs);
virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos);
virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos);
int seekBestOverlapPosition(const SAMPLETYPE *refPos);
virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
void clearMidBuffer();
void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
void calcSeqParameters();
/// Changes the tempo of the given sound samples.
/// Returns amount of samples returned in the "output" buffer.
/// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function.
void processSamples();
public:
TDStretch();
virtual ~TDStretch();
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX/SSE/etc-capable CPU available or not.
static void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct feature set depending on if the CPU
/// supports MMX/SSE/etc extensions.
static TDStretch *newInstance();
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the input buffer object
FIFOSamplePipe *getInput() { return &inputBuffer; };
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
/// tempo, larger faster tempo.
void setTempo(float newTempo);
/// Returns nonzero if there aren't any samples available for outputting.
virtual void clear();
/// Clears the input buffer
void clearInput();
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(int numChannels);
/// Enables/disables the quick position seeking algorithm. Zero to disable,
/// nonzero to enable
void enableQuickSeek(BOOL enable);
/// Returns nonzero if the quick seeking algorithm is enabled.
BOOL isQuickSeekEnabled() const;
/// Sets routine control parameters. These control are certain time constants
/// defining how the sound is stretched to the desired duration.
//
/// 'sampleRate' = sample rate of the sound
/// 'sequenceMS' = one processing sequence length in milliseconds
/// 'seekwindowMS' = seeking window length for scanning the best overlapping
/// position
/// 'overlapMS' = overlapping length
void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
int sequenceMS = -1, ///< Single processing sequence length (ms)
int seekwindowMS = -1, ///< Offset seeking window length (ms)
int overlapMS = -1 ///< Sequence overlapping length (ms)
);
/// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be NULL, in such case corresponding parameter
/// value isn't returned.
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
/// Adds 'numsamples' pcs of samples from the 'samples' memory position into
/// the input of the object.
virtual void putSamples(
const SAMPLETYPE *samples, ///< Input sample data
uint numSamples ///< Number of samples in 'samples' so that one sample
///< contains both channels if stereo
);
/// return nominal input sample requirement for triggering a processing batch
int getInputSampleReq() const
{
return (int)(nominalSkip + 0.5);
}
/// return nominal output sample amount when running a processing batch
int getOutputBatchSize() const
{
return seekWindowLength - overlapLength;
}
};
// Implementation-specific class declarations:
#ifdef SOUNDTOUCH_ALLOW_MMX
/// Class that implements MMX optimized routines for 16bit integer samples type.
class TDStretchMMX : public TDStretch
{
protected:
double calcCrossCorr(const short *mixingPos, const short *compare) const;
virtual void overlapStereo(short *output, const short *input) const;
virtual void clearCrossCorrState();
};
#endif /// SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE
/// Class that implements SSE optimized routines for floating point samples type.
class TDStretchSSE : public TDStretch
{
protected:
double calcCrossCorr(const float *mixingPos, const float *compare) const;
};
#endif /// SOUNDTOUCH_ALLOW_SSE
}
#endif /// TDStretch_H
////////////////////////////////////////////////////////////////////////////////
///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like method
/// with several performance-increasing tweaks.
///
/// Note : MMX/SSE optimized functions reside in separate, platform-specific files
/// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef TDStretch_H
#define TDStretch_H
#include <stddef.h>
#include "STTypes.h"
#include "RateTransposer.h"
#include "FIFOSamplePipe.h"
namespace soundtouch
{
/// Default values for sound processing parameters:
/// Notice that the default parameters are tuned for contemporary popular music
/// processing. For speech processing applications these parameters suit better:
/// #define DEFAULT_SEQUENCE_MS 40
/// #define DEFAULT_SEEKWINDOW_MS 15
/// #define DEFAULT_OVERLAP_MS 8
///
/// Default length of a single processing sequence, in milliseconds. This determines to how
/// long sequences the original sound is chopped in the time-stretch algorithm.
///
/// The larger this value is, the lesser sequences are used in processing. In principle
/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
/// and vice versa.
///
/// Increasing this value reduces computational burden & vice versa.
//#define DEFAULT_SEQUENCE_MS 40
#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN
/// Giving this value for the sequence length sets automatic parameter value
/// according to tempo setting (recommended)
#define USE_AUTO_SEQUENCE_LEN 0
/// Seeking window default length in milliseconds for algorithm that finds the best possible
/// overlapping location. This determines from how wide window the algorithm may look for an
/// optimal joining location when mixing the sound sequences back together.
///
/// The bigger this window setting is, the higher the possibility to find a better mixing
/// position will become, but at the same time large values may cause a "drifting" artifact
/// because consequent sequences will be taken at more uneven intervals.
///
/// If there's a disturbing artifact that sounds as if a constant frequency was drifting
/// around, try reducing this setting.
///
/// Increasing this value increases computational burden & vice versa.
//#define DEFAULT_SEEKWINDOW_MS 15
#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN
/// Giving this value for the seek window length sets automatic parameter value
/// according to tempo setting (recommended)
#define USE_AUTO_SEEKWINDOW_LEN 0
/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together,
/// to form a continuous sound stream, this parameter defines over how long period the two
/// consecutive sequences are let to overlap each other.
///
/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting
/// by a large amount, you might wish to try a smaller value on this.
///
/// Increasing this value increases computational burden & vice versa.
#define DEFAULT_OVERLAP_MS 8
/// Class that does the time-stretch (tempo change) effect for the processed
/// sound.
class TDStretch : public FIFOProcessor
{
protected:
int channels;
int sampleReq;
int overlapLength;
int seekLength;
int seekWindowLength;
int overlapDividerBitsNorm;
int overlapDividerBitsPure;
int slopingDivider;
int sampleRate;
int sequenceMs;
int seekWindowMs;
int overlapMs;
unsigned long maxnorm;
float maxnormf;
double tempo;
double nominalSkip;
double skipFract;
bool bQuickSeek;
bool bAutoSeqSetting;
bool bAutoSeekSetting;
bool isBeginning;
SAMPLETYPE *pMidBuffer;
SAMPLETYPE *pMidBufferUnaligned;
FIFOSampleBuffer outputBuffer;
FIFOSampleBuffer inputBuffer;
void acceptNewOverlapLength(int newOverlapLength);
virtual void clearCrossCorrState();
void calculateOverlapLength(int overlapMs);
virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);
virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);
virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos);
virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos);
virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos);
virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const;
void clearMidBuffer();
void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
void calcSeqParameters();
void adaptNormalizer();
/// Changes the tempo of the given sound samples.
/// Returns amount of samples returned in the "output" buffer.
/// The maximum amount of samples that can be returned at a time is set by
/// the 'set_returnBuffer_size' function.
void processSamples();
public:
TDStretch();
virtual ~TDStretch() override;
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX/SSE/etc-capable CPU available or not.
static void *operator new(size_t s);
/// Use this function instead of "new" operator to create a new instance of this class.
/// This function automatically chooses a correct feature set depending on if the CPU
/// supports MMX/SSE/etc extensions.
static TDStretch *newInstance();
/// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; };
/// Returns the input buffer object
FIFOSamplePipe *getInput() { return &inputBuffer; };
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
/// tempo, larger faster tempo.
void setTempo(double newTempo);
/// Returns nonzero if there aren't any samples available for outputting.
virtual void clear() override;
/// Clears the input buffer
void clearInput();
/// Sets the number of channels, 1 = mono, 2 = stereo
void setChannels(int numChannels);
/// Enables/disables the quick position seeking algorithm. Zero to disable,
/// nonzero to enable
void enableQuickSeek(bool enable);
/// Returns nonzero if the quick seeking algorithm is enabled.
bool isQuickSeekEnabled() const;
/// Sets routine control parameters. These control are certain time constants
/// defining how the sound is stretched to the desired duration.
//
/// 'sampleRate' = sample rate of the sound
/// 'sequenceMS' = one processing sequence length in milliseconds
/// 'seekwindowMS' = seeking window length for scanning the best overlapping
/// position
/// 'overlapMS' = overlapping length
void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
int sequenceMS = -1, ///< Single processing sequence length (ms)
int seekwindowMS = -1, ///< Offset seeking window length (ms)
int overlapMS = -1 ///< Sequence overlapping length (ms)
);
/// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be nullptr, in such case corresponding parameter
/// value isn't returned.
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
/// Adds 'numsamples' pcs of samples from the 'samples' memory position into
/// the input of the object.
virtual void putSamples(
const SAMPLETYPE *samples, ///< Input sample data
uint numSamples ///< Number of samples in 'samples' so that one sample
///< contains both channels if stereo
) override;
/// return nominal input sample requirement for triggering a processing batch
int getInputSampleReq() const
{
return (int)(nominalSkip + 0.5);
}
/// return nominal output sample amount when running a processing batch
int getOutputBatchSize() const
{
return seekWindowLength - overlapLength;
}
/// return approximate initial input-output latency
int getLatency() const
{
return sampleReq;
}
};
// Implementation-specific class declarations:
#ifdef SOUNDTOUCH_ALLOW_MMX
/// Class that implements MMX optimized routines for 16bit integer samples type.
class TDStretchMMX : public TDStretch
{
protected:
double calcCrossCorr(const short *mixingPos, const short *compare, double &norm) override;
double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) override;
virtual void overlapStereo(short *output, const short *input) const override;
virtual void clearCrossCorrState() override;
};
#endif /// SOUNDTOUCH_ALLOW_MMX
#ifdef SOUNDTOUCH_ALLOW_SSE
/// Class that implements SSE optimized routines for floating point samples type.
class TDStretchSSE : public TDStretch
{
protected:
double calcCrossCorr(const float *mixingPos, const float *compare, double &norm) override;
double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) override;
};
#endif /// SOUNDTOUCH_ALLOW_SSE
}
#endif /// TDStretch_H

View File

@ -1,62 +1,55 @@
////////////////////////////////////////////////////////////////////////////////
///
/// A header file for detecting the Intel MMX instructions set extension.
///
/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
/// routine implementations for x86 Windows, x86 gnu version and non-x86
/// platforms, respectively.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _CPU_DETECT_H_
#define _CPU_DETECT_H_
#include "STTypes.h"
#define SUPPORT_MMX 0x0001
#define SUPPORT_3DNOW 0x0002
#define SUPPORT_ALTIVEC 0x0004
#define SUPPORT_SSE 0x0008
#define SUPPORT_SSE2 0x0010
/// Checks which instruction set extensions are supported by the CPU.
///
/// \return A bitmask of supported extensions, see SUPPORT_... defines.
uint detectCPUextensions(void);
/// Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint wDisableMask);
#endif // _CPU_DETECT_H_
////////////////////////////////////////////////////////////////////////////////
///
/// A header file for detecting the Intel MMX instructions set extension.
///
/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
/// routine implementations for x86 Windows, x86 gnu version and non-x86
/// platforms, respectively.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#ifndef _CPU_DETECT_H_
#define _CPU_DETECT_H_
#include "STTypes.h"
#define SUPPORT_MMX 0x0001
#define SUPPORT_3DNOW 0x0002
#define SUPPORT_ALTIVEC 0x0004
#define SUPPORT_SSE 0x0008
#define SUPPORT_SSE2 0x0010
/// Checks which instruction set extensions are supported by the CPU.
///
/// \return A bitmask of supported extensions, see SUPPORT_... defines.
uint detectCPUextensions(void);
/// Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint wDisableMask);
#endif // _CPU_DETECT_H_

View File

@ -1,139 +1,130 @@
////////////////////////////////////////////////////////////////////////////////
///
/// Generic version of the x86 CPU extension detection routine.
///
/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
/// for the Microsoft compiler version.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h"
#include "STTypes.h"
#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
#if defined(__GNUC__) && defined(__i386__)
// gcc
#include "cpuid.h"
#endif
#if defined(_M_IX86)
// windows
#include <intrin.h>
#define bit_MMX (1 << 23)
#define bit_SSE (1 << 25)
#define bit_SSE2 (1 << 26)
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// processor instructions extension detection routines
//
//////////////////////////////////////////////////////////////////////////////
// Flag variable indicating whick ISA extensions are disabled (for debugging)
static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
// Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint dwDisableMask)
{
_dwDisabledISA = dwDisableMask;
}
/// Checks which instruction set extensions are supported by the CPU.
uint detectCPUextensions(void)
{
/// If building for a 64bit system (no Itanium) and the user wants optimizations.
/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19.
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
#if ((defined(__GNUC__) && defined(__x86_64__)) \
|| defined(_M_X64)) \
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
return 0x19 & ~_dwDisabledISA;
/// If building for a 32bit system and the user wants optimizations.
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
#elif ((defined(__GNUC__) && defined(__i386__)) \
|| defined(_M_IX86)) \
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
if (_dwDisabledISA == 0xffffffff) return 0;
uint res = 0;
#if defined(__GNUC__)
// GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support.
uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable.
// Check if no cpuid support.
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions.
if (edx & bit_MMX) res = res | SUPPORT_MMX;
if (edx & bit_SSE) res = res | SUPPORT_SSE;
if (edx & bit_SSE2) res = res | SUPPORT_SSE2;
#else
// Window / VS version of cpuid. Notice that Visual Studio 2005 or later required
// for __cpuid intrinsic support.
int reg[4] = {-1};
// Check if no cpuid support.
__cpuid(reg,0);
if ((unsigned int)reg[0] == 0) return 0; // always disable extensions.
__cpuid(reg,1);
if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX;
if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE;
if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2;
#endif
return res & ~_dwDisabledISA;
#else
/// One of these is true:
/// 1) We don't want optimizations.
/// 2) Using an unsupported compiler.
/// 3) Running on a non-x86 platform.
return 0;
#endif
}
////////////////////////////////////////////////////////////////////////////////
///
/// Generic version of the x86 CPU extension detection routine.
///
/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
/// for the Microsoft compiler version.
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h"
#include "STTypes.h"
#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
#if defined(__GNUC__) && defined(__i386__)
// gcc
#include "cpuid.h"
#elif defined(_M_IX86)
// windows non-gcc
#include <intrin.h>
#endif
#define bit_MMX (1 << 23)
#define bit_SSE (1 << 25)
#define bit_SSE2 (1 << 26)
#endif
//////////////////////////////////////////////////////////////////////////////
//
// processor instructions extension detection routines
//
//////////////////////////////////////////////////////////////////////////////
// Flag variable indicating whick ISA extensions are disabled (for debugging)
static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
// Disables given set of instruction extensions. See SUPPORT_... defines.
void disableExtensions(uint dwDisableMask)
{
_dwDisabledISA = dwDisableMask;
}
/// Checks which instruction set extensions are supported by the CPU.
uint detectCPUextensions(void)
{
/// If building for a 64bit system (no Itanium) and the user wants optimizations.
/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19.
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
#if ((defined(__GNUC__) && defined(__x86_64__)) \
|| defined(_M_X64)) \
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
return 0x19 & ~_dwDisabledISA;
/// If building for a 32bit system and the user wants optimizations.
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
#elif ((defined(__GNUC__) && defined(__i386__)) \
|| defined(_M_IX86)) \
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
if (_dwDisabledISA == 0xffffffff) return 0;
uint res = 0;
#if defined(__GNUC__)
// GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support.
uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable.
// Check if no cpuid support.
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions.
if (edx & bit_MMX) res = res | SUPPORT_MMX;
if (edx & bit_SSE) res = res | SUPPORT_SSE;
if (edx & bit_SSE2) res = res | SUPPORT_SSE2;
#else
// Window / VS version of cpuid. Notice that Visual Studio 2005 or later required
// for __cpuid intrinsic support.
int reg[4] = {-1};
// Check if no cpuid support.
__cpuid(reg,0);
if ((unsigned int)reg[0] == 0) return 0; // always disable extensions.
__cpuid(reg,1);
if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX;
if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE;
if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2;
#endif
return res & ~_dwDisabledISA;
#else
/// One of these is true:
/// 1) We don't want optimizations.
/// 2) Using an unsupported compiler.
/// 3) Running on a non-x86 platform.
return 0;
#endif
}

View File

@ -1,317 +1,396 @@
////////////////////////////////////////////////////////////////////////////////
///
/// MMX optimized routines. All MMX optimized functions have been gathered into
/// this single source code file, regardless to their class or original source
/// code file, in order to ease porting the library to other compiler and
/// processor platforms.
///
/// The MMX-optimizations are programmed using MMX compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets.
///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support compiler intrinsic syntax. The update
/// is available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "STTypes.h"
#ifdef SOUNDTOUCH_ALLOW_MMX
// MMX routines available only with integer sample type
using namespace soundtouch;
//////////////////////////////////////////////////////////////////////////////
//
// implementation of MMX optimized functions of class 'TDStretchMMX'
//
//////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h"
#include <mmintrin.h>
#include <limits.h>
#include <math.h>
// Calculates cross correlation of two buffers
double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2) const
{
const __m64 *pVec1, *pVec2;
__m64 shifter;
__m64 accu, normaccu;
long corr, norm;
int i;
pVec1 = (__m64*)pV1;
pVec2 = (__m64*)pV2;
shifter = _m_from_int(overlapDividerBits);
normaccu = accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
// during each round for improved CPU-level parallellization.
for (i = 0; i < channels * overlapLength / 16; i ++)
{
__m64 temp, temp2;
// dictionary of instructions:
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
// _mm_add_pi32 : 2*32bit add
// _m_psrad : 32bit right-shift
temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]),
_mm_madd_pi16(pVec1[1], pVec2[1]));
temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]),
_mm_madd_pi16(pVec1[1], pVec1[1]));
accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter));
temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]),
_mm_madd_pi16(pVec1[3], pVec2[3]));
temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]),
_mm_madd_pi16(pVec1[3], pVec1[3]));
accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter));
pVec1 += 4;
pVec2 += 4;
}
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
// and finally store the result into the variable "corr"
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
corr = _m_to_int(accu);
normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32));
norm = _m_to_int(normaccu);
// Clear MMS state
_m_empty();
// Normalize result by dividing by sqrt(norm) - this step is easiest
// done using floating point operation
if (norm == 0) norm = 1; // to avoid div by zero
return (double)corr / sqrt((double)norm);
// Note: Warning about the missing EMMS instruction is harmless
// as it'll be called elsewhere.
}
void TDStretchMMX::clearCrossCorrState()
{
// Clear MMS state
_m_empty();
//_asm EMMS;
}
// MMX-optimized version of the function overlapStereo
void TDStretchMMX::overlapStereo(short *output, const short *input) const
{
const __m64 *pVinput, *pVMidBuf;
__m64 *pVdest;
__m64 mix1, mix2, adder, shifter;
int i;
pVinput = (const __m64*)input;
pVMidBuf = (const __m64*)pMidBuffer;
pVdest = (__m64*)output;
// mix1 = mixer values for 1st stereo sample
// mix1 = mixer values for 2nd stereo sample
// adder = adder for updating mixer values after each round
mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
adder = _mm_set_pi16(1, -1, 1, -1);
mix2 = _mm_add_pi16(mix1, adder);
adder = _mm_add_pi16(adder, adder);
// Overlaplength-division by shifter. "+1" is to account for "-1" deduced in
// overlapDividerBits calculation earlier.
shifter = _m_from_int(overlapDividerBits + 1);
for (i = 0; i < overlapLength / 4; i ++)
{
__m64 temp1, temp2;
// load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
// temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder
mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder);
// --- second round begins here ---
// load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r
temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r
// temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder
mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder);
pVinput += 2;
pVMidBuf += 2;
pVdest += 2;
}
_m_empty(); // clear MMS state
}
//////////////////////////////////////////////////////////////////////////////
//
// implementation of MMX optimized functions of class 'FIRFilter'
//
//////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h"
FIRFilterMMX::FIRFilterMMX() : FIRFilter()
{
filterCoeffsUnalign = NULL;
}
FIRFilterMMX::~FIRFilterMMX()
{
delete[] filterCoeffsUnalign;
}
// (overloaded) Calculates filter coefficients for MMX routine
void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)
{
uint i;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new short[2 * newLength + 8];
filterCoeffsAlign = (short *)(((ulong)filterCoeffsUnalign + 15) & -16);
// rearrange the filter coefficients for mmx routines
for (i = 0;i < length; i += 4)
{
filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];
filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];
}
}
// mmx-optimized version of the filter routine for stereo sound
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
{
// Create stack copies of the needed member variables for asm routines :
uint i, j;
__m64 *pVdest = (__m64*)dest;
if (length < 2) return 0;
for (i = 0; i < (numSamples - length) / 2; i ++)
{
__m64 accu1;
__m64 accu2;
const __m64 *pVsrc = (const __m64*)src;
const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;
accu1 = accu2 = _mm_setzero_si64();
for (j = 0; j < lengthDiv8 * 2; j ++)
{
__m64 temp1, temp2;
temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0
temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1
temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1
// accu1 += l2*f2+l0*f0 r2*f2+r0*f0
// += l3*f3+l1*f1 r3*f3+r1*f1
// accu2 += l3*f2+l1*f0 r3*f2+r1*f0
// l4*f3+l2*f1 r4*f3+r2*f1
pVfilter += 2;
pVsrc += 2;
}
// accu >>= resultDivFactor
accu1 = _mm_srai_pi32(accu1, resultDivFactor);
accu2 = _mm_srai_pi32(accu2, resultDivFactor);
// pack 2*2*32bits => 4*16 bits
pVdest[0] = _mm_packs_pi32(accu1, accu2);
src += 4;
pVdest ++;
}
_m_empty(); // clear emms state
return (numSamples & 0xfffffffe) - length;
}
#endif // SOUNDTOUCH_ALLOW_MMX
////////////////////////////////////////////////////////////////////////////////
///
/// MMX optimized routines. All MMX optimized functions have been gathered into
/// this single source code file, regardless to their class or original source
/// code file, in order to ease porting the library to other compiler and
/// processor platforms.
///
/// The MMX-optimizations are programmed using MMX compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets.
///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support compiler intrinsic syntax. The update
/// is available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "STTypes.h"
#ifdef SOUNDTOUCH_ALLOW_MMX
// MMX routines available only with integer sample type
using namespace soundtouch;
//////////////////////////////////////////////////////////////////////////////
//
// implementation of MMX optimized functions of class 'TDStretchMMX'
//
//////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h"
#include <mmintrin.h>
#include <limits.h>
#include <math.h>
// Calculates cross correlation of two buffers
double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm)
{
const __m64 *pVec1, *pVec2;
__m64 shifter;
__m64 accu, normaccu;
long corr, norm;
int i;
pVec1 = (__m64*)pV1;
pVec2 = (__m64*)pV2;
shifter = _m_from_int(overlapDividerBitsNorm);
normaccu = accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
// during each round for improved CPU-level parallellization.
for (i = 0; i < channels * overlapLength / 16; i ++)
{
__m64 temp, temp2;
// dictionary of instructions:
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
// _mm_add_pi32 : 2*32bit add
// _m_psrad : 32bit right-shift
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter),
_mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter));
temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), shifter),
_mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec1[1]), shifter));
accu = _mm_add_pi32(accu, temp);
normaccu = _mm_add_pi32(normaccu, temp2);
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter),
_mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter));
temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), shifter),
_mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec1[3]), shifter));
accu = _mm_add_pi32(accu, temp);
normaccu = _mm_add_pi32(normaccu, temp2);
pVec1 += 4;
pVec2 += 4;
}
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
// and finally store the result into the variable "corr"
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
corr = _m_to_int(accu);
normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32));
norm = _m_to_int(normaccu);
// Clear MMS state
_m_empty();
if (norm > (long)maxnorm)
{
// modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
#pragma omp critical
if (norm > (long)maxnorm)
{
maxnorm = norm;
}
}
// Normalize result by dividing by sqrt(norm) - this step is easiest
// done using floating point operation
dnorm = (double)norm;
return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm);
// Note: Warning about the missing EMMS instruction is harmless
// as it'll be called elsewhere.
}
/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value
double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm)
{
const __m64 *pVec1, *pVec2;
__m64 shifter;
__m64 accu;
long corr, lnorm;
int i;
// cancel first normalizer tap from previous round
lnorm = 0;
for (i = 1; i <= channels; i ++)
{
lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBitsNorm;
}
pVec1 = (__m64*)pV1;
pVec2 = (__m64*)pV2;
shifter = _m_from_int(overlapDividerBitsNorm);
accu = _mm_setzero_si64();
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
// during each round for improved CPU-level parallellization.
for (i = 0; i < channels * overlapLength / 16; i ++)
{
__m64 temp;
// dictionary of instructions:
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
// _mm_add_pi32 : 2*32bit add
// _m_psrad : 32bit right-shift
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter),
_mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter));
accu = _mm_add_pi32(accu, temp);
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter),
_mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter));
accu = _mm_add_pi32(accu, temp);
pVec1 += 4;
pVec2 += 4;
}
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
// and finally store the result into the variable "corr"
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
corr = _m_to_int(accu);
// Clear MMS state
_m_empty();
// update normalizer with last samples of this round
pV1 = (short *)pVec1;
for (int j = 1; j <= channels; j ++)
{
lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBitsNorm;
}
dnorm += (double)lnorm;
if (lnorm > (long)maxnorm)
{
maxnorm = lnorm;
}
// Normalize result by dividing by sqrt(norm) - this step is easiest
// done using floating point operation
return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm);
}
void TDStretchMMX::clearCrossCorrState()
{
// Clear MMS state
_m_empty();
//_asm EMMS;
}
// MMX-optimized version of the function overlapStereo
void TDStretchMMX::overlapStereo(short *output, const short *input) const
{
const __m64 *pVinput, *pVMidBuf;
__m64 *pVdest;
__m64 mix1, mix2, adder, shifter;
int i;
pVinput = (const __m64*)input;
pVMidBuf = (const __m64*)pMidBuffer;
pVdest = (__m64*)output;
// mix1 = mixer values for 1st stereo sample
// mix1 = mixer values for 2nd stereo sample
// adder = adder for updating mixer values after each round
mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
adder = _mm_set_pi16(1, -1, 1, -1);
mix2 = _mm_add_pi16(mix1, adder);
adder = _mm_add_pi16(adder, adder);
// Overlaplength-division by shifter. "+1" is to account for "-1" deduced in
// overlapDividerBits calculation earlier.
shifter = _m_from_int(overlapDividerBitsPure + 1);
for (i = 0; i < overlapLength / 4; i ++)
{
__m64 temp1, temp2;
// load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
// temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder
mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder);
// --- second round begins here ---
// load & shuffle data so that input & mixbuffer data samples are paired
temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r
temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r
// temp = (temp .* mix) >> shifter
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
// update mix += adder
mix1 = _mm_add_pi16(mix1, adder);
mix2 = _mm_add_pi16(mix2, adder);
pVinput += 2;
pVMidBuf += 2;
pVdest += 2;
}
_m_empty(); // clear MMS state
}
//////////////////////////////////////////////////////////////////////////////
//
// implementation of MMX optimized functions of class 'FIRFilter'
//
//////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h"
FIRFilterMMX::FIRFilterMMX() : FIRFilter()
{
filterCoeffsAlign = nullptr;
filterCoeffsUnalign = nullptr;
}
FIRFilterMMX::~FIRFilterMMX()
{
delete[] filterCoeffsUnalign;
}
// (overloaded) Calculates filter coefficients for MMX routine
void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)
{
uint i;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new short[2 * newLength + 8];
filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
// rearrange the filter coefficients for mmx routines
for (i = 0;i < length; i += 4)
{
filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];
filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];
filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];
filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];
filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];
}
}
// mmx-optimized version of the filter routine for stereo sound
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
{
// Create stack copies of the needed member variables for asm routines :
uint i, j;
__m64 *pVdest = (__m64*)dest;
if (length < 2) return 0;
for (i = 0; i < (numSamples - length) / 2; i ++)
{
__m64 accu1;
__m64 accu2;
const __m64 *pVsrc = (const __m64*)src;
const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;
accu1 = accu2 = _mm_setzero_si64();
for (j = 0; j < lengthDiv8 * 2; j ++)
{
__m64 temp1, temp2;
temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0
temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1
temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1
// accu1 += l2*f2+l0*f0 r2*f2+r0*f0
// += l3*f3+l1*f1 r3*f3+r1*f1
// accu2 += l3*f2+l1*f0 r3*f2+r1*f0
// l4*f3+l2*f1 r4*f3+r2*f1
pVfilter += 2;
pVsrc += 2;
}
// accu >>= resultDivFactor
accu1 = _mm_srai_pi32(accu1, resultDivFactor);
accu2 = _mm_srai_pi32(accu2, resultDivFactor);
// pack 2*2*32bits => 4*16 bits
pVdest[0] = _mm_packs_pi32(accu1, accu2);
src += 4;
pVdest ++;
}
_m_empty(); // clear emms state
return (numSamples & 0xfffffffe) - length;
}
#else
// workaround to not complain about empty module
bool _dontcomplain_mmx_empty;
#endif // SOUNDTOUCH_ALLOW_MMX

View File

@ -1,361 +1,362 @@
////////////////////////////////////////////////////////////////////////////////
///
/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
/// optimized functions have been gathered into this single source
/// code file, regardless to their class or original source code file, in order
/// to ease porting the library to other compiler and processor platforms.
///
/// The SSE-optimizations are programmed using SSE compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets.
///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support SSE instruction set. The update is
/// available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
///
/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
/// perform a search with keywords "processor pack".
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// Last changed : $Date$
// File revision : $Revision: 4 $
//
// $Id$
//
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h"
#include "STTypes.h"
using namespace soundtouch;
#ifdef SOUNDTOUCH_ALLOW_SSE
// SSE routines available only with float sample type
//////////////////////////////////////////////////////////////////////////////
//
// implementation of SSE optimized functions of class 'TDStretchSSE'
//
//////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h"
#include <xmmintrin.h>
#include <math.h>
// Calculates cross correlation of two buffers
double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2) const
{
int i;
const float *pVec1;
const __m128 *pVec2;
__m128 vSum, vNorm;
// Note. It means a major slow-down if the routine needs to tolerate
// unaligned __m128 memory accesses. It's way faster if we can skip
// unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
// This can mean up to ~ 10-fold difference (incl. part of which is
// due to skipping every second round for stereo sound though).
//
// Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
// for choosing if this little cheating is allowed.
#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION
// Little cheating allowed, return valid correlation only for
// aligned locations, meaning every second round for stereo sound.
#define _MM_LOAD _mm_load_ps
if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations
#else
// No cheating allowed, use unaligned load & take the resulting
// performance hit.
#define _MM_LOAD _mm_loadu_ps
#endif
// ensure overlapLength is divisible by 8
assert((overlapLength % 8) == 0);
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
// Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
pVec1 = (const float*)pV1;
pVec2 = (const __m128*)pV2;
vSum = vNorm = _mm_setzero_ps();
// Unroll the loop by factor of 4 * 4 operations. Use same routine for
// stereo & mono, for mono it just means twice the amount of unrolling.
for (i = 0; i < channels * overlapLength / 16; i ++)
{
__m128 vTemp;
// vSum += pV1[0..3] * pV2[0..3]
vTemp = _MM_LOAD(pVec1);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[4..7] * pV2[4..7]
vTemp = _MM_LOAD(pVec1 + 4);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[8..11] * pV2[8..11]
vTemp = _MM_LOAD(pVec1 + 8);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[12..15] * pV2[12..15]
vTemp = _MM_LOAD(pVec1 + 12);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
pVec1 += 16;
pVec2 += 4;
}
// return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
float *pvNorm = (float*)&vNorm;
double norm = sqrt(pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]);
if (norm < 1e-9) norm = 1.0; // to avoid div by zero
float *pvSum = (float*)&vSum;
return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / norm;
/* This is approximately corresponding routine in C-language yet without normalization:
double corr, norm;
uint i;
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
corr = norm = 0.0;
for (i = 0; i < channels * overlapLength / 16; i ++)
{
corr += pV1[0] * pV2[0] +
pV1[1] * pV2[1] +
pV1[2] * pV2[2] +
pV1[3] * pV2[3] +
pV1[4] * pV2[4] +
pV1[5] * pV2[5] +
pV1[6] * pV2[6] +
pV1[7] * pV2[7] +
pV1[8] * pV2[8] +
pV1[9] * pV2[9] +
pV1[10] * pV2[10] +
pV1[11] * pV2[11] +
pV1[12] * pV2[12] +
pV1[13] * pV2[13] +
pV1[14] * pV2[14] +
pV1[15] * pV2[15];
for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j];
pV1 += 16;
pV2 += 16;
}
return corr / sqrt(norm);
*/
}
//////////////////////////////////////////////////////////////////////////////
//
// implementation of SSE optimized functions of class 'FIRFilter'
//
//////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h"
FIRFilterSSE::FIRFilterSSE() : FIRFilter()
{
filterCoeffsAlign = NULL;
filterCoeffsUnalign = NULL;
}
FIRFilterSSE::~FIRFilterSSE()
{
delete[] filterCoeffsUnalign;
filterCoeffsAlign = NULL;
filterCoeffsUnalign = NULL;
}
// (overloaded) Calculates filter coefficients for SSE routine
void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
{
uint i;
float fDivider;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Scale the filter coefficients so that it won't be necessary to scale the filtering result
// also rearrange coefficients suitably for SSE
// Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new float[2 * newLength + 4];
filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & (ulong)-16);
fDivider = (float)resultDivider;
// rearrange the filter coefficients for mmx routines
for (i = 0; i < newLength; i ++)
{
filterCoeffsAlign[2 * i + 0] =
filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider;
}
}
// SSE-optimized version of the filter routine for stereo sound
uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const
{
int count = (int)((numSamples - length) & (uint)-2);
int j;
assert(count % 2 == 0);
if (count < 2) return 0;
assert(source != NULL);
assert(dest != NULL);
assert((length % 8) == 0);
assert(filterCoeffsAlign != NULL);
assert(((ulong)filterCoeffsAlign) % 16 == 0);
// filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
for (j = 0; j < count; j += 2)
{
const float *pSrc;
const __m128 *pFil;
__m128 sum1, sum2;
uint i;
pSrc = (const float*)source; // source audio data
pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
// are aligned to 16-byte boundary
sum1 = sum2 = _mm_setzero_ps();
for (i = 0; i < length / 8; i ++)
{
// Unroll loop for efficiency & calculate filter for 2*2 stereo samples
// at each pass
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
// sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
pSrc += 16;
pFil += 4;
}
// Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need
// to sum the two hi- and lo-floats of these registers together.
// post-shuffle & add the filtered values and store to dest.
_mm_storeu_ps(dest, _mm_add_ps(
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
));
source += 4;
dest += 4;
}
// Ideas for further improvement:
// 1. If it could be guaranteed that 'source' were always aligned to 16-byte
// boundary, a faster aligned '_mm_load_ps' instruction could be used.
// 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
// boundary, a faster '_mm_store_ps' instruction could be used.
return (uint)count;
/* original routine in C-language. please notice the C-version has differently
organized coefficients though.
double suml1, suml2;
double sumr1, sumr2;
uint i, j;
for (j = 0; j < count; j += 2)
{
const float *ptr;
const float *pFil;
suml1 = sumr1 = 0.0;
suml2 = sumr2 = 0.0;
ptr = src;
pFil = filterCoeffs;
for (i = 0; i < lengthLocal; i ++)
{
// unroll loop for efficiency.
suml1 += ptr[0] * pFil[0] +
ptr[2] * pFil[2] +
ptr[4] * pFil[4] +
ptr[6] * pFil[6];
sumr1 += ptr[1] * pFil[1] +
ptr[3] * pFil[3] +
ptr[5] * pFil[5] +
ptr[7] * pFil[7];
suml2 += ptr[8] * pFil[0] +
ptr[10] * pFil[2] +
ptr[12] * pFil[4] +
ptr[14] * pFil[6];
sumr2 += ptr[9] * pFil[1] +
ptr[11] * pFil[3] +
ptr[13] * pFil[5] +
ptr[15] * pFil[7];
ptr += 16;
pFil += 8;
}
dest[0] = (float)suml1;
dest[1] = (float)sumr1;
dest[2] = (float)suml2;
dest[3] = (float)sumr2;
src += 4;
dest += 4;
}
*/
}
#endif // SOUNDTOUCH_ALLOW_SSE
////////////////////////////////////////////////////////////////////////////////
///
/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
/// optimized functions have been gathered into this single source
/// code file, regardless to their class or original source code file, in order
/// to ease porting the library to other compiler and processor platforms.
///
/// The SSE-optimizations are programmed using SSE compiler intrinsics that
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
/// should compile with both toolsets.
///
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
/// 6.0 processor pack" update to support SSE instruction set. The update is
/// available for download at Microsoft Developers Network, see here:
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
///
/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
/// perform a search with keywords "processor pack".
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
//
// License :
//
// SoundTouch audio processing library
// Copyright (c) Olli Parviainen
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
////////////////////////////////////////////////////////////////////////////////
#include "cpu_detect.h"
#include "STTypes.h"
using namespace soundtouch;
#ifdef SOUNDTOUCH_ALLOW_SSE
// SSE routines available only with float sample type
//////////////////////////////////////////////////////////////////////////////
//
// implementation of SSE optimized functions of class 'TDStretchSSE'
//
//////////////////////////////////////////////////////////////////////////////
#include "TDStretch.h"
#include <xmmintrin.h>
#include <math.h>
// Calculates cross correlation of two buffers
double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm)
{
int i;
const float *pVec1;
const __m128 *pVec2;
__m128 vSum, vNorm;
// Note. It means a major slow-down if the routine needs to tolerate
// unaligned __m128 memory accesses. It's way faster if we can skip
// unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
// This can mean up to ~ 10-fold difference (incl. part of which is
// due to skipping every second round for stereo sound though).
//
// Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
// for choosing if this little cheating is allowed.
#ifdef ST_SIMD_AVOID_UNALIGNED
// Little cheating allowed, return valid correlation only for
// aligned locations, meaning every second round for stereo sound.
#define _MM_LOAD _mm_load_ps
if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations
#else
// No cheating allowed, use unaligned load & take the resulting
// performance hit.
#define _MM_LOAD _mm_loadu_ps
#endif
// ensure overlapLength is divisible by 8
assert((overlapLength % 8) == 0);
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
// Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
pVec1 = (const float*)pV1;
pVec2 = (const __m128*)pV2;
vSum = vNorm = _mm_setzero_ps();
// Unroll the loop by factor of 4 * 4 operations. Use same routine for
// stereo & mono, for mono it just means twice the amount of unrolling.
for (i = 0; i < channels * overlapLength / 16; i ++)
{
__m128 vTemp;
// vSum += pV1[0..3] * pV2[0..3]
vTemp = _MM_LOAD(pVec1);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[4..7] * pV2[4..7]
vTemp = _MM_LOAD(pVec1 + 4);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[8..11] * pV2[8..11]
vTemp = _MM_LOAD(pVec1 + 8);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
// vSum += pV1[12..15] * pV2[12..15]
vTemp = _MM_LOAD(pVec1 + 12);
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3]));
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
pVec1 += 16;
pVec2 += 4;
}
// return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
float *pvNorm = (float*)&vNorm;
float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]);
anorm = norm;
float *pvSum = (float*)&vSum;
return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm);
/* This is approximately corresponding routine in C-language yet without normalization:
double corr, norm;
uint i;
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
corr = norm = 0.0;
for (i = 0; i < channels * overlapLength / 16; i ++)
{
corr += pV1[0] * pV2[0] +
pV1[1] * pV2[1] +
pV1[2] * pV2[2] +
pV1[3] * pV2[3] +
pV1[4] * pV2[4] +
pV1[5] * pV2[5] +
pV1[6] * pV2[6] +
pV1[7] * pV2[7] +
pV1[8] * pV2[8] +
pV1[9] * pV2[9] +
pV1[10] * pV2[10] +
pV1[11] * pV2[11] +
pV1[12] * pV2[12] +
pV1[13] * pV2[13] +
pV1[14] * pV2[14] +
pV1[15] * pV2[15];
for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j];
pV1 += 16;
pV2 += 16;
}
return corr / sqrt(norm);
*/
}
double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm)
{
// call usual calcCrossCorr function because SSE does not show big benefit of
// accumulating "norm" value, and also the "norm" rolling algorithm would get
// complicated due to SSE-specific alignment-vs-nonexact correlation rules.
return calcCrossCorr(pV1, pV2, norm);
}
//////////////////////////////////////////////////////////////////////////////
//
// implementation of SSE optimized functions of class 'FIRFilter'
//
//////////////////////////////////////////////////////////////////////////////
#include "FIRFilter.h"
FIRFilterSSE::FIRFilterSSE() : FIRFilter()
{
filterCoeffsAlign = nullptr;
filterCoeffsUnalign = nullptr;
}
FIRFilterSSE::~FIRFilterSSE()
{
delete[] filterCoeffsUnalign;
filterCoeffsAlign = nullptr;
filterCoeffsUnalign = nullptr;
}
// (overloaded) Calculates filter coefficients for SSE routine
void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
{
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Scale the filter coefficients so that it won't be necessary to scale the filtering result
// also rearrange coefficients suitably for SSE
// Ensure that filter coeffs array is aligned to 16-byte boundary
delete[] filterCoeffsUnalign;
filterCoeffsUnalign = new float[2 * newLength + 4];
filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
const float scale = ::pow(0.5, (int)resultDivFactor);
// rearrange the filter coefficients for sse routines
for (auto i = 0U; i < newLength; i ++)
{
filterCoeffsAlign[2 * i + 0] =
filterCoeffsAlign[2 * i + 1] = coeffs[i] * scale;
}
}
// SSE-optimized version of the filter routine for stereo sound
uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const
{
int count = (int)((numSamples - length) & (uint)-2);
int j;
assert(count % 2 == 0);
if (count < 2) return 0;
assert(source != nullptr);
assert(dest != nullptr);
assert((length % 8) == 0);
assert(filterCoeffsAlign != nullptr);
assert(((ulongptr)filterCoeffsAlign) % 16 == 0);
// filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'
#pragma omp parallel for
for (j = 0; j < count; j += 2)
{
const float *pSrc;
float *pDest;
const __m128 *pFil;
__m128 sum1, sum2;
uint i;
pSrc = (const float*)source + j * 2; // source audio data
pDest = dest + j * 2; // destination audio data
pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
// are aligned to 16-byte boundary
sum1 = sum2 = _mm_setzero_ps();
for (i = 0; i < length / 8; i ++)
{
// Unroll loop for efficiency & calculate filter for 2*2 stereo samples
// at each pass
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
// sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
pSrc += 16;
pFil += 4;
}
// Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need
// to sum the two hi- and lo-floats of these registers together.
// post-shuffle & add the filtered values and store to dest.
_mm_storeu_ps(pDest, _mm_add_ps(
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
));
}
// Ideas for further improvement:
// 1. If it could be guaranteed that 'source' were always aligned to 16-byte
// boundary, a faster aligned '_mm_load_ps' instruction could be used.
// 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
// boundary, a faster '_mm_store_ps' instruction could be used.
return (uint)count;
/* original routine in C-language. please notice the C-version has differently
organized coefficients though.
double suml1, suml2;
double sumr1, sumr2;
uint i, j;
for (j = 0; j < count; j += 2)
{
const float *ptr;
const float *pFil;
suml1 = sumr1 = 0.0;
suml2 = sumr2 = 0.0;
ptr = src;
pFil = filterCoeffs;
for (i = 0; i < lengthLocal; i ++)
{
// unroll loop for efficiency.
suml1 += ptr[0] * pFil[0] +
ptr[2] * pFil[2] +
ptr[4] * pFil[4] +
ptr[6] * pFil[6];
sumr1 += ptr[1] * pFil[1] +
ptr[3] * pFil[3] +
ptr[5] * pFil[5] +
ptr[7] * pFil[7];
suml2 += ptr[8] * pFil[0] +
ptr[10] * pFil[2] +
ptr[12] * pFil[4] +
ptr[14] * pFil[6];
sumr2 += ptr[9] * pFil[1] +
ptr[11] * pFil[3] +
ptr[13] * pFil[5] +
ptr[15] * pFil[7];
ptr += 16;
pFil += 8;
}
dest[0] = (float)suml1;
dest[1] = (float)sumr1;
dest[2] = (float)suml2;
dest[3] = (float)sumr2;
src += 4;
dest += 4;
}
*/
}
#endif // SOUNDTOUCH_ALLOW_SSE

View File

@ -0,0 +1,115 @@
////////////////////////////////////////////////////////////////////////////////
///
/// DllTest.cpp : This is small app main routine used for testing sound processing
/// with SoundTouch.dll API
///
/// Author : Copyright (c) Olli Parviainen
/// Author e-mail : oparviai 'at' iki.fi
/// SoundTouch WWW: http://www.surina.net/soundtouch
///
////////////////////////////////////////////////////////////////////////////////
#include <string>
#include <iostream>
#include <fstream>
#include "../SoundTouchDLL.h"
#include "../../SoundStretch/WavFile.h"
using namespace std;
using namespace soundstretch;
// DllTest main
int wmain(int argc, const wchar_t *argv[])
{
// Check program arguments
if (argc < 4)
{
cout << "Too few arguments. Usage: DllTest [infile.wav] [outfile.wav] [sampletype]" << endl;
return -1;
}
wstring inFileName = argv[1];
wstring outFileName = argv[2];
wstring str_sampleType = argv[3];
bool floatSample;
if (str_sampleType == L"float")
{
floatSample = true;
}
else if (str_sampleType == L"short")
{
floatSample = false;
}
else
{
cerr << "Missing or invalid sampletype. Expected either short or float" << endl;
return -1;
}
try
{
// Open input & output WAV files
WavInFile inFile(inFileName);
int numChannels = inFile.getNumChannels();
int sampleRate = inFile.getSampleRate();
WavOutFile outFile(outFileName, sampleRate, inFile.getNumBits(), numChannels);
// Create SoundTouch DLL instance
HANDLE st = soundtouch_createInstance();
soundtouch_setChannels(st, numChannels);
soundtouch_setSampleRate(st, sampleRate);
soundtouch_setPitchSemiTones(st, 2);
cout << "processing with soundtouch.dll routines";
if (floatSample)
{
// Process file with SoundTouch.DLL float sample (default) API
float fbuffer[2048];
int nmax = 2048 / numChannels;
cout << " using float api ..." << endl;
while (inFile.eof() == false)
{
int n = inFile.read(fbuffer, nmax * numChannels) / numChannels;
soundtouch_putSamples(st, fbuffer, n);
do
{
n = soundtouch_receiveSamples(st, fbuffer, nmax);
outFile.write(fbuffer, n * numChannels);
} while (n > 0);
}
}
else
{
// Process file with SoundTouch.DLL int16 (short) sample API.
// Notice that SoundTouch.dll does internally processing using floating
// point routines so the int16 API is not any faster, but provided for
// convenience.
short i16buffer[2048];
int nmax = 2048 / numChannels;
cout << " using i16 api ..." << endl;
while (inFile.eof() == false)
{
int n = inFile.read(i16buffer, nmax * numChannels) / numChannels;
soundtouch_putSamples_i16(st, i16buffer, n);
do
{
n = soundtouch_receiveSamples_i16(st, i16buffer, nmax);
outFile.write(i16buffer, n * numChannels);
} while (n > 0);
}
}
soundtouch_destroyInstance(st);
cout << "done." << endl;
}
catch (const runtime_error &e)
{
cerr << e.what() << endl;
}
return 0;
}

View File

@ -0,0 +1,180 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{E3C0726F-28F4-4F0B-8183-B87CA60C063C}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>DllTest</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<TargetName>$(ProjectName)D</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<TargetName>$(ProjectName)D_x64</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(Platform)\$(Configuration)\</OutDir>
<TargetName>$(ProjectName)_x64</TargetName>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>..\..\..\lib\SoundTouchDllD.lib</AdditionalDependencies>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>..\..\..\lib\SoundTouchDllD_x64.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>..\..\..\lib\SoundTouchDll.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>..\..\..\lib\SoundTouchDll_x64.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<Text Include="ReadMe.txt" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\SoundStretch\WavFile.cpp" />
<ClCompile Include="DllTest.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,10 @@
This is Lazarus Pascal example that loads the SoundTouch dynamic-load library
and queries the library version as a simple example how to load SoundTouch from
Pascal / Lazarus.
Set the SoundTouch dynamic library file name in the 'InitDLL' procedure of
file 'SoundTouchDLL.pas' depending on if you're building for Windows or Linux.
The example expects the the 'libSoundTouchDll.so' (linux) or 'SoundTouch.dll' (Windows)
library binary files is found within this project directory, either via soft-link
(in Linux) or as a copied file.

View File

@ -2,13 +2,8 @@ unit SoundTouchDLL;
//////////////////////////////////////////////////////////////////////////////
//
// SoundTouch.dll wrapper for accessing SoundTouch routines from Delphi/Pascal
//
// Module Author : Christian Budde
//
////////////////////////////////////////////////////////////////////////////////
//
// $Id$
// SoundTouch.dll / libSoundTouchDll.so wrapper for accessing SoundTouch
// routines from Delphi/Pascal/Lazarus
//
////////////////////////////////////////////////////////////////////////////////
//
@ -35,58 +30,60 @@ unit SoundTouchDLL;
interface
uses
Windows;
//uses
//Windows;
type
TSoundTouchHandle = THandle;
// Create a new instance of SoundTouch processor.
TSoundTouchCreateInstance = function : TSoundTouchHandle; stdcall;
TSoundTouchCreateInstance = function : TSoundTouchHandle; cdecl;
// Destroys a SoundTouch processor instance.
TSoundTouchDestroyInstance = procedure (Handle: TSoundTouchHandle); stdcall;
TSoundTouchDestroyInstance = procedure (Handle: TSoundTouchHandle); cdecl;
// Get SoundTouch library version string
TSoundTouchGetVersionString = function : PChar; stdcall;
TSoundTouchGetVersionString = function : PAnsiChar; cdecl;
// Get SoundTouch library version string 2
TSoundTouchGetVersionString2 = procedure(VersionString : PAnsiChar; BufferSize : Integer); cdecl;
// Get SoundTouch library version Id
TSoundTouchGetVersionId = function : Cardinal; stdcall;
TSoundTouchGetVersionId = function : Cardinal; cdecl;
// Sets new rate control value. Normal rate = 1.0, smaller values
// represent slower rate, larger faster rates.
TSoundTouchSetRate = procedure (Handle: TSoundTouchHandle; newRate: Single); stdcall;
TSoundTouchSetRate = procedure (Handle: TSoundTouchHandle; NewRate: Single); cdecl;
// Sets new tempo control value. Normal tempo = 1.0, smaller values
// represent slower tempo, larger faster tempo.
TSoundTouchSetTempo = procedure (Handle: TSoundTouchHandle; newTempo: Single); stdcall;
TSoundTouchSetTempo = procedure (Handle: TSoundTouchHandle; NewTempo: Single); cdecl;
// Sets new rate control value as a difference in percents compared
// to the original rate (-50 .. +100 %);
TSoundTouchSetRateChange = procedure (Handle: TSoundTouchHandle; newRate: Single); stdcall;
TSoundTouchSetRateChange = procedure (Handle: TSoundTouchHandle; NewRate: Single); cdecl;
// Sets new tempo control value as a difference in percents compared
// to the original tempo (-50 .. +100 %);
TSoundTouchSetTempoChange = procedure (Handle: TSoundTouchHandle; newTempo: Single); stdcall;
TSoundTouchSetTempoChange = procedure (Handle: TSoundTouchHandle; NewTempo: Single); cdecl;
// Sets new pitch control value. Original pitch = 1.0, smaller values
// represent lower pitches, larger values higher pitch.
TSoundTouchSetPitch = procedure (Handle: TSoundTouchHandle; newPitch: Single); stdcall;
TSoundTouchSetPitch = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;
// Sets pitch change in octaves compared to the original pitch
// (-1.00 .. +1.00);
TSoundTouchSetPitchOctaves = procedure (Handle: TSoundTouchHandle; newPitch: Single); stdcall;
TSoundTouchSetPitchOctaves = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;
// Sets pitch change in semi-tones compared to the original pitch
// (-12 .. +12);
TSoundTouchSetPitchSemiTones = procedure (Handle: TSoundTouchHandle; newPitch: Single); stdcall;
TSoundTouchSetPitchSemiTones = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;
// Sets the number of channels, 1 = mono, 2 = stereo
TSoundTouchSetChannels = procedure (Handle: TSoundTouchHandle; numChannels: Cardinal); stdcall;
TSoundTouchSetChannels = procedure (Handle: TSoundTouchHandle; NumChannels: Cardinal); cdecl;
// Sets sample rate.
TSoundTouchSetSampleRate = procedure (Handle: TSoundTouchHandle; SampleRate: Cardinal); stdcall;
TSoundTouchSetSampleRate = procedure (Handle: TSoundTouchHandle; SampleRate: Cardinal); cdecl;
// Flushes the last samples from the processing pipeline to the output.
// Clears also the internal processing buffers.
@ -95,7 +92,7 @@ type
// stream. This function may introduce additional blank samples in the end
// of the sound stream, and thus it
// in the middle of a sound stream.
TSoundTouchFlush = procedure (Handle: TSoundTouchHandle); stdcall;
TSoundTouchFlush = procedure (Handle: TSoundTouchHandle); cdecl;
// Adds 'numSamples' pcs of samples from the 'samples' memory position into
// the input of the object. Notice that sample rate _has_to_ be set before
@ -105,53 +102,64 @@ type
NumSamples: Cardinal //< Number of samples in buffer. Notice
//< that in case of stereo-sound a single sample
//< contains data for both channels.
); stdcall;
); cdecl;
TSoundTouchPutSamplesI16 = procedure (Handle: TSoundTouchHandle;
const Samples: Pint16; //< Pointer to sample buffer.
NumSamples: Cardinal //< Number of samples in buffer. Notice
//< that in case of stereo-sound a single sample
//< contains data for both channels.
); cdecl;
// Clears all the samples in the object's output and internal processing
// buffers.
TSoundTouchClear = procedure (Handle: TSoundTouchHandle); stdcall;
TSoundTouchClear = procedure (Handle: TSoundTouchHandle); cdecl;
// Changes a setting controlling the processing system behaviour. See the
// 'SETTING_...' defines for available setting ID's.
//
// \return 'TRUE' if the setting was succesfully changed
// \return 'TRUE' if the setting was successfully changed
TSoundTouchSetSetting = function (Handle: TSoundTouchHandle;
SettingId: Integer; //< Setting ID number. see SETTING_... defines.
Value: Integer //< New setting value.
): Boolean; stdcall;
): Boolean; cdecl;
// Reads a setting controlling the processing system behaviour. See the
// 'SETTING_...' defines for available setting ID's.
//
// \return the setting value.
TSoundTouchGetSetting = function (Handle: TSoundTouchHandle;
settingId: Integer //< Setting ID number, see SETTING_... defines.
): Integer; stdcall;
SettingId: Integer //< Setting ID number, see SETTING_... defines.
): Integer; cdecl;
// Returns number of samples currently unprocessed.
TSoundTouchNumUnprocessedSamples = function (Handle: TSoundTouchHandle): Cardinal; stdcall;
TSoundTouchNumUnprocessedSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;
// Adjusts book-keeping so that given number of samples are removed from beginning of the
// sample buffer without copying them anywhere.
//
// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
// with 'ptrBegin' function.
/// Receive ready samples from the processing pipeline.
///
/// if called with outBuffer=nullptr, just reduces amount of ready samples within the pipeline.
TSoundTouchReceiveSamples = function (Handle: TSoundTouchHandle;
outBuffer: PSingle; //< Buffer where to copy output samples.
maxSamples: Integer //< How many samples to receive at max.
): Cardinal; stdcall;
OutBuffer: PSingle; //< Buffer where to copy output samples.
MaxSamples: Integer //< How many samples to receive at max.
): Cardinal; cdecl;
/// int16 version of soundtouch_receiveSamples(): This converts internal float samples
/// into int16 (short) return data type
TSoundTouchReceiveSamplesI16 = function (Handle: TSoundTouchHandle;
OutBuffer: int16; //< Buffer where to copy output samples.
MaxSamples: Integer //< How many samples to receive at max.
): Cardinal; cdecl;
// Returns number of samples currently available.
TSoundTouchNumSamples = function (Handle: TSoundTouchHandle): Cardinal; stdcall;
TSoundTouchNumSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;
// Returns nonzero if there aren't any samples available for outputting.
TSoundTouchIsEmpty = function (Handle: TSoundTouchHandle): Integer; stdcall;
TSoundTouchIsEmpty = function (Handle: TSoundTouchHandle): Integer; cdecl;
var
SoundTouchCreateInstance : TSoundTouchCreateInstance;
SoundTouchDestroyInstance : TSoundTouchDestroyInstance;
SoundTouchGetVersionString : TSoundTouchGetVersionString;
SoundTouchGetVersionString2 : TSoundTouchGetVersionString2;
SoundTouchGetVersionId : TSoundTouchGetVersionId;
SoundTouchSetRate : TSoundTouchSetRate;
SoundTouchSetTempo : TSoundTouchSetTempo;
@ -164,11 +172,13 @@ var
SoundTouchSetSampleRate : TSoundTouchSetSampleRate;
SoundTouchFlush : TSoundTouchFlush;
SoundTouchPutSamples : TSoundTouchPutSamples;
SoundTouchPutSamplesI16 : TSoundTouchPutSamplesI16;
SoundTouchClear : TSoundTouchClear;
SoundTouchSetSetting : TSoundTouchSetSetting;
SoundTouchGetSetting : TSoundTouchGetSetting;
SoundTouchNumUnprocessedSamples : TSoundTouchNumUnprocessedSamples;
SoundTouchReceiveSamples : TSoundTouchReceiveSamples;
SoundTouchReceiveSamplesI16 : TSoundTouchReceiveSamplesI16;
SoundTouchNumSamples : TSoundTouchNumSamples;
SoundTouchIsEmpty : TSoundTouchIsEmpty;
@ -210,10 +220,10 @@ type
procedure Clear; virtual;
procedure PutSamples(const Samples: PSingle; const NumSamples: Cardinal);
function ReceiveSamples(const outBuffer: PSingle; const maxSamples: Integer): Cardinal;
function ReceiveSamples(const OutBuffer: PSingle; const MaxSamples: Integer): Cardinal;
function SetSetting(const SettingId: Integer; const Value: Integer): Boolean;
function GetSetting(const settingId: Integer): Integer;
function GetSetting(const SettingId: Integer): Integer;
property VersionString: string read GetVersionString;
property VersionID: Cardinal read GetVersionId;
@ -231,17 +241,17 @@ type
property IsEmpty: Integer read GetIsEmpty;
end;
implementation
// list of exported functions and procedures
function IsSoundTouchLoaded: Boolean;
uses
SysUtils;
implementation
{ TSoundTouch }
constructor TSoundTouch.Create;
begin
inherited;
FHandle := SoundTouchCreateInstance;
FHandle := SoundTouchCreateInstance();
FRate := 1;
FTempo := 1;
FPitch := 1;
@ -299,12 +309,12 @@ end;
class function TSoundTouch.GetVersionId: Cardinal;
begin
result := SoundTouchGetVersionId;
result := SoundTouchGetVersionId();
end;
class function TSoundTouch.GetVersionString: string;
begin
result := StrPas(SoundTouchGetVersionString);
result := StrPas(SoundTouchGetVersionString());
end;
procedure TSoundTouch.SetChannels(const Value: Cardinal);
@ -347,10 +357,10 @@ begin
SoundTouchSetRate(FHandle, FRate);
end;
function TSoundTouch.ReceiveSamples(const outBuffer: PSingle;
const maxSamples: Integer): Cardinal;
function TSoundTouch.ReceiveSamples(const OutBuffer: PSingle;
const MaxSamples: Integer): Cardinal;
begin
result := SoundTouchReceiveSamples(FHandle, outBuffer, maxSamples);
result := SoundTouchReceiveSamples(FHandle, OutBuffer, MaxSamples);
end;
procedure TSoundTouch.SetPitchChange(const Value: Single);
@ -418,36 +428,55 @@ begin
end;
var
SoundTouchLibHandle: HINST;
SoundTouchDLL: PAnsiChar = 'SoundTouch.DLL';
SoundTouchLibHandle: THandle;
SoundTouchDLLFile: AnsiString = 'libSoundTouchDll.so';
//SoundTouchDLLFile: AnsiString = 'SoundTouch.dll';
// bpm detect functions. untested -- if these don't work then remove:
bpm_createInstance: function(chan: int32; sampleRate : int32): THandle; cdecl;
bpm_destroyInstance: procedure(h: THandle); cdecl;
bpm_getBpm: function(h: THandle): Single; cdecl;
bpm_putSamples: procedure(h: THandle; const samples: PSingle; numSamples: cardinal); cdecl;
procedure InitDLL;
begin
SoundTouchLibHandle := LoadLibrary(SoundTouchDLL);
{$ifdef mswindows} // Windows
SoundTouchLibHandle := LoadLibrary('.\SoundTouchDll.dll');
{$else} // Unix
SoundTouchLibHandle := LoadLibrary('./libSoundTouchDll.so');
{$endif}
if SoundTouchLibHandle <> 0 then
try
SoundTouchCreateInstance := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 2)); //'soundtouch_createInstance');
SoundTouchDestroyInstance := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 3)); //'soundtouch_destroyInstance');
SoundTouchGetVersionString := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 7)); //'soundtouch_getVersionString');
SoundTouchGetVersionId := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 6)); //'soundtouch_getVersionId');
SoundTouchSetRate := GetProcAddress(SoundTouchLibHandle, PAnsiChar(17)); //'soundtouch_setRate');
SoundTouchSetTempo := GetProcAddress(SoundTouchLibHandle, PAnsiChar(21)); //'soundtouch_setTempo');
SoundTouchSetRateChange := GetProcAddress(SoundTouchLibHandle, PAnsiChar(18)); //'soundtouch_setRateChange');
SoundTouchSetTempoChange := GetProcAddress(SoundTouchLibHandle, PAnsiChar(22)); //'soundtouch_setTempoChange');
SoundTouchSetPitch := GetProcAddress(SoundTouchLibHandle, PAnsiChar(14)); //'soundtouch_setPitch');
SoundTouchSetPitchOctaves := GetProcAddress(SoundTouchLibHandle, PAnsiChar(15)); //'soundtouch_setPitchOctaves');
SoundTouchSetPitchSemiTones := GetProcAddress(SoundTouchLibHandle, PAnsiChar(16)); //'soundtouch_setPitchSemiTones');
SoundTouchSetChannels := GetProcAddress(SoundTouchLibHandle, PAnsiChar(13)); //'soundtouch_setChannels');
SoundTouchSetSampleRate := GetProcAddress(SoundTouchLibHandle, PAnsiChar(19)); //'soundtouch_setSampleRate');
SoundTouchFlush := GetProcAddress(SoundTouchLibHandle, PAnsiChar(4)); //'soundtouch_flush');
SoundTouchPutSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(11)); //'soundtouch_putSamples');
SoundTouchClear := GetProcAddress(SoundTouchLibHandle, PAnsiChar(1)); //'soundtouch_clear');
SoundTouchSetSetting := GetProcAddress(SoundTouchLibHandle, PAnsiChar(20)); //'soundtouch_SetSetting');
SoundTouchGetSetting := GetProcAddress(SoundTouchLibHandle, PAnsiChar(5)); //'soundtouch_setSetting');
SoundTouchNumUnprocessedSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(10)); //'soundtouch_numUnprocessedSamples');
SoundTouchReceiveSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(12)); //'soundtouch_receiveSamples');
SoundTouchNumSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(9)); //'soundtouch_numSamples');
SoundTouchIsEmpty := GetProcAddress(SoundTouchLibHandle, PAnsiChar(8)); //'soundtouch_isEmpty');
Pointer(SoundTouchCreateInstance) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_createInstance');
Pointer(SoundTouchDestroyInstance) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_destroyInstance');
Pointer(SoundTouchGetVersionString) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionString');
Pointer(SoundTouchGetVersionString2) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionString2');
Pointer(SoundTouchGetVersionId) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionId');
Pointer(SoundTouchSetRate) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setRate');
Pointer(SoundTouchSetTempo) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setTempo');
Pointer(SoundTouchSetRateChange) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setRateChange');
Pointer(SoundTouchSetTempoChange) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setTempoChange');
Pointer(SoundTouchSetPitch) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitch');
Pointer(SoundTouchSetPitchOctaves) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitchOctaves');
Pointer(SoundTouchSetPitchSemiTones) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitchSemiTones');
Pointer(SoundTouchSetChannels) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setChannels');
Pointer(SoundTouchSetSampleRate) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setSampleRate');
Pointer(SoundTouchFlush) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_flush');
Pointer(SoundTouchPutSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_putSamples');
Pointer(SoundTouchPutSamplesI16) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_putSamples_i16');
Pointer(SoundTouchClear) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_clear');
Pointer(SoundTouchSetSetting) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_SetSetting');
Pointer(SoundTouchGetSetting) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setSetting');
Pointer(SoundTouchNumUnprocessedSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_numUnprocessedSamples');
Pointer(SoundTouchReceiveSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_receiveSamples');
Pointer(SoundTouchReceiveSamplesI16) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_receiveSamples_i16');
Pointer(SoundTouchNumSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_numSamples');
Pointer(SoundTouchIsEmpty) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_isEmpty');
Pointer(bpm_createInstance) :=GetProcAddress(SoundTouchLibHandle, 'bpm_createInstance');
Pointer(bpm_destroyInstance) :=GetProcAddress(SoundTouchLibHandle, 'bpm_destroyInstance');
Pointer(bpm_getBpm) :=GetProcAddress(SoundTouchLibHandle, 'bpm_getBpm');
Pointer(bpm_putSamples) :=GetProcAddress(SoundTouchLibHandle, 'bpm_putSamples');
except
FreeLibrary(SoundTouchLibHandle);
@ -460,6 +489,12 @@ begin
if SoundTouchLibHandle <> 0 then FreeLibrary(SoundTouchLibHandle);
end;
// returns 'true' if SoundTouch dynamic library has been successfully loaded, otherwise 'false'
function IsSoundTouchLoaded: Boolean;
begin;
result := SoundTouchLibHandle <> 0
end;
initialization
InitDLL;

View File

@ -0,0 +1 @@
../.libs/libSoundTouchDll.so

View File

@ -0,0 +1,36 @@
object Form1: TForm1
Left = 2237
Height = 128
Top = 242
Width = 381
Caption = 'SoundTouch test'
ClientHeight = 128
ClientWidth = 381
LCLVersion = '2.2.0.4'
object Load: TButton
Left = 19
Height = 50
Top = 16
Width = 144
Caption = 'Load SoundTouch'
OnClick = LoadClick
TabOrder = 0
end
object EditVersion: TEdit
Left = 184
Height = 34
Top = 80
Width = 184
TabOrder = 1
Text = 'n/a'
TextHint = 'click to populate'
end
object Label1: TLabel
Left = 19
Height = 17
Top = 90
Width = 156
Caption = 'Soundtouch lib version:'
WordWrap = True
end
end

View File

@ -0,0 +1,49 @@
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, SoundTouchDLL;
type
{ TForm1 }
TForm1 = class(TForm)
EditVersion: TEdit;
Label1: TLabel;
Load: TButton;
procedure LoadClick(Sender: TObject);
private
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.LoadClick(Sender: TObject);
var
version:string;
begin
if IsSoundTouchLoaded() then
version := SoundTouchGetVersionString()
else
version := '<library loading failed>';
EditVersion.Text:= version;
end;
end.

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectOptions>
<Version Value="12"/>
<General>
<SessionStorage Value="InProjectDir"/>
<Title Value="soundtouchtest"/>
<Scaled Value="True"/>
<ResourceType Value="res"/>
<UseXPManifest Value="True"/>
<XPManifest>
<DpiAware Value="True"/>
</XPManifest>
<Icon Value="0"/>
</General>
<BuildModes>
<Item Name="Default" Default="True"/>
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<UseFileFilters Value="True"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
</RunParams>
<RequiredPackages>
<Item>
<PackageName Value="LCL"/>
</Item>
</RequiredPackages>
<Units>
<Unit>
<Filename Value="soundtouchtest.lpr"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="main.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>
<Version Value="11"/>
<Target>
<Filename Value="soundtouchtest"/>
</Target>
<SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf3"/>
</Debugging>
<Options>
<Win32>
<GraphicApplication Value="True"/>
</Win32>
</Options>
</Linking>
</CompilerOptions>
<Debugging>
<Exceptions>
<Item>
<Name Value="EAbort"/>
</Item>
<Item>
<Name Value="ECodetoolError"/>
</Item>
<Item>
<Name Value="EFOpenError"/>
</Item>
</Exceptions>
</Debugging>
</CONFIG>

Some files were not shown because too many files have changed in this diff Show More