Compare commits

...

141 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
87 changed files with 13021 additions and 11718 deletions

15
.gitignore vendored
View File

@ -38,3 +38,18 @@ source/SoundTouchDll/Win32/
source/SoundTouchDll/x64/ source/SoundTouchDll/x64/
source/SoundTouchDll/DllTest/Win32/ source/SoundTouchDll/DllTest/Win32/
source/SoundTouchDll/DllTest/x64/ 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

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 Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc. 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 Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. 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 0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or 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"). this Lesser General Public License (also called "this License").
Each licensee is addressed as "you". Each licensee is addressed as "you".

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 OUT_DIR=.
set TEST_NAME=semmari set TEST_NAME=semmari
set OUT_NAME=out set OUT_NAME=out
set SS=soundstretch set SS=soundstretch_x64
set TEST_PARAM=-pitch=-3 -bpm set TEST_PARAM=-pitch=-3 -bpm
call %SS% %SOUND_DIR%\%TEST_NAME%-8b1.wav %OUT_DIR%\%OUT_NAME%-8b1.wav %TEST_PARAM% call %SS% %SOUND_DIR%\%TEST_NAME%-8b1.wav %OUT_DIR%\%OUT_NAME%-8b1.wav %TEST_PARAM%

View File

@ -1,5 +1,7 @@
#!/bin/sh #!/bin/sh
unset ACLOCAL
if [ "$1" = "--clean" ] if [ "$1" = "--clean" ]
then then
if [ -a Makefile ] if [ -a Makefile ]
@ -14,9 +16,6 @@ then
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 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 else
export AUTOMAKE="automake --add-missing --foreign --copy" export AUTOMAKE="automake --add-missing --foreign --copy"
autoreconf -fisv && rm -f `find . -name "*~"` && rm -f ChangeLog autoreconf -fisv && rm -f `find . -name "*~"` && rm -f ChangeLog

View File

@ -15,22 +15,25 @@ dnl this program; if not, write to the Free Software Foundation, Inc., 59 Temple
dnl Place - Suite 330, Boston, MA 02111-1307, USA dnl Place - Suite 330, Boston, MA 02111-1307, USA
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
AC_INIT([SoundTouch], [2.0.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 dnl Default to libSoundTouch.so.$LIB_SONAME.0.0
LIB_SONAME=1 LIB_SONAME=1
AC_SUBST(LIB_SONAME) AC_SUBST(LIB_SONAME)
AC_CONFIG_AUX_DIR(config) AC_CONFIG_AUX_DIR(config)
AC_CONFIG_MACRO_DIR([config/m4]) AC_CONFIG_MACRO_DIR([config/m4])
AM_CONFIG_HEADER([config.h include/soundtouch_config.h]) AC_CONFIG_HEADERS([config.h include/soundtouch_config.h])
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE
AM_SILENT_RULES([yes]) AM_SILENT_RULES([yes])
#AC_DISABLE_SHARED dnl This makes libtool only build static libs #AC_DISABLE_SHARED dnl This makes libtool only build static libs
AC_DISABLE_STATIC dnl This makes libtool only build shared 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++) 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')" # Set AR_FLAGS to avoid build warning "ar: `u' modifier ignored since `D' is the default (see `U')"
AR_FLAGS='cr' AR_FLAGS='cr'
@ -47,7 +50,7 @@ AC_PROG_INSTALL
#AC_PROG_LN_S #AC_PROG_LN_S
AC_PROG_MAKE_SET AC_PROG_MAKE_SET
AM_PROG_LIBTOOL dnl turn on using libtool LT_INIT dnl turn on using libtool
@ -55,10 +58,11 @@ AM_PROG_LIBTOOL dnl turn on using libtool
dnl ############################################################################ dnl ############################################################################
dnl # Checks for header files # dnl # Checks for header files #
dnl ############################################################################ dnl ############################################################################
AC_HEADER_STDC
#AC_HEADER_SYS_WAIT #AC_HEADER_SYS_WAIT
# add any others you want to check for here # 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 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([The cpuid.h file was not found therefore the x86 optimizations will be disabled.])
@ -77,31 +81,34 @@ AC_C_INLINE
AC_ARG_ENABLE(integer-samples, AC_ARG_ENABLE(integer-samples,
[AC_HELP_STRING([--enable-integer-samples], [AS_HELP_STRING([--enable-integer-samples],[use integer samples instead of floats [default=no]])],,
[use integer samples instead of floats
[default=no]])],,
[enable_integer_samples=no]) [enable_integer_samples=no])
AC_ARG_ENABLE(openmp, AC_ARG_ENABLE(openmp,
[AC_HELP_STRING([--enable-openmp], [AS_HELP_STRING([--enable-openmp],[use parallel multicore calculation through OpenMP [default=no]])],,
[use parallel multicore calculation through OpenMP [default=no]])],,
[enable_openmp=no]) [enable_openmp=no])
# Let the user enable/disable the x86 optimizations. # Let the user enable/disable the x86 optimizations.
# Useful when compiling on non-x86 architectures. # Useful when compiling on non-x86 architectures.
AC_ARG_ENABLE([x86-optimizations], AC_ARG_ENABLE([x86-optimizations],
[AS_HELP_STRING([--enable-x86-optimizations], [AS_HELP_STRING([--enable-x86-optimizations],
[use MMX or SSE optimization [use MMX or SSE optimization [default=yes]])],[enable_x86_optimizations="${enableval}"],
[default=yes]])],[enable_x86_optimizations="${enableval}"],
[enable_x86_optimizations=yes]) [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. # Tell the Makefile.am if the user wants to disable optimizations.
# Makefile.am will enable them by default if support is available. # Makefile.am will enable them by default if support is available.
# Note: We check if optimizations are supported a few lines down. # Note: We check if optimizations are supported a few lines down.
AM_CONDITIONAL([X86_OPTIMIZATIONS], [test "x$enable_x86_optimizations" = "xyes"]) AM_CONDITIONAL([X86_OPTIMIZATIONS], [test "x$enable_x86_optimizations" = "xyes"])
if test "x$enable_integer_samples" = "xyes"; then if test "x$enable_integer_samples" = "xyes"; then
echo "****** Integer sample type enabled ******" echo "****** Integer sample type enabled ******"
AC_DEFINE(SOUNDTOUCH_INTEGER_SAMPLES,1,[Use Integer as Sample type]) AC_DEFINE(SOUNDTOUCH_INTEGER_SAMPLES,1,[Use Integer as Sample type])
@ -109,7 +116,7 @@ else
echo "****** Float sample type enabled ******" echo "****** Float sample type enabled ******"
AC_DEFINE(SOUNDTOUCH_FLOAT_SAMPLES,1,[Use Float as Sample type]) AC_DEFINE(SOUNDTOUCH_FLOAT_SAMPLES,1,[Use Float as Sample type])
fi fi
AM_CONDITIONAL([SOUNDTOUCH_FLOAT_SAMPLES], [test "x$enable_integer_samples" != "xyes"])
if test "x$enable_openmp" = "xyes"; then if test "x$enable_openmp" = "xyes"; then
echo "****** openmp optimizations enabled ******" echo "****** openmp optimizations enabled ******"
@ -195,6 +202,52 @@ else
CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS" CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
fi 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 # Set AM_CXXFLAGS
AC_SUBST([AM_CXXFLAGS], [$AM_CXXFLAGS]) AC_SUBST([AM_CXXFLAGS], [$AM_CXXFLAGS])
@ -217,8 +270,6 @@ AM_CONDITIONAL([HAVE_SSE], [test "x$have_sse_intrinsics" = "xyes"])
dnl ############################################################################ dnl ############################################################################
dnl # Checks for library functions/classes # dnl # Checks for library functions/classes #
dnl ############################################################################ dnl ############################################################################
AC_FUNC_MALLOC
AC_TYPE_SIGNAL
dnl make -lm get added to the LIBS 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]))
@ -251,11 +302,12 @@ AC_CONFIG_FILES([
source/Makefile source/Makefile
source/SoundTouch/Makefile source/SoundTouch/Makefile
source/SoundStretch/Makefile source/SoundStretch/Makefile
source/SoundTouchDLL/Makefile
include/Makefile include/Makefile
]) ])
AC_OUTPUT( AC_CONFIG_FILES([soundtouch.pc
soundtouch.pc ])
) AC_OUTPUT
dnl use 'echo' to put stuff here if you want a message to the builder dnl use 'echo' to put stuff here if you want a message to the builder

View File

@ -196,7 +196,7 @@ namespace soundtouch
/// - "values" receive array of beat detection strengths /// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array. /// - max_num indicates max.size of "pos" and "values" array.
/// ///
/// You can query a suitable array sized by calling this with NULL in "pos" & "values". /// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
/// ///
/// \return number of beats in the arrays. /// \return number of beats in the arrays.
int getBeats(float *pos, float *strength, int max_num); int getBeats(float *pos, float *strength, int max_num);

View File

@ -91,7 +91,7 @@ public:
); );
/// destructor /// destructor
~FIFOSampleBuffer(); ~FIFOSampleBuffer() override;
/// Returns a pointer to the beginning of the output samples. /// Returns a pointer to the beginning of the output samples.
/// This function is provided for accessing the output samples directly. /// This function is provided for accessing the output samples directly.
@ -100,7 +100,7 @@ public:
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin(); virtual SAMPLETYPE *ptrBegin() override;
/// Returns a pointer to the end of the used part of the sample buffer (i.e. /// 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 /// where the new samples are to be inserted). This function may be used for
@ -121,7 +121,7 @@ public:
/// the sample buffer. /// the sample buffer.
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples. virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
uint numSamples ///< Number of samples to insert. uint numSamples ///< Number of samples to insert.
); ) override;
/// Adjusts the book-keeping to increase number of samples in the buffer without /// Adjusts the book-keeping to increase number of samples in the buffer without
/// copying any actual samples. /// copying any actual samples.
@ -139,7 +139,7 @@ public:
/// \return Number of samples returned. /// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max. 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 /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
@ -147,10 +147,10 @@ public:
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
); ) override;
/// Returns number of samples currently available. /// Returns number of samples currently available.
virtual uint numSamples() const; virtual uint numSamples() const override;
/// Sets number of channels, 1 = mono, 2 = stereo. /// Sets number of channels, 1 = mono, 2 = stereo.
void setChannels(int numChannels); void setChannels(int numChannels);
@ -162,14 +162,17 @@ public:
} }
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const; virtual int isEmpty() const override;
/// Clears all the samples. /// Clears all the samples.
virtual void clear(); virtual void clear() override;
/// allow trimming (downwards) amount of samples in pipeline. /// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples /// Returns adjusted amount of samples
uint adjustAmountOfSamples(uint numSamples); uint adjustAmountOfSamples(uint numSamples) override;
/// Add silence to end of buffer
void addSilent(uint nSamples);
}; };
} }

View File

@ -88,11 +88,11 @@ public:
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data. void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
) )
{ {
int oNumSamples = other.numSamples(); const uint oNumSamples = other.numSamples();
putSamples(other.ptrBegin(), oNumSamples); putSamples(other.ptrBegin(), oNumSamples);
other.receiveSamples(oNumSamples); other.receiveSamples(oNumSamples);
}; }
/// Output samples from beginning of the sample buffer. Copies requested samples to /// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than /// output buffer and removes them from the sample buffer. If there are less than
@ -144,8 +144,8 @@ protected:
/// Sets output pipe. /// Sets output pipe.
void setOutPipe(FIFOSamplePipe *pOutput) void setOutPipe(FIFOSamplePipe *pOutput)
{ {
assert(output == NULL); assert(output == nullptr);
assert(pOutput != NULL); assert(pOutput != nullptr);
output = pOutput; output = pOutput;
} }
@ -153,7 +153,7 @@ protected:
/// 'setOutPipe' function. /// 'setOutPipe' function.
FIFOProcessor() FIFOProcessor()
{ {
output = NULL; output = nullptr;
} }
/// Constructor. Configures output pipe. /// Constructor. Configures output pipe.
@ -164,7 +164,7 @@ protected:
} }
/// Destructor. /// Destructor.
virtual ~FIFOProcessor() virtual ~FIFOProcessor() override
{ {
} }
@ -175,7 +175,7 @@ protected:
/// When using this function to output samples, also remember to 'remove' the /// When using this function to output samples, also remember to 'remove' the
/// output samples from the buffer by calling the /// output samples from the buffer by calling the
/// 'receiveSamples(numSamples)' function /// 'receiveSamples(numSamples)' function
virtual SAMPLETYPE *ptrBegin() virtual SAMPLETYPE *ptrBegin() override
{ {
return output->ptrBegin(); return output->ptrBegin();
} }
@ -189,7 +189,7 @@ public:
/// \return Number of samples returned. /// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. virtual uint receiveSamples(SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max. uint maxSamples ///< How many samples to receive at max.
) ) override
{ {
return output->receiveSamples(outBuffer, maxSamples); return output->receiveSamples(outBuffer, maxSamples);
} }
@ -200,26 +200,26 @@ public:
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
) ) override
{ {
return output->receiveSamples(maxSamples); return output->receiveSamples(maxSamples);
} }
/// Returns number of samples currently available. /// Returns number of samples currently available.
virtual uint numSamples() const virtual uint numSamples() const override
{ {
return output->numSamples(); return output->numSamples();
} }
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
virtual int isEmpty() const virtual int isEmpty() const override
{ {
return output->isEmpty(); return output->isEmpty();
} }
/// allow trimming (downwards) amount of samples in pipeline. /// allow trimming (downwards) amount of samples in pipeline.
/// Returns adjusted amount of samples /// Returns adjusted amount of samples
virtual uint adjustAmountOfSamples(uint numSamples) virtual uint adjustAmountOfSamples(uint numSamples) override
{ {
return output->adjustAmountOfSamples(numSamples); return output->adjustAmountOfSamples(numSamples);
} }

View File

@ -56,8 +56,9 @@ typedef unsigned long ulong;
namespace soundtouch namespace soundtouch
{ {
/// Max allowed number of channels /// Max allowed number of channels. This is not a hard limit but to have some
#define SOUNDTOUCH_MAX_CHANNELS 16 /// 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 /// Activate these undef's to overrule the possible sampletype
/// setting inherited from some other header file: /// setting inherited from some other header file:
@ -121,10 +122,10 @@ namespace soundtouch
#endif #endif
// If defined, allows the SIMD-optimized routines to take minor shortcuts // If defined, allows the SIMD-optimized routines to skip unevenly aligned
// for improved performance. Undefine to require faithfully similar SIMD // memory offsets that can cause performance penalty in some SIMD implementations.
// calculations as in normal C implementation. // Causes slight compromise in sound quality.
#define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1 // #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
@ -149,8 +150,9 @@ namespace soundtouch
// floating point samples // floating point samples
typedef float SAMPLETYPE; typedef float SAMPLETYPE;
// data type for sample accumulation: Use double to utilize full precision. // data type for sample accumulation: Use float also here to enable
typedef double LONG_SAMPLETYPE; // efficient autovectorization
typedef float LONG_SAMPLETYPE;
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS #ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
// Allow SSE optimizations // Allow SSE optimizations
@ -159,7 +161,13 @@ namespace soundtouch
#endif // SOUNDTOUCH_INTEGER_SAMPLES #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 switch to disable throwing std exceptions:
// #define ST_NO_EXCEPTION_HANDLING 1 // #define ST_NO_EXCEPTION_HANDLING 1

View File

@ -72,10 +72,10 @@ namespace soundtouch
{ {
/// Soundtouch library version string /// Soundtouch library version string
#define SOUNDTOUCH_VERSION "2.1pre" #define SOUNDTOUCH_VERSION "2.3.3"
/// SoundTouch library version id /// SoundTouch library version id
#define SOUNDTOUCH_VERSION_ID (20009) #define SOUNDTOUCH_VERSION_ID (20303)
// //
// Available setting IDs for the 'setSetting' & 'get_setting' functions: // Available setting IDs for the 'setSetting' & 'get_setting' functions:
@ -209,7 +209,7 @@ protected :
public: public:
SoundTouch(); SoundTouch();
virtual ~SoundTouch(); virtual ~SoundTouch() override;
/// Get SoundTouch library version string /// Get SoundTouch library version string
static const char *getVersionString(); static const char *getVersionString();
@ -287,7 +287,7 @@ public:
uint numSamples ///< Number of samples in buffer. Notice uint numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample ///< that in case of stereo-sound a single sample
///< contains data for both channels. ///< contains data for both channels.
); ) override;
/// Output samples from beginning of the sample buffer. Copies requested samples to /// Output samples from beginning of the sample buffer. Copies requested samples to
/// output buffer and removes them from the sample buffer. If there are less than /// output buffer and removes them from the sample buffer. If there are less than
@ -296,7 +296,7 @@ public:
/// \return Number of samples returned. /// \return Number of samples returned.
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples. virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
uint maxSamples ///< How many samples to receive at max. 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 /// Adjusts book-keeping so that given number of samples are removed from beginning of the
/// sample buffer without copying them anywhere. /// sample buffer without copying them anywhere.
@ -304,11 +304,11 @@ public:
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
/// with 'ptrBegin' function. /// with 'ptrBegin' function.
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe. 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 /// Clears all the samples in the object's output and internal processing
/// buffers. /// buffers.
virtual void clear(); virtual void clear() override;
/// Changes a setting controlling the processing system behaviour. See the /// Changes a setting controlling the processing system behaviour. See the
/// 'SETTING_...' defines for available setting ID's. /// 'SETTING_...' defines for available setting ID's.

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

@ -3,3 +3,6 @@
/* Use Integer as Sample type */ /* Use Integer as Sample type */
#undef SOUNDTOUCH_INTEGER_SAMPLES #undef SOUNDTOUCH_INTEGER_SAMPLES
/* Use ARM NEON extension */
#undef SOUNDTOUCH_USE_NEON

View File

@ -31,8 +31,9 @@ echo ***************************************************************************
echo ** echo **
echo ** ERROR: Visual Studio path not set. echo ** ERROR: Visual Studio path not set.
echo ** echo **
echo ** Run "vsvars32.bat" or "vcvars32.bat" from Visual Studio installation dir, echo ** Open "tools"->"Developer Command Line" from Visual Studio IDE, or
echo ** e.g. "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin", 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 ** then try again.
echo ** echo **
echo **************************************************************************** echo ****************************************************************************

View File

@ -1,5 +1,7 @@
# SoundTouch library # 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: 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 **tempo** while maintaining the original pitch
* Change **pitch** while maintaining the original tempo * Change **pitch** while maintaining the original tempo
@ -7,7 +9,9 @@ SoundTouch is an open-source audio processing library that allows changing the s
same time same time
* Change any combination of tempo/pitch/rate * Change any combination of tempo/pitch/rate
Visit [SoundTouch website](https://www.surina.net/soundtouch) and see the [README file](README.html) for more information and audio examples. 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 ## Example
@ -17,7 +21,7 @@ Use SoundStretch example app for modifying wav audio files, for example as follo
soundstretch my_original_file.wav output_file.wav -tempo=+15 -pitch=-3 soundstretch my_original_file.wav output_file.wav -tempo=+15 -pitch=-3
``` ```
See the [README file](README.html) for more usage examples and instructions how to build SoundTouch + SoundStretch. 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. Ready [SoundStretch application executables](https://www.surina.net/soundtouch/download.html) are available for download for Windows and Mac OS.
@ -33,6 +37,18 @@ SoundTouch is written in C++ and compiles in virtually any platform:
The source code package includes dynamic library import modules for C#, Java and Pascal/Delphi languages. 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 ## License
SoundTouch is released under LGPL v2.1: SoundTouch is released under LGPL v2.1:

View File

@ -103,6 +103,7 @@ in the <strong>soundtouch-jni.cpp </strong>source code file for more details.</p
the Java interface class that loasd & accesses the JNI routines in the natively compiled library. 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 The example Android application uses this class as interface for processing audio files
with SoundTouch.</li> with SoundTouch.</li>
<li><b>Android-lib/build.gradle</b>: Top level build script file for Android Studio 3.1.4+</li>
</ul> </ul>
<p> <p>
Feel free to examine and extend the provided cpp/java source code example file pair to Feel free to examine and extend the provided cpp/java source code example file pair to

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

@ -1,22 +1,8 @@
# Copyright (C) 2010 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../include $(LOCAL_PATH)/../../SoundStretch
# *** Remember: Change -O0 into -O2 in add-applications.mk *** # *** Remember: Change -O0 into -O2 in add-applications.mk ***
LOCAL_MODULE := soundtouch LOCAL_MODULE := soundtouch
@ -38,7 +24,7 @@ LOCAL_LDLIBS += -llog
# Custom Flags: # Custom Flags:
# -fvisibility=hidden : don't export all symbols # -fvisibility=hidden : don't export all symbols
LOCAL_CFLAGS += -fvisibility=hidden -I ../../../include -fdata-sections -ffunction-sections LOCAL_CFLAGS += -fvisibility=hidden -fdata-sections -ffunction-sections -ffast-math
# OpenMP mode : enable these flags to enable using OpenMP for parallel computation # OpenMP mode : enable these flags to enable using OpenMP for parallel computation
#LOCAL_CFLAGS += -fopenmp #LOCAL_CFLAGS += -fopenmp

View File

@ -4,6 +4,6 @@
APP_ABI := all #armeabi-v7a armeabi APP_ABI := all #armeabi-v7a armeabi
APP_OPTIM := release APP_OPTIM := release
APP_STL := stlport_static APP_STL := c++_static
APP_CPPFLAGS := -fexceptions # -D SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS APP_CPPFLAGS := -fexceptions # -D SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS

View File

@ -41,12 +41,12 @@ static void _setErrmsg(const char *msg)
_errMsg = msg; _errMsg = msg;
} }
#if 0 // apparently following workaround not needed any more with concurrent Android SDKs
#ifdef _OPENMP #ifdef _OPENMP
#include <pthread.h> #include <pthread.h>
extern pthread_key_t gomp_tls_key; extern pthread_key_t gomp_tls_key;
static void * _p_gomp_tls = NULL; static void * _p_gomp_tls = nullptr;
/// Function to initialize threading for OpenMP. /// Function to initialize threading for OpenMP.
/// ///
@ -54,7 +54,7 @@ static void * _p_gomp_tls = NULL;
/// called from the Android App main thread because in the main thread the gomp_tls storage is /// 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. /// 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, /// Thus if OpenMP routines are invoked from some other thread than the main thread,
/// the OpenMP routine will crash the application due to NULL pointer access on uninitialized storage. /// 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. /// 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" /// In order this to work, the Application main thread needws to call at least "getVersionString"
@ -63,7 +63,7 @@ static int _init_threading(bool warn)
{ {
void *ptr = pthread_getspecific(gomp_tls_key); void *ptr = pthread_getspecific(gomp_tls_key);
LOGV("JNI thread-specific TLS storage %ld", (long)ptr); LOGV("JNI thread-specific TLS storage %ld", (long)ptr);
if (ptr == NULL) if (ptr == nullptr)
{ {
LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls); LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);
pthread_setspecific(gomp_tls_key, _p_gomp_tls); pthread_setspecific(gomp_tls_key, _p_gomp_tls);
@ -74,7 +74,7 @@ static int _init_threading(bool warn)
_p_gomp_tls = ptr; _p_gomp_tls = ptr;
} }
// Where critical, show warning if storage still not properly initialized // Where critical, show warning if storage still not properly initialized
if ((warn) && (_p_gomp_tls == NULL)) if ((warn) && (_p_gomp_tls == nullptr))
{ {
_setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!"); _setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");
return -1; return -1;
@ -90,6 +90,7 @@ static int _init_threading(bool warn)
} }
#endif #endif
#endif
// Processes the sound file // Processes the sound file
static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName) static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
@ -162,8 +163,9 @@ extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionSt
// Call example SoundTouch routine // Call example SoundTouch routine
verStr = SoundTouch::getVersionString(); verStr = SoundTouch::getVersionString();
/// gomp_tls storage bug workaround - see comments in _init_threading() function! // gomp_tls storage bug workaround - see comments in _init_threading() function!
_init_threading(false); // update: apparently this is not needed any more with concurrent Android SDKs
// _init_threading(false);
int threads = 0; int threads = 0;
#pragma omp parallel #pragma omp parallel
@ -232,7 +234,8 @@ extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIE
LOGV("JNI process file %s", inputFile); LOGV("JNI process file %s", inputFile);
/// gomp_tls storage bug workaround - see comments in _init_threading() function! /// gomp_tls storage bug workaround - see comments in _init_threading() function!
if (_init_threading(true)) return -1; // update: apparently this is not needed any more with concurrent Android SDKs
// if (_init_threading(true)) return -1;
try try
{ {

View File

@ -17,8 +17,9 @@
include $(top_srcdir)/config/am_include.mk include $(top_srcdir)/config/am_include.mk
SUBDIRS=SoundTouch SoundStretch if SOUNDTOUCH_FLOAT_SAMPLES
# build SoundTouchDLL only if float samples used
# set to something if you want other stuff to be included in the distribution tarball SUBDIRS=SoundTouch SoundStretch SoundTouchDLL
#EXTRA_DIST= else
SUBDIRS=SoundTouch SoundStretch
endif

View File

@ -40,11 +40,11 @@ soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp
soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm
## linker flags. ## linker flags.
# OP 2011-7-17 Linker flag -s disabled to prevent stripping symbols by default # Linker flag -s disabled to prevent stripping symbols by default
#soundstretch_LDFLAGS=-s #soundstretch_LDFLAGS=-s
## additional compiler flags ## additional compiler flags
soundstretch_CXXFLAGS=-O3 $(AM_CXXFLAGS) soundstretch_CXXFLAGS=$(AM_CXXFLAGS)
#clean-local: #clean-local:
# -rm -f additional-files-to-remove-on-make-clean # -rm -f additional-files-to-remove-on-make-clean

View File

@ -30,12 +30,15 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <string> #include <string>
#include <stdlib.h> #include <cstdlib>
#include "RunParameters.h" #include "RunParameters.h"
using namespace std; using namespace std;
namespace soundstretch
{
// Program usage instructions // Program usage instructions
static const char licenseText[] = static const char licenseText[] =
@ -94,9 +97,8 @@ static int _toLowerCase(int c)
return c; return c;
} }
// Constructor // Constructor
RunParameters::RunParameters(const int nParams, const char * const paramStr[]) RunParameters::RunParameters(int nParams, const CHARTYPE* paramStr[])
{ {
int i; int i;
int nFirstParam; int nFirstParam;
@ -112,28 +114,17 @@ RunParameters::RunParameters(const int nParams, const char * const paramStr[])
} }
string msg = whatText; string msg = whatText;
msg += usage; msg += usage;
ST_THROW_RT_ERROR(msg.c_str()); throw(msg);
} }
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 // Get input & output file names
inFileName = (char*)paramStr[1]; inFileName = paramStr[1];
outFileName = (char*)paramStr[2]; outFileName = paramStr[2];
if (outFileName[0] == '-') if (outFileName[0] == '-')
{ {
// no outputfile name was given but parameters // outputfile name was omitted but other parameter switches given instead
outFileName = NULL; outFileName = STRING_CONST("");
nFirstParam = 2; nFirstParam = 2;
} }
else else
@ -182,25 +173,33 @@ void RunParameters::checkLimits()
} }
} }
// Convert STRING to std::string. Actually needed only if STRING is std::wstring, but conversion penalty is negligible
// Unknown switch parameter -- throws an exception with an error message std::string convertString(const STRING& str)
void RunParameters::throwIllegalParamExp(const string &str) const
{ {
string msg = "ERROR : Illegal parameter \""; std::string res;
msg += str; for (auto c : str)
msg += "\".\n\n"; {
msg += usage; res += (char)c;
ST_THROW_RT_ERROR(msg.c_str()); }
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 void RunParameters::throwLicense() const
{ {
ST_THROW_RT_ERROR(licenseText); ST_THROW_RT_ERROR(licenseText);
} }
double RunParameters::parseSwitchValue(const STRING& str) const
float RunParameters::parseSwitchValue(const string &str) const
{ {
int pos; int pos;
@ -212,14 +211,14 @@ float RunParameters::parseSwitchValue(const string &str) const
} }
// Read numerical parameter value after '=' // Read numerical parameter value after '='
return (float)atof(str.substr(pos + 1).c_str()); return stof(str.substr(pos + 1).c_str());
} }
// Interprets a single switch parameter string of format "-switch=xx" // Interprets a single switch parameter string of format "-switch=xx"
// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores // Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
// switch values into 'params' structure. // switch values into 'params' structure.
void RunParameters::parseSwitchParam(const string &str) void RunParameters::parseSwitchParam(const STRING& str)
{ {
int upS; int upS;
@ -289,3 +288,5 @@ void RunParameters::parseSwitchParam(const string &str)
throwIllegalParamExp(str); throwIllegalParamExp(str);
} }
} }
}

View File

@ -32,34 +32,39 @@
#ifndef RUNPARAMETERS_H #ifndef RUNPARAMETERS_H
#define RUNPARAMETERS_H #define RUNPARAMETERS_H
#include "STTypes.h"
#include <string> #include <string>
#include "STTypes.h"
#include "SS_CharTypes.h"
#include "WavFile.h"
using namespace std; namespace soundstretch
{
/// Parses command line parameters into program parameters /// Parses command line parameters into program parameters
class RunParameters class RunParameters
{ {
private: private:
void throwIllegalParamExp(const string &str) const; void throwIllegalParamExp(const STRING& str) const;
void throwLicense() const; void throwLicense() const;
void parseSwitchParam(const string &str); void parseSwitchParam(const STRING& str);
void checkLimits(); void checkLimits();
float parseSwitchValue(const string &str) const; double parseSwitchValue(const STRING& tr) const;
public: public:
char *inFileName; STRING inFileName;
char *outFileName; STRING outFileName;
float tempoDelta; double tempoDelta{ 0 };
float pitchDelta; double pitchDelta{ 0 };
float rateDelta; double rateDelta{ 0 };
int quick; int quick{ 0 };
int noAntiAlias; int noAntiAlias{ 0 };
float goalBPM; double goalBPM{ 0 };
bool detectBPM; bool detectBPM{ false };
bool speech; bool speech{ false };
RunParameters(const int nParams, const char * const paramStr[]); RunParameters(int nParams, const CHARTYPE* paramStr[]);
}; };
}
#endif #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

View File

@ -42,14 +42,23 @@
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <cstring> #include <cstring>
#include <assert.h> #include <cassert>
#include <limits.h> #include <climits>
#include "WavFile.h" #include "WavFile.h"
#include "STTypes.h" #include "STTypes.h"
using namespace std; using namespace std;
namespace soundstretch
{
#if _WIN32
#define FOPEN(name, mode) _wfopen(name, STRING_CONST(mode))
#else
#define FOPEN(name, mode) fopen(name, mode)
#endif
static const char riffStr[] = "RIFF"; static const char riffStr[] = "RIFF";
static const char waveStr[] = "WAVE"; static const char waveStr[] = "WAVE";
static const char fmtStr[] = "fmt "; static const char fmtStr[] = "fmt ";
@ -66,67 +75,67 @@ static const char dataStr[] = "data";
// while PowerPC of Mac's and many other RISC cpu's are big-endian. // while PowerPC of Mac's and many other RISC cpu's are big-endian.
#ifdef BYTE_ORDER #ifdef BYTE_ORDER
// In gcc compiler detect the byte order automatically // In gcc compiler detect the byte order automatically
#if BYTE_ORDER == BIG_ENDIAN #if BYTE_ORDER == BIG_ENDIAN
// big-endian platform. // big-endian platform.
#define _BIG_ENDIAN_ #define _BIG_ENDIAN_
#endif #endif
#endif #endif
#ifdef _BIG_ENDIAN_ #ifdef _BIG_ENDIAN_
// big-endian CPU, swap bytes in 16 & 32 bit words // big-endian CPU, swap bytes in 16 & 32 bit words
// helper-function to swap byte-order of 32bit integer // helper-function to swap byte-order of 32bit integer
static inline int _swap32(int &dwData) static inline int _swap32(int& dwData)
{ {
dwData = ((dwData >> 24) & 0x000000FF) | dwData = ((dwData >> 24) & 0x000000FF) |
((dwData >> 8) & 0x0000FF00) | ((dwData >> 8) & 0x0000FF00) |
((dwData << 8) & 0x00FF0000) | ((dwData << 8) & 0x00FF0000) |
((dwData << 24) & 0xFF000000); ((dwData << 24) & 0xFF000000);
return dwData; return dwData;
} }
// helper-function to swap byte-order of 16bit integer // helper-function to swap byte-order of 16bit integer
static inline short _swap16(short &wData) static inline short _swap16(short& wData)
{ {
wData = ((wData >> 8) & 0x00FF) | wData = ((wData >> 8) & 0x00FF) |
((wData << 8) & 0xFF00); ((wData << 8) & 0xFF00);
return wData; return wData;
} }
// helper-function to swap byte-order of buffer of 16bit integers // helper-function to swap byte-order of buffer of 16bit integers
static inline void _swap16Buffer(short *pData, int numWords) static inline void _swap16Buffer(short* pData, int numWords)
{ {
int i; int i;
for (i = 0; i < numWords; i ++) for (i = 0; i < numWords; i++)
{ {
pData[i] = _swap16(pData[i]); pData[i] = _swap16(pData[i]);
} }
} }
#else // BIG_ENDIAN #else // BIG_ENDIAN
// little-endian CPU, WAV file is ok as such // little-endian CPU, WAV file is ok as such
// dummy helper-function // dummy helper-function
static inline int _swap32(int &dwData) static inline int _swap32(int& dwData)
{ {
// do nothing // do nothing
return dwData; return dwData;
} }
// dummy helper-function // dummy helper-function
static inline short _swap16(short &wData) static inline short _swap16(short& wData)
{ {
// do nothing // do nothing
return wData; return wData;
} }
// dummy helper-function // dummy helper-function
static inline void _swap16Buffer(short *pData, int numBytes) static inline void _swap16Buffer(short*, int)
{ {
// do nothing // do nothing
} }
#endif // BIG_ENDIAN #endif // BIG_ENDIAN
@ -138,7 +147,7 @@ static const char dataStr[] = "data";
WavFileBase::WavFileBase() WavFileBase::WavFileBase()
{ {
convBuff = NULL; convBuff = nullptr;
convBuffSize = 0; convBuffSize = 0;
} }
@ -151,7 +160,7 @@ WavFileBase::~WavFileBase()
/// Get pointer to conversion buffer of at min. given size /// Get pointer to conversion buffer of at min. given size
void *WavFileBase::getConvBuffer(int sizeBytes) void* WavFileBase::getConvBuffer(int sizeBytes)
{ {
if (convBuffSize < sizeBytes) if (convBuffSize < sizeBytes)
{ {
@ -169,32 +178,26 @@ void *WavFileBase::getConvBuffer(int sizeBytes)
// Class WavInFile // Class WavInFile
// //
WavInFile::WavInFile(const char *fileName) WavInFile::WavInFile(const STRING& fileName)
{ {
// Try to open the file for reading // Try to open the file for reading
fptr = fopen(fileName, "rb"); fptr = FOPEN(fileName.c_str(), "rb");
if (fptr == NULL) if (fptr == nullptr)
{ {
// didn't succeed ST_THROW_RT_ERROR("Error : Unable to open file for reading.");
string msg = "Error : Unable to open file \"";
msg += fileName;
msg += "\" for reading.";
ST_THROW_RT_ERROR(msg.c_str());
} }
init(); init();
} }
WavInFile::WavInFile(FILE *file) WavInFile::WavInFile(FILE* file)
{ {
// Try to open the file for reading // Try to open the file for reading
fptr = file; fptr = file;
if (!file) if (!file)
{ {
// didn't succeed ST_THROW_RT_ERROR("Error : Unable to access input stream for reading");
string msg = "Error : Unable to access input stream for reading";
ST_THROW_RT_ERROR(msg.c_str());
} }
init(); init();
@ -213,7 +216,6 @@ void WavInFile::init()
hdrsOk = readWavHeaders(); hdrsOk = readWavHeaders();
if (hdrsOk != 0) if (hdrsOk != 0)
{ {
// Something didn't match in the wav file headers
ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file"); ST_THROW_RT_ERROR("Input file is corrupt or not a WAV file");
} }
@ -223,7 +225,6 @@ void WavInFile::init()
(header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) || (header.format.byte_per_sample < 1) || (header.format.byte_per_sample > 320) ||
(header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32)) (header.format.bits_per_sample < 8) || (header.format.bits_per_sample > 32))
{ {
// Something didn't match in the wav file headers
ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters."); ST_THROW_RT_ERROR("Error: Illegal wav file header format parameters.");
} }
@ -234,7 +235,7 @@ void WavInFile::init()
WavInFile::~WavInFile() WavInFile::~WavInFile()
{ {
if (fptr) fclose(fptr); if (fptr) fclose(fptr);
fptr = NULL; fptr = nullptr;
} }
@ -260,7 +261,7 @@ int WavInFile::checkCharTags() const
} }
int WavInFile::read(unsigned char *buffer, int maxElems) int WavInFile::read(unsigned char* buffer, int maxElems)
{ {
int numBytes; int numBytes;
uint afterDataRead; uint afterDataRead;
@ -289,7 +290,7 @@ int WavInFile::read(unsigned char *buffer, int maxElems)
} }
int WavInFile::read(short *buffer, int maxElems) int WavInFile::read(short* buffer, int maxElems)
{ {
unsigned int afterDataRead; unsigned int afterDataRead;
int numBytes; int numBytes;
@ -301,12 +302,12 @@ int WavInFile::read(short *buffer, int maxElems)
case 8: case 8:
{ {
// 8 bit format // 8 bit format
unsigned char *temp = (unsigned char*)getConvBuffer(maxElems); unsigned char* temp = (unsigned char*)getConvBuffer(maxElems);
int i; int i;
numElems = read(temp, maxElems); numElems = read(temp, maxElems);
// convert from 8 to 16 bit // convert from 8 to 16 bit
for (i = 0; i < numElems; i ++) for (i = 0; i < numElems; i++)
{ {
buffer[i] = (short)(((short)temp[i] - 128) * 256); buffer[i] = (short)(((short)temp[i] - 128) * 256);
} }
@ -333,7 +334,7 @@ int WavInFile::read(short *buffer, int maxElems)
numElems = numBytes / 2; numElems = numBytes / 2;
// 16bit samples, swap byte order if necessary // 16bit samples, swap byte order if necessary
_swap16Buffer((short *)buffer, numElems); _swap16Buffer((short*)buffer, numElems);
break; break;
} }
@ -353,7 +354,7 @@ int WavInFile::read(short *buffer, int maxElems)
/// Read data in float format. Notice that when reading in float format /// Read data in float format. Notice that when reading in float format
/// 8/16/24/32 bit sample formats are supported /// 8/16/24/32 bit sample formats are supported
int WavInFile::read(float *buffer, int maxElems) int WavInFile::read(float* buffer, int maxElems)
{ {
unsigned int afterDataRead; unsigned int afterDataRead;
int numBytes; int numBytes;
@ -382,7 +383,7 @@ int WavInFile::read(float *buffer, int maxElems)
} }
// read raw data into temporary buffer // read raw data into temporary buffer
char *temp = (char*)getConvBuffer(numBytes); char* temp = (char*)getConvBuffer(numBytes);
numBytes = (int)fread(temp, 1, numBytes, fptr); numBytes = (int)fread(temp, 1, numBytes, fptr);
dataRead += numBytes; dataRead += numBytes;
@ -393,9 +394,9 @@ int WavInFile::read(float *buffer, int maxElems)
{ {
case 1: case 1:
{ {
unsigned char *temp2 = (unsigned char*)temp; unsigned char* temp2 = (unsigned char*)temp;
double conv = 1.0 / 128.0; double conv = 1.0 / 128.0;
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
buffer[i] = (float)(temp2[i] * conv - 1.0); buffer[i] = (float)(temp2[i] * conv - 1.0);
} }
@ -404,9 +405,9 @@ int WavInFile::read(float *buffer, int maxElems)
case 2: case 2:
{ {
short *temp2 = (short*)temp; short* temp2 = (short*)temp;
double conv = 1.0 / 32768.0; double conv = 1.0 / 32768.0;
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
short value = temp2[i]; short value = temp2[i];
buffer[i] = (float)(_swap16(value) * conv); buffer[i] = (float)(_swap16(value) * conv);
@ -416,9 +417,9 @@ int WavInFile::read(float *buffer, int maxElems)
case 3: case 3:
{ {
char *temp2 = (char *)temp; char* temp2 = (char*)temp;
double conv = 1.0 / 8388608.0; double conv = 1.0 / 8388608.0;
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
int value = *((int*)temp2); int value = *((int*)temp2);
value = _swap32(value) & 0x00ffffff; // take 24 bits value = _swap32(value) & 0x00ffffff; // take 24 bits
@ -431,10 +432,10 @@ int WavInFile::read(float *buffer, int maxElems)
case 4: case 4:
{ {
int *temp2 = (int *)temp; int* temp2 = (int*)temp;
double conv = 1.0 / 2147483648.0; double conv = 1.0 / 2147483648.0;
assert(sizeof(int) == 4); assert(sizeof(int) == 4);
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
int value = temp2[i]; int value = temp2[i];
buffer[i] = (float)(_swap32(value) * conv); buffer[i] = (float)(_swap32(value) * conv);
@ -450,7 +451,7 @@ int WavInFile::read(float *buffer, int maxElems)
int WavInFile::eof() const int WavInFile::eof() const
{ {
// return true if all data has been read or file eof has reached // return true if all data has been read or file eof has reached
return (dataRead == header.data.data_len || feof(fptr)); return ((uint)dataRead == header.data.data_len || feof(fptr));
} }
@ -462,7 +463,7 @@ static int isAlpha(char c)
// test if all characters are between a white space ' ' and little 'z' // test if all characters are between a white space ' ' and little 'z'
static int isAlphaStr(const char *str) static int isAlphaStr(const char* str)
{ {
char c; char c;
@ -470,7 +471,7 @@ static int isAlphaStr(const char *str)
while (c) while (c)
{ {
if (isAlpha(c) == 0) return 0; if (isAlpha(c) == 0) return 0;
str ++; str++;
c = str[0]; c = str[0];
} }
@ -483,7 +484,7 @@ int WavInFile::readRIFFBlock()
if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1; if (fread(&(header.riff), sizeof(WavRiff), 1, fptr) != 1) return -1;
// swap 32bit data byte order if necessary // swap 32bit data byte order if necessary
_swap32((int &)header.riff.package_len); _swap32((int&)header.riff.package_len);
// header.riff.riff_char should equal to 'RIFF'); // header.riff.riff_char should equal to 'RIFF');
if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1; if (memcmp(riffStr, header.riff.riff_char, 4) != 0) return -1;
@ -500,7 +501,7 @@ int WavInFile::readHeaderBlock()
string sLabel; string sLabel;
// lead label string // lead label string
if (fread(label, 1, 4, fptr) !=4) return -1; if (fread(label, 1, 4, fptr) != 4) return -1;
label[4] = 0; label[4] = 0;
if (isAlphaStr(label) == 0) return -1; // not a valid label if (isAlphaStr(label) == 0) return -1; // not a valid label
@ -536,12 +537,12 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1; if (fread(&(header.format.fixed), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary // swap byte order if necessary
_swap16((short &)header.format.fixed); // short int fixed; _swap16((short&)header.format.fixed); // short int fixed;
_swap16((short &)header.format.channel_number); // short int channel_number; _swap16((short&)header.format.channel_number); // short int channel_number;
_swap32((int &)header.format.sample_rate); // int sample_rate; _swap32((int&)header.format.sample_rate); // int sample_rate;
_swap32((int &)header.format.byte_rate); // int byte_rate; _swap32((int&)header.format.byte_rate); // int byte_rate;
_swap16((short &)header.format.byte_per_sample); // short int byte_per_sample; _swap16((short&)header.format.byte_per_sample); // short int byte_per_sample;
_swap16((short &)header.format.bits_per_sample); // short int bits_per_sample; _swap16((short&)header.format.bits_per_sample); // short int bits_per_sample;
// if format_len is larger than expected, skip the extra data // if format_len is larger than expected, skip the extra data
if (nDump > 0) if (nDump > 0)
@ -581,7 +582,7 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.fact.fact_sample_len), nLen, 1, fptr) != 1) return -1; if (fread(&(header.fact.fact_sample_len), nLen, 1, fptr) != 1) return -1;
// swap byte order if necessary // swap byte order if necessary
_swap32((int &)header.fact.fact_sample_len); // int sample_length; _swap32((int&)header.fact.fact_sample_len); // int sample_length;
// if fact_len is larger than expected, skip the extra data // if fact_len is larger than expected, skip the extra data
if (nDump > 0) if (nDump > 0)
@ -598,7 +599,7 @@ int WavInFile::readHeaderBlock()
if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1; if (fread(&(header.data.data_len), sizeof(uint), 1, fptr) != 1) return -1;
// swap byte order if necessary // swap byte order if necessary
_swap32((int &)header.data.data_len); _swap32((int&)header.data.data_len);
return 1; return 1;
} }
@ -611,7 +612,7 @@ int WavInFile::readHeaderBlock()
// read length // read length
if (fread(&len, sizeof(len), 1, fptr) != 1) return -1; if (fread(&len, sizeof(len), 1, fptr) != 1) return -1;
// scan through the block // scan through the block
for (i = 0; i < len; i ++) for (i = 0; i < len; i++)
{ {
if (fread(&temp, 1, 1, fptr) != 1) return -1; if (fread(&temp, 1, 1, fptr) != 1) return -1;
if (feof(fptr)) return -1; // unexpected eof if (feof(fptr)) return -1; // unexpected eof
@ -703,17 +704,13 @@ uint WavInFile::getElapsedMS() const
// Class WavOutFile // Class WavOutFile
// //
WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels) WavOutFile::WavOutFile(const STRING& fileName, int sampleRate, int bits, int channels)
{ {
bytesWritten = 0; bytesWritten = 0;
fptr = fopen(fileName, "wb"); fptr = FOPEN(fileName.c_str(), "wb");
if (fptr == NULL) if (fptr == nullptr)
{ {
string msg = "Error : Unable to open file \""; ST_THROW_RT_ERROR("Error : Unable to open file for writing.");
msg += fileName;
msg += "\" for writing.";
//pmsg = msg.c_str;
ST_THROW_RT_ERROR(msg.c_str());
} }
fillInHeader(sampleRate, bits, channels); fillInHeader(sampleRate, bits, channels);
@ -721,14 +718,13 @@ WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int chann
} }
WavOutFile::WavOutFile(FILE *file, int sampleRate, int bits, int channels) WavOutFile::WavOutFile(FILE* file, int sampleRate, int bits, int channels)
{ {
bytesWritten = 0; bytesWritten = 0;
fptr = file; fptr = file;
if (fptr == NULL) if (fptr == nullptr)
{ {
string msg = "Error : Unable to access output file stream."; ST_THROW_RT_ERROR("Error : Unable to access output file stream.");
ST_THROW_RT_ERROR(msg.c_str());
} }
fillInHeader(sampleRate, bits, channels); fillInHeader(sampleRate, bits, channels);
@ -740,7 +736,7 @@ WavOutFile::~WavOutFile()
{ {
finishHeader(); finishHeader();
if (fptr) fclose(fptr); if (fptr) fclose(fptr);
fptr = NULL; fptr = nullptr;
} }
@ -801,17 +797,17 @@ void WavOutFile::writeHeader()
// swap byte order if necessary // swap byte order if necessary
hdrTemp = header; hdrTemp = header;
_swap32((int &)hdrTemp.riff.package_len); _swap32((int&)hdrTemp.riff.package_len);
_swap32((int &)hdrTemp.format.format_len); _swap32((int&)hdrTemp.format.format_len);
_swap16((short &)hdrTemp.format.fixed); _swap16((short&)hdrTemp.format.fixed);
_swap16((short &)hdrTemp.format.channel_number); _swap16((short&)hdrTemp.format.channel_number);
_swap32((int &)hdrTemp.format.sample_rate); _swap32((int&)hdrTemp.format.sample_rate);
_swap32((int &)hdrTemp.format.byte_rate); _swap32((int&)hdrTemp.format.byte_rate);
_swap16((short &)hdrTemp.format.byte_per_sample); _swap16((short&)hdrTemp.format.byte_per_sample);
_swap16((short &)hdrTemp.format.bits_per_sample); _swap16((short&)hdrTemp.format.bits_per_sample);
_swap32((int &)hdrTemp.data.data_len); _swap32((int&)hdrTemp.data.data_len);
_swap32((int &)hdrTemp.fact.fact_len); _swap32((int&)hdrTemp.fact.fact_len);
_swap32((int &)hdrTemp.fact.fact_sample_len); _swap32((int&)hdrTemp.fact.fact_sample_len);
// write the supplemented header in the beginning of the file // write the supplemented header in the beginning of the file
fseek(fptr, 0, SEEK_SET); fseek(fptr, 0, SEEK_SET);
@ -826,7 +822,7 @@ void WavOutFile::writeHeader()
} }
void WavOutFile::write(const unsigned char *buffer, int numElems) void WavOutFile::write(const unsigned char* buffer, int numElems)
{ {
int res; int res;
@ -846,7 +842,7 @@ void WavOutFile::write(const unsigned char *buffer, int numElems)
} }
void WavOutFile::write(const short *buffer, int numElems) void WavOutFile::write(const short* buffer, int numElems)
{ {
int res; int res;
@ -858,9 +854,9 @@ void WavOutFile::write(const short *buffer, int numElems)
case 8: case 8:
{ {
int i; int i;
unsigned char *temp = (unsigned char *)getConvBuffer(numElems); unsigned char* temp = (unsigned char*)getConvBuffer(numElems);
// convert from 16bit format to 8bit format // convert from 16bit format to 8bit format
for (i = 0; i < numElems; i ++) for (i = 0; i < numElems; i++)
{ {
temp[i] = (unsigned char)(buffer[i] / 256 + 128); temp[i] = (unsigned char)(buffer[i] / 256 + 128);
} }
@ -874,8 +870,8 @@ void WavOutFile::write(const short *buffer, int numElems)
// 16bit format // 16bit format
// use temp buffer to swap byte order if necessary // use temp buffer to swap byte order if necessary
short *pTemp = (short *)getConvBuffer(numElems * sizeof(short)); short* pTemp = (short*)getConvBuffer(numElems * sizeof(short));
memcpy(pTemp, buffer, numElems * 2); memcpy(pTemp, buffer, (size_t)numElems * 2L);
_swap16Buffer(pTemp, numElems); _swap16Buffer(pTemp, numElems);
res = (int)fwrite(pTemp, 2, numElems, fptr); res = (int)fwrite(pTemp, 2, numElems, fptr);
@ -915,7 +911,7 @@ inline int saturate(float fvalue, float minval, float maxval)
} }
void WavOutFile::write(const float *buffer, int numElems) void WavOutFile::write(const float* buffer, int numElems)
{ {
int numBytes; int numBytes;
int bytesPerSample; int bytesPerSample;
@ -924,14 +920,14 @@ void WavOutFile::write(const float *buffer, int numElems)
bytesPerSample = header.format.bits_per_sample / 8; bytesPerSample = header.format.bits_per_sample / 8;
numBytes = numElems * bytesPerSample; numBytes = numElems * bytesPerSample;
short *temp = (short*)getConvBuffer(numBytes); void* temp = getConvBuffer(numBytes + 7); // round bit up to avoid buffer overrun with 24bit-value assignment
switch (bytesPerSample) switch (bytesPerSample)
{ {
case 1: case 1:
{ {
unsigned char *temp2 = (unsigned char *)temp; unsigned char* temp2 = (unsigned char*)temp;
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
temp2[i] = (unsigned char)saturate(buffer[i] * 128.0f + 128.0f, 0.0f, 255.0f); temp2[i] = (unsigned char)saturate(buffer[i] * 128.0f + 128.0f, 0.0f, 255.0f);
} }
@ -940,8 +936,8 @@ void WavOutFile::write(const float *buffer, int numElems)
case 2: case 2:
{ {
short *temp2 = (short *)temp; short* temp2 = (short*)temp;
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
short value = (short)saturate(buffer[i] * 32768.0f, -32768.0f, 32767.0f); short value = (short)saturate(buffer[i] * 32768.0f, -32768.0f, 32767.0f);
temp2[i] = _swap16(value); temp2[i] = _swap16(value);
@ -951,8 +947,8 @@ void WavOutFile::write(const float *buffer, int numElems)
case 3: case 3:
{ {
char *temp2 = (char *)temp; char* temp2 = (char*)temp;
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
int value = saturate(buffer[i] * 8388608.0f, -8388608.0f, 8388607.0f); int value = saturate(buffer[i] * 8388608.0f, -8388608.0f, 8388607.0f);
*((int*)temp2) = _swap32(value); *((int*)temp2) = _swap32(value);
@ -963,8 +959,8 @@ void WavOutFile::write(const float *buffer, int numElems)
case 4: case 4:
{ {
int *temp2 = (int *)temp; int* temp2 = (int*)temp;
for (int i = 0; i < numElems; i ++) for (int i = 0; i < numElems; i++)
{ {
int value = saturate(buffer[i] * 2147483648.0f, -2147483648.0f, 2147483647.0f); int value = saturate(buffer[i] * 2147483648.0f, -2147483648.0f, 2147483647.0f);
temp2[i] = _swap32(value); temp2[i] = _swap32(value);
@ -984,3 +980,5 @@ void WavOutFile::write(const float *buffer, int numElems)
} }
bytesWritten += numBytes; bytesWritten += numBytes;
} }
}

View File

@ -40,7 +40,12 @@
#ifndef WAVFILE_H #ifndef WAVFILE_H
#define WAVFILE_H #define WAVFILE_H
#include <stdio.h> #include <cstdio>
#include <string>
#include "SS_CharTypes.h"
namespace soundstretch
{
#ifndef uint #ifndef uint
typedef unsigned int uint; typedef unsigned int uint;
@ -118,9 +123,6 @@ private:
/// File pointer. /// File pointer.
FILE *fptr; FILE *fptr;
/// Position within the audio stream
long position;
/// Counter of how many bytes of sample data have been read from the file. /// Counter of how many bytes of sample data have been read from the file.
long dataRead; long dataRead;
@ -148,7 +150,7 @@ private:
public: public:
/// Constructor: Opens the given WAV file. If the file can't be opened, /// Constructor: Opens the given WAV file. If the file can't be opened,
/// throws 'runtime_error' exception. /// throws 'runtime_error' exception.
WavInFile(const char *filename); WavInFile(const STRING& filename);
WavInFile(FILE *file); WavInFile(FILE *file);
@ -244,7 +246,7 @@ private:
public: public:
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
/// if file creation fails. /// if file creation fails.
WavOutFile(const char *fileName, ///< Filename WavOutFile(const STRING& fileName, ///< Filename
int sampleRate, ///< Sample rate (e.g. 44100 etc) int sampleRate, ///< Sample rate (e.g. 44100 etc)
int bits, ///< Bits per sample (8 or 16 bits) int bits, ///< Bits per sample (8 or 16 bits)
int channels ///< Number of channels (1=mono, 2=stereo) int channels ///< Number of channels (1=mono, 2=stereo)
@ -274,4 +276,6 @@ public:
); );
}; };
}
#endif #endif

View File

@ -29,10 +29,12 @@
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <memory>
#include <stdexcept> #include <stdexcept>
#include <stdio.h> #include <string>
#include <string.h> #include <cstdio>
#include <time.h> #include <ctime>
#include "RunParameters.h" #include "RunParameters.h"
#include "WavFile.h" #include "WavFile.h"
#include "SoundTouch.h" #include "SoundTouch.h"
@ -41,18 +43,21 @@
using namespace soundtouch; using namespace soundtouch;
using namespace std; using namespace std;
namespace soundstretch
{
// Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...) // Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...)
#define BUFF_SIZE 6720 #define BUFF_SIZE 6720
#if _WIN32 #if _WIN32
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
// Macro for Win32 standard input/output stream support: Sets a file stream into binary mode // 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)) #define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY))
#else #else
// Not needed for GNU environment... // Not needed for GNU environment...
#define SET_STREAM_TO_BIN_MODE(f) {} #define SET_STREAM_TO_BIN_MODE(f) {}
#endif #endif
@ -68,90 +73,81 @@ static const char _helloText[] =
"more information.\n" "more information.\n"
"\n"; "\n";
static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParameters *params) static void openFiles(unique_ptr<WavInFile>& inFile, unique_ptr<WavOutFile>& outFile, const RunParameters& params)
{ {
int bits, samplerate, channels; if (params.inFileName == STRING_CONST("stdin"))
if (strcmp(params->inFileName, "stdin") == 0)
{ {
// used 'stdin' as input file // used 'stdin' as input file
SET_STREAM_TO_BIN_MODE(stdin); SET_STREAM_TO_BIN_MODE(stdin);
*inFile = new WavInFile(stdin); inFile = make_unique<WavInFile>(stdin);
} }
else else
{ {
// open input file... // open input file...
*inFile = new WavInFile(params->inFileName); inFile = make_unique<WavInFile>(params.inFileName.c_str());
} }
// ... open output file with same sound parameters // ... open output file with same sound parameters
bits = (int)(*inFile)->getNumBits(); const int bits = (int)inFile->getNumBits();
samplerate = (int)(*inFile)->getSampleRate(); const int samplerate = (int)inFile->getSampleRate();
channels = (int)(*inFile)->getNumChannels(); const int channels = (int)inFile->getNumChannels();
if (params->outFileName) if (!params.outFileName.empty())
{ {
if (strcmp(params->outFileName, "stdout") == 0) if (params.outFileName == STRING_CONST("stdout"))
{ {
SET_STREAM_TO_BIN_MODE(stdout); SET_STREAM_TO_BIN_MODE(stdout);
*outFile = new WavOutFile(stdout, samplerate, bits, channels); outFile = make_unique<WavOutFile>(stdout, samplerate, bits, channels);
} }
else else
{ {
*outFile = new WavOutFile(params->outFileName, samplerate, bits, channels); outFile = make_unique<WavOutFile>(params.outFileName.c_str(), samplerate, bits, channels);
} }
} }
else
{
*outFile = NULL;
}
} }
// Sets the 'SoundTouch' object up according to input file sound format & // Sets the 'SoundTouch' object up according to input file sound format &
// command line parameters // command line parameters
static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunParameters *params) static void setup(SoundTouch& soundTouch, const WavInFile& inFile, const RunParameters& params)
{ {
int sampleRate; const int sampleRate = (int)inFile.getSampleRate();
int channels; const int channels = (int)inFile.getNumChannels();
soundTouch.setSampleRate(sampleRate);
soundTouch.setChannels(channels);
sampleRate = (int)inFile->getSampleRate(); soundTouch.setTempoChange(params.tempoDelta);
channels = (int)inFile->getNumChannels(); soundTouch.setPitchSemiTones(params.pitchDelta);
pSoundTouch->setSampleRate(sampleRate); soundTouch.setRateChange(params.rateDelta);
pSoundTouch->setChannels(channels);
pSoundTouch->setTempoChange(params->tempoDelta); soundTouch.setSetting(SETTING_USE_QUICKSEEK, params.quick);
pSoundTouch->setPitchSemiTones(params->pitchDelta); soundTouch.setSetting(SETTING_USE_AA_FILTER, !(params.noAntiAlias));
pSoundTouch->setRateChange(params->rateDelta);
pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, params->quick); if (params.speech)
pSoundTouch->setSetting(SETTING_USE_AA_FILTER, !(params->noAntiAlias));
if (params->speech)
{ {
// use settings for speech processing // use settings for speech processing
pSoundTouch->setSetting(SETTING_SEQUENCE_MS, 40); soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
pSoundTouch->setSetting(SETTING_SEEKWINDOW_MS, 15); soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
pSoundTouch->setSetting(SETTING_OVERLAP_MS, 8); soundTouch.setSetting(SETTING_OVERLAP_MS, 8);
fprintf(stderr, "Tune processing parameters for speech processing.\n"); fprintf(stderr, "Tune processing parameters for speech processing.\n");
} }
// print processing information // print processing information
if (params->outFileName) if (!params.outFileName.empty())
{ {
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n"); fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
#else #else
#ifndef SOUNDTOUCH_FLOAT_SAMPLES #ifndef SOUNDTOUCH_FLOAT_SAMPLES
#error "Sampletype not defined" #error "Sampletype not defined"
#endif #endif
fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n"); fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");
#endif #endif
// print processing information only if outFileName given i.e. some processing will happen // 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, "Processing the file with the following changes:\n");
fprintf(stderr, " tempo change = %+g %%\n", params->tempoDelta); fprintf(stderr, " tempo change = %+lg %%\n", params.tempoDelta);
fprintf(stderr, " pitch change = %+g semitones\n", params->pitchDelta); fprintf(stderr, " pitch change = %+lg semitones\n", params.pitchDelta);
fprintf(stderr, " rate change = %+g %%\n\n", params->rateDelta); fprintf(stderr, " rate change = %+lg %%\n\n", params.rateDelta);
fprintf(stderr, "Working..."); fprintf(stderr, "Working...");
} }
else else
@ -165,30 +161,24 @@ static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunPar
// Processes the sound // Processes the sound
static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outFile) static void process(SoundTouch& soundTouch, WavInFile& inFile, WavOutFile& outFile)
{ {
int nSamples;
int nChannels;
int buffSizeSamples;
SAMPLETYPE sampleBuffer[BUFF_SIZE]; SAMPLETYPE sampleBuffer[BUFF_SIZE];
int nSamples;
if ((inFile == NULL) || (outFile == NULL)) return; // nothing to do. const int nChannels = (int)inFile.getNumChannels();
nChannels = (int)inFile->getNumChannels();
assert(nChannels > 0); assert(nChannels > 0);
buffSizeSamples = BUFF_SIZE / nChannels; const int buffSizeSamples = BUFF_SIZE / nChannels;
// Process samples read from the input file // Process samples read from the input file
while (inFile->eof() == 0) while (inFile.eof() == 0)
{ {
int num;
// Read a chunk of samples from the input file // Read a chunk of samples from the input file
num = inFile->read(sampleBuffer, BUFF_SIZE); const int num = inFile.read(sampleBuffer, BUFF_SIZE);
nSamples = num / (int)inFile->getNumChannels(); int nSamples = num / (int)inFile.getNumChannels();
// Feed the samples into SoundTouch processor // Feed the samples into SoundTouch processor
pSoundTouch->putSamples(sampleBuffer, nSamples); soundTouch.putSamples(sampleBuffer, nSamples);
// Read ready samples from SoundTouch processor & write them output file. // Read ready samples from SoundTouch processor & write them output file.
// NOTES: // NOTES:
@ -200,61 +190,57 @@ static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outF
// outputs samples. // outputs samples.
do do
{ {
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
outFile->write(sampleBuffer, nSamples * nChannels); outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0); } while (nSamples != 0);
} }
// Now the input file is processed, yet 'flush' few last samples that are // Now the input file is processed, yet 'flush' few last samples that are
// hiding in the SoundTouch's internal processing pipeline. // hiding in the SoundTouch's internal processing pipeline.
pSoundTouch->flush(); soundTouch.flush();
do do
{ {
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples); nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
outFile->write(sampleBuffer, nSamples * nChannels); outFile.write(sampleBuffer, nSamples * nChannels);
} while (nSamples != 0); } while (nSamples != 0);
} }
// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary // Detect BPM rate of inFile and adjust tempo setting accordingly if necessary
static void detectBPM(WavInFile *inFile, RunParameters *params) static void detectBPM(WavInFile& inFile, RunParameters& params)
{ {
float bpmValue; BPMDetect bpm(inFile.getNumChannels(), inFile.getSampleRate());
int nChannels;
BPMDetect bpm(inFile->getNumChannels(), inFile->getSampleRate());
SAMPLETYPE sampleBuffer[BUFF_SIZE]; SAMPLETYPE sampleBuffer[BUFF_SIZE];
// detect bpm rate // detect bpm rate
fprintf(stderr, "Detecting BPM rate..."); fprintf(stderr, "Detecting BPM rate...");
fflush(stderr); fflush(stderr);
nChannels = (int)inFile->getNumChannels(); const int nChannels = (int)inFile.getNumChannels();
assert(BUFF_SIZE % nChannels == 0); 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 // Process the 'inFile' in small blocks, repeat until whole file has
// been processed // been processed
while (inFile->eof() == 0) while (inFile.eof() == 0)
{ {
int num, samples;
// Read sample data from input file // Read sample data from input file
num = inFile->read(sampleBuffer, BUFF_SIZE); const int num = inFile.read(sampleBuffer, readSize);
// Enter the new samples to the bpm analyzer class // Enter the new samples to the bpm analyzer class
samples = num / nChannels; const int samples = num / nChannels;
bpm.inputSamples(sampleBuffer, samples); bpm.inputSamples(sampleBuffer, samples);
} }
// Now the whole song data has been analyzed. Read the resulting bpm. // Now the whole song data has been analyzed. Read the resulting bpm.
bpmValue = bpm.getBpm(); const float bpmValue = bpm.getBpm();
fprintf(stderr, "Done!\n"); fprintf(stderr, "Done!\n");
// rewind the file after bpm detection // rewind the file after bpm detection
inFile->rewind(); inFile.rewind();
if (bpmValue > 0) if (bpmValue > 0)
{ {
fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue); fprintf(stderr, "Detected BPM rate %.1lf\n\n", bpmValue);
} }
else else
{ {
@ -262,61 +248,74 @@ static void detectBPM(WavInFile *inFile, RunParameters *params)
return; return;
} }
if (params->goalBPM > 0) if (params.goalBPM > 0)
{ {
// adjust tempo to given bpm // adjust tempo to given bpm
params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f; params.tempoDelta = (params.goalBPM / bpmValue - 1.0f) * 100.0f;
fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params->goalBPM); fprintf(stderr, "The file will be converted to %.1lf BPM\n\n", params.goalBPM);
} }
} }
void printHelloText()
int main(const int nParams, const char * const paramStr[])
{ {
WavInFile *inFile; SoundTouch soundTouch;
WavOutFile *outFile; fprintf(stderr, _helloText, soundTouch.getVersionString());
RunParameters *params; }
void ss_main(RunParameters& params)
{
unique_ptr<WavInFile> inFile;
unique_ptr<WavOutFile> outFile;
SoundTouch soundTouch; SoundTouch soundTouch;
fprintf(stderr, _helloText, SoundTouch::getVersionString());
try
{
// Parse command line parameters
params = new RunParameters(nParams, paramStr);
// Open input & output files // Open input & output files
openFiles(&inFile, &outFile, params); openFiles(inFile, outFile, params);
if (params->detectBPM == true) if (params.detectBPM == true)
{ {
// detect sound BPM (and adjust processing parameters // detect sound BPM (and adjust processing parameters
// accordingly if necessary) // accordingly if necessary)
detectBPM(inFile, params); detectBPM(*inFile, params);
} }
// Setup the 'SoundTouch' object for processing the sound // Setup the 'SoundTouch' object for processing the sound
setup(&soundTouch, inFile, params); setup(soundTouch, *inFile, params);
// clock_t cs = clock(); // for benchmarking processing duration // clock_t cs = clock(); // for benchmarking processing duration
// Process the sound // Process the sound
process(&soundTouch, inFile, outFile); if (inFile && outFile)
{
process(soundTouch, *inFile, *outFile);
}
// clock_t ce = clock(); // for benchmarking processing duration // clock_t ce = clock(); // for benchmarking processing duration
// printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC); // 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"); fprintf(stderr, "Done!\n");
} }
catch (const runtime_error &e)
}
#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)
{ {
// An exception occurred during processing, display an error message
fprintf(stderr, "%s\n", e.what()); fprintf(stderr, "%s\n", e.what());
return -1; return -1;
} }
catch (const string& e)
{
fprintf(stderr, "%s\n", e.c_str());
return -1;
}
return 0; return 0;
} }

View File

@ -21,32 +21,32 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}</ProjectGuid> <ProjectGuid>{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}</ProjectGuid>
<RootNamespace>soundstretch</RootNamespace> <RootNamespace>soundstretch</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
@ -114,9 +114,10 @@
<BrowseInformation>true</BrowseInformation> <BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner> <SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs> <CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -133,10 +134,7 @@
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName> <MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention /> <DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin <Command>if not exist ..\..\bin mkdir ..\..\bin
@ -167,6 +165,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
<DebugInformationFormat /> <DebugInformationFormat />
<CompileAs>Default</CompileAs> <CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -181,9 +180,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName> <MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention /> <DataExecutionPrevention />
<TargetMachine>MachineX86</TargetMachine>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin <Command>if not exist ..\..\bin mkdir ..\..\bin
@ -215,6 +212,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
<CompileAs>Default</CompileAs> <CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>
</EnableEnhancedInstructionSet> </EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -231,9 +229,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName> <MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention /> <DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin <Command>if not exist ..\..\bin mkdir ..\..\bin
@ -266,6 +262,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
<CompileAs>Default</CompileAs> <CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>
</EnableEnhancedInstructionSet> </EnableEnhancedInstructionSet>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -280,9 +277,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
<GenerateMapFile>true</GenerateMapFile> <GenerateMapFile>true</GenerateMapFile>
<MapFileName>$(OutDir)$(TargetName).map</MapFileName> <MapFileName>$(OutDir)$(TargetName).map</MapFileName>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<RandomizedBaseAddress>false</RandomizedBaseAddress>
<DataExecutionPrevention /> <DataExecutionPrevention />
<TargetMachine>MachineX64</TargetMachine>
</Link> </Link>
<PostBuildEvent> <PostBuildEvent>
<Command>if not exist ..\..\bin mkdir ..\..\bin <Command>if not exist ..\..\bin mkdir ..\..\bin
@ -323,6 +318,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="RunParameters.h" /> <ClInclude Include="RunParameters.h" />
<ClInclude Include="SS_CharTypes.h" />
<ClInclude Include="WavFile.h" /> <ClInclude Include="WavFile.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -54,7 +54,7 @@ using namespace soundtouch;
static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len) static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)
{ {
FILE *fptr = fopen("aa_filter_coeffs.txt", "wt"); FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");
if (fptr == NULL) return; if (fptr == nullptr) return;
for (int i = 0; i < len; i ++) for (int i = 0; i < len; i ++)
{ {

View File

@ -186,8 +186,10 @@ BPMDetect::BPMDetect(int numChannels, int aSampleRate) :
// choose decimation factor so that result is approx. 1000 Hz // choose decimation factor so that result is approx. 1000 Hz
decimateBy = sampleRate / TARGET_SRATE; decimateBy = sampleRate / TARGET_SRATE;
assert(decimateBy > 0); if ((decimateBy <= 0) || (decimateBy * DECIMATED_BLOCK_SIZE < INPUT_BLOCK_SIZE))
assert(INPUT_BLOCK_SIZE < decimateBy * DECIMATED_BLOCK_SIZE); {
ST_THROW_RT_ERROR("Too small samplerate");
}
// Calculate window length & starting item according to desired min & max bpms // Calculate window length & starting item according to desired min & max bpms
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM); windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
@ -299,7 +301,7 @@ void BPMDetect::updateXCorr(int process_samples)
pBuffer = buffer->ptrBegin(); pBuffer = buffer->ptrBegin();
// calculate decay factor for xcorr filtering // calculate decay factor for xcorr filtering
float xcorr_decay = (float)pow(0.5, 1.0 / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE / process_samples)); float xcorr_decay = (float)pow(0.5, process_samples / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE));
// prescale pbuffer // prescale pbuffer
float tmp[XCORR_UPDATE_SEQUENCE]; float tmp[XCORR_UPDATE_SEQUENCE];
@ -311,7 +313,7 @@ void BPMDetect::updateXCorr(int process_samples)
#pragma omp parallel for #pragma omp parallel for
for (offs = windowStart; offs < windowLen; offs ++) for (offs = windowStart; offs < windowLen; offs ++)
{ {
double sum; float sum;
int i; int i;
sum = 0; sum = 0;
@ -339,7 +341,6 @@ void BPMDetect::updateBeatPos(int process_samples)
// static double thr = 0.0003; // static double thr = 0.0003;
double posScale = (double)this->decimateBy / (double)this->sampleRate; double posScale = (double)this->decimateBy / (double)this->sampleRate;
int resetDur = (int)(0.12 / posScale + 0.5); int resetDur = (int)(0.12 / posScale + 0.5);
double corrScale = 1.0 / (double)(windowLen - windowStart);
// prescale pbuffer // prescale pbuffer
float tmp[XCORR_UPDATE_SEQUENCE / 2]; float tmp[XCORR_UPDATE_SEQUENCE / 2];
@ -351,7 +352,7 @@ void BPMDetect::updateBeatPos(int process_samples)
#pragma omp parallel for #pragma omp parallel for
for (int offs = windowStart; offs < windowLen; offs++) for (int offs = windowStart; offs < windowLen; offs++)
{ {
double sum = 0; float sum = 0;
for (int i = 0; i < process_samples; i++) for (int i = 0; i < process_samples; i++)
{ {
sum += tmp[i] * pBuffer[offs + i]; sum += tmp[i] * pBuffer[offs + i];
@ -375,8 +376,6 @@ void BPMDetect::updateBeatPos(int process_samples)
// detect beats // detect beats
for (int i = 0; i < skipstep; i++) for (int i = 0; i < skipstep; i++)
{ {
LONG_SAMPLETYPE max = 0;
float sum = beatcorr_ringbuff[beatcorr_ringbuffpos]; float sum = beatcorr_ringbuff[beatcorr_ringbuffpos];
sum -= beat_lpf.update(sum); sum -= beat_lpf.update(sum);
@ -555,13 +554,13 @@ float BPMDetect::getBpm()
/// - "values" receive array of beat detection strengths /// - "values" receive array of beat detection strengths
/// - max_num indicates max.size of "pos" and "values" array. /// - max_num indicates max.size of "pos" and "values" array.
/// ///
/// You can query a suitable array sized by calling this with NULL in "pos" & "values". /// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
/// ///
/// \return number of beats in the arrays. /// \return number of beats in the arrays.
int BPMDetect::getBeats(float *pos, float *values, int max_num) int BPMDetect::getBeats(float *pos, float *values, int max_num)
{ {
int num = beats.size(); int num = (int)beats.size();
if ((!pos) || (!values)) return num; // pos or values NULL, return just size if ((!pos) || (!values)) return num; // pos or values nullptr, return just size
for (int i = 0; (i < num) && (i < max_num); i++) for (int i = 0; (i < num) && (i < max_num); i++)
{ {

View File

@ -50,8 +50,8 @@ FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
{ {
assert(numChannels > 0); assert(numChannels > 0);
sizeInBytes = 0; // reasonable initial value sizeInBytes = 0; // reasonable initial value
buffer = NULL; buffer = nullptr;
bufferUnaligned = NULL; bufferUnaligned = nullptr;
samplesInBuffer = 0; samplesInBuffer = 0;
bufferPos = 0; bufferPos = 0;
channels = (uint)numChannels; channels = (uint)numChannels;
@ -63,8 +63,8 @@ FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
FIFOSampleBuffer::~FIFOSampleBuffer() FIFOSampleBuffer::~FIFOSampleBuffer()
{ {
delete[] bufferUnaligned; delete[] bufferUnaligned;
bufferUnaligned = NULL; bufferUnaligned = nullptr;
buffer = NULL; buffer = nullptr;
} }
@ -166,7 +166,7 @@ void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096; sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
assert(sizeInBytes % 2 == 0); assert(sizeInBytes % 2 == 0);
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)]; tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
if (tempUnaligned == NULL) if (tempUnaligned == nullptr)
{ {
ST_THROW_RT_ERROR("Couldn't allocate memory!\n"); ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
} }
@ -265,3 +265,11 @@ uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
} }
return samplesInBuffer; 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

@ -56,16 +56,17 @@ using namespace soundtouch;
FIRFilter::FIRFilter() FIRFilter::FIRFilter()
{ {
resultDivFactor = 0; resultDivFactor = 0;
resultDivider = 0;
length = 0; length = 0;
lengthDiv8 = 0; lengthDiv8 = 0;
filterCoeffs = NULL; filterCoeffs = nullptr;
filterCoeffsStereo = nullptr;
} }
FIRFilter::~FIRFilter() FIRFilter::~FIRFilter()
{ {
delete[] filterCoeffs; delete[] filterCoeffs;
delete[] filterCoeffsStereo;
} }
@ -73,40 +74,27 @@ FIRFilter::~FIRFilter()
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{ {
int j, end; int j, end;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES // hint compiler autovectorization that loop length is divisible by 8
// when using floating point samples, use a scaler instead of a divider uint ilength = length & -8;
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0); assert((length != 0) && (length == ilength) && (src != nullptr) && (dest != nullptr) && (filterCoeffs != nullptr));
assert(src != NULL); assert(numSamples > ilength);
assert(dest != NULL);
assert(filterCoeffs != NULL);
end = 2 * (numSamples - length); end = 2 * (numSamples - ilength);
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < end; j += 2) for (j = 0; j < end; j += 2)
{ {
const SAMPLETYPE *ptr; const SAMPLETYPE *ptr;
LONG_SAMPLETYPE suml, sumr; LONG_SAMPLETYPE suml, sumr;
uint i;
suml = sumr = 0; suml = sumr = 0;
ptr = src + j; ptr = src + j;
for (i = 0; i < length; i += 4) for (uint i = 0; i < ilength; i ++)
{ {
// loop is unrolled by factor of 4 here for efficiency suml += ptr[2 * i] * filterCoeffsStereo[2 * i];
suml += ptr[2 * i + 0] * filterCoeffs[i + 0] + sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1];
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 #ifdef SOUNDTOUCH_INTEGER_SAMPLES
@ -116,14 +104,11 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml; suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
// saturate to 16 bit integer limits // saturate to 16 bit integer limits
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr; sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
#else
suml *= dScaler;
sumr *= dScaler;
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)suml; dest[j] = (SAMPLETYPE)suml;
dest[j + 1] = (SAMPLETYPE)sumr; dest[j + 1] = (SAMPLETYPE)sumr;
} }
return numSamples - length; return numSamples - ilength;
} }
@ -131,37 +116,29 @@ uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, ui
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
{ {
int j, end; int j, end;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0); // hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8;
end = numSamples - length; assert(ilength != 0);
end = numSamples - ilength;
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < end; j ++) for (j = 0; j < end; j ++)
{ {
const SAMPLETYPE *pSrc = src + j; const SAMPLETYPE *pSrc = src + j;
LONG_SAMPLETYPE sum; LONG_SAMPLETYPE sum;
uint i; int i;
sum = 0; sum = 0;
for (i = 0; i < length; i += 4) for (i = 0; i < ilength; i ++)
{ {
// loop is unrolled by factor of 4 here for efficiency sum += pSrc[i] * filterCoeffs[i];
sum += pSrc[i + 0] * filterCoeffs[i + 0] +
pSrc[i + 1] * filterCoeffs[i + 1] +
pSrc[i + 2] * filterCoeffs[i + 2] +
pSrc[i + 3] * filterCoeffs[i + 3];
} }
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
sum >>= resultDivFactor; sum >>= resultDivFactor;
// saturate to 16 bit integer limits // saturate to 16 bit integer limits
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum; sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
#else
sum *= dScaler;
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j] = (SAMPLETYPE)sum; dest[j] = (SAMPLETYPE)sum;
} }
@ -173,26 +150,24 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin
{ {
int j, end; int j, end;
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
// when using floating point samples, use a scaler instead of a divider
// because division is much slower operation than multiplying.
double dScaler = 1.0 / (double)resultDivider;
#endif
assert(length != 0); assert(length != 0);
assert(src != NULL); assert(src != nullptr);
assert(dest != NULL); assert(dest != nullptr);
assert(filterCoeffs != NULL); assert(filterCoeffs != nullptr);
assert(numChannels < 16); assert(numChannels <= SOUNDTOUCH_MAX_CHANNELS);
end = numChannels * (numSamples - length); // hint compiler autovectorization that loop length is divisible by 8
int ilength = length & -8;
end = numChannels * (numSamples - ilength);
#pragma omp parallel for #pragma omp parallel for
for (j = 0; j < end; j += numChannels) for (j = 0; j < end; j += numChannels)
{ {
const SAMPLETYPE *ptr; const SAMPLETYPE *ptr;
LONG_SAMPLETYPE sums[16]; LONG_SAMPLETYPE sums[16];
uint c, i; uint c;
int i;
for (c = 0; c < numChannels; c ++) for (c = 0; c < numChannels; c ++)
{ {
@ -201,7 +176,7 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin
ptr = src + j; ptr = src + j;
for (i = 0; i < length; i ++) for (i = 0; i < ilength; i ++)
{ {
SAMPLETYPE coef=filterCoeffs[i]; SAMPLETYPE coef=filterCoeffs[i];
for (c = 0; c < numChannels; c ++) for (c = 0; c < numChannels; c ++)
@ -215,13 +190,11 @@ uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uin
{ {
#ifdef SOUNDTOUCH_INTEGER_SAMPLES #ifdef SOUNDTOUCH_INTEGER_SAMPLES
sums[c] >>= resultDivFactor; sums[c] >>= resultDivFactor;
#else
sums[c] *= dScaler;
#endif // SOUNDTOUCH_INTEGER_SAMPLES #endif // SOUNDTOUCH_INTEGER_SAMPLES
dest[j+c] = (SAMPLETYPE)sums[c]; dest[j+c] = (SAMPLETYPE)sums[c];
} }
} }
return numSamples - length; return numSamples - ilength;
} }
@ -238,11 +211,27 @@ void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint u
assert(length == newLength); assert(length == newLength);
resultDivFactor = uResultDivFactor; resultDivFactor = uResultDivFactor;
resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);
delete[] filterCoeffs; delete[] filterCoeffs;
filterCoeffs = new SAMPLETYPE[length]; filterCoeffs = new SAMPLETYPE[length];
memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE)); 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);
}
} }
@ -283,7 +272,7 @@ uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSample
// Operator 'new' is overloaded so that it automatically creates a suitable instance // Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX-capable CPU available or not. // depending on if we've a MMX-capable CPU available or not.
void * FIRFilter::operator new(size_t s) void * FIRFilter::operator new(size_t)
{ {
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead! // 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!"); ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
@ -296,6 +285,7 @@ FIRFilter * FIRFilter::newInstance()
uint uExtensions; uint uExtensions;
uExtensions = detectCPUextensions(); uExtensions = detectCPUextensions();
(void)uExtensions;
// Check if MMX/SSE instruction set extensions supported by CPU // Check if MMX/SSE instruction set extensions supported by CPU

View File

@ -52,11 +52,9 @@ protected:
// Result divider factor in 2^k format // Result divider factor in 2^k format
uint resultDivFactor; uint resultDivFactor;
// Result divider value.
SAMPLETYPE resultDivider;
// Memory for filter coefficients // Memory for filter coefficients
SAMPLETYPE *filterCoeffs; SAMPLETYPE *filterCoeffs;
SAMPLETYPE *filterCoeffsStereo;
virtual uint evaluateFilterStereo(SAMPLETYPE *dest, virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
@ -105,12 +103,12 @@ public:
short *filterCoeffsUnalign; short *filterCoeffsUnalign;
short *filterCoeffsAlign; short *filterCoeffsAlign;
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const; virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const override;
public: public:
FIRFilterMMX(); FIRFilterMMX();
~FIRFilterMMX(); ~FIRFilterMMX();
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor); virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) override;
}; };
#endif // SOUNDTOUCH_ALLOW_MMX #endif // SOUNDTOUCH_ALLOW_MMX
@ -124,12 +122,12 @@ public:
float *filterCoeffsUnalign; float *filterCoeffsUnalign;
float *filterCoeffsAlign; float *filterCoeffsAlign;
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const; virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const override;
public: public:
FIRFilterSSE(); FIRFilterSSE();
~FIRFilterSSE(); ~FIRFilterSSE();
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor); virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) override;
}; };
#endif // SOUNDTOUCH_ALLOW_SSE #endif // SOUNDTOUCH_ALLOW_SSE

View File

@ -41,21 +41,27 @@ namespace soundtouch
class InterpolateCubic : public TransposerBase class InterpolateCubic : public TransposerBase
{ {
protected: protected:
virtual void resetRegisters();
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, virtual int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
double fract; double fract;
public: public:
InterpolateCubic(); InterpolateCubic();
virtual void resetRegisters() override;
virtual int getLatency() const override
{
return 1;
}
}; };
} }

View File

@ -142,7 +142,7 @@ int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE
LONG_SAMPLETYPE temp, vol1; LONG_SAMPLETYPE temp, vol1;
assert(iFract < SCALE); assert(iFract < SCALE);
vol1 = (SCALE - iFract); vol1 = (LONG_SAMPLETYPE)(SCALE - iFract);
for (int c = 0; c < numChannels; c ++) for (int c = 0; c < numChannels; c ++)
{ {
temp = vol1 * src[c] + iFract * src[c + numChannels]; temp = vol1 * src[c] + iFract * src[c + numChannels];

View File

@ -45,21 +45,26 @@ protected:
int iFract; int iFract;
int iRate; int iRate;
virtual void resetRegisters();
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
virtual int transposeStereo(SAMPLETYPE *dest, virtual int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples); virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override;
public: public:
InterpolateLinearInteger(); InterpolateLinearInteger();
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower /// Sets new target rate. Normal rate = 1.0, smaller values represent slower
/// rate, larger faster rates. /// rate, larger faster rates.
virtual void setRate(double newRate); virtual void setRate(double newRate) override;
virtual void resetRegisters() override;
virtual int getLatency() const override
{
return 0;
}
}; };
@ -69,8 +74,6 @@ class InterpolateLinearFloat : public TransposerBase
protected: protected:
double fract; double fract;
virtual void resetRegisters();
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples);
@ -81,6 +84,13 @@ protected:
public: public:
InterpolateLinearFloat(); InterpolateLinearFloat();
virtual void resetRegisters();
int getLatency() const
{
return 0;
}
}; };
} }

View File

@ -171,9 +171,9 @@ int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest,
/// Transpose stereo audio. Returns number of produced output samples, and /// Transpose stereo audio. Returns number of produced output samples, and
/// updates "srcSamples" to amount of consumed source samples /// updates "srcSamples" to amount of consumed source samples
int InterpolateShannon::transposeMulti(SAMPLETYPE *pdest, int InterpolateShannon::transposeMulti(SAMPLETYPE *,
const SAMPLETYPE *psrc, const SAMPLETYPE *,
int &srcSamples) int &)
{ {
// not implemented // not implemented
assert(false); assert(false);

View File

@ -46,21 +46,27 @@ namespace soundtouch
class InterpolateShannon : public TransposerBase class InterpolateShannon : public TransposerBase
{ {
protected: protected:
void resetRegisters();
int transposeMono(SAMPLETYPE *dest, int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
int transposeStereo(SAMPLETYPE *dest, int transposeStereo(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
int transposeMulti(SAMPLETYPE *dest, int transposeMulti(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples); int &srcSamples) override;
double fract; double fract;
public: public:
InterpolateShannon(); InterpolateShannon();
void resetRegisters() override;
virtual int getLatency() const override
{
return 3;
}
}; };
} }

View File

@ -33,7 +33,7 @@ libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp \
InterpolateShannon.cpp InterpolateShannon.cpp
# Compiler flags # Compiler flags
AM_CXXFLAGS+=-O3 #AM_CXXFLAGS+=
# Compile the files that need MMX and SSE individually. # Compile the files that need MMX and SSE individually.
libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la

View File

@ -57,7 +57,7 @@ int PeakFinder::findTop(const float *data, int peakpos) const
refvalue = data[peakpos]; refvalue = data[peakpos];
// seek within <EFBFBD>10 points // seek within ±10 points
start = peakpos - 10; start = peakpos - 10;
if (start < minPos) start = minPos; if (start < minPos) start = minPos;
end = peakpos + 10; end = peakpos + 10;
@ -142,7 +142,7 @@ int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, i
peaklevel = data[peakpos]; peaklevel = data[peakpos];
assert(peaklevel >= level); assert(peaklevel >= level);
pos = peakpos; pos = peakpos;
while ((pos >= minPos) && (pos < maxPos)) while ((pos >= minPos) && (pos + direction < maxPos))
{ {
if (data[pos + direction] < level) return pos; // crossing found if (data[pos + direction] < level) return pos; // crossing found
pos += direction; pos += direction;
@ -256,7 +256,7 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
// accept harmonic peak if // accept harmonic peak if
// (a) it is found // (a) it is found
// (b) is within <EFBFBD>4% of the expected harmonic interval // (b) is within ±4% of the expected harmonic interval
// (c) has at least half x-corr value of the max. peak // (c) has at least half x-corr value of the max. peak
double diff = harmonic * peaktmp / highPeak; double diff = harmonic * peaktmp / highPeak;

View File

@ -61,6 +61,7 @@ RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
// Instantiates the anti-alias filter // Instantiates the anti-alias filter
pAAFilter = new AAFilter(64); pAAFilter = new AAFilter(64);
pTransposer = TransposerBase::newInstance(); pTransposer = TransposerBase::newInstance();
clear();
} }
@ -77,6 +78,7 @@ void RateTransposer::enableAAFilter(bool newMode)
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER #ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover // Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
bUseAAFilter = newMode; bUseAAFilter = newMode;
clear();
#endif #endif
} }
@ -129,8 +131,6 @@ void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
// the 'set_returnBuffer_size' function. // the 'set_returnBuffer_size' function.
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples) void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
{ {
uint count;
if (nSamples == 0) return; if (nSamples == 0) return;
// Store samples to input buffer // Store samples to input buffer
@ -140,7 +140,7 @@ void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
// the filter // the filter
if (bUseAAFilter == false) if (bUseAAFilter == false)
{ {
count = pTransposer->transpose(outputBuffer, inputBuffer); (void)pTransposer->transpose(outputBuffer, inputBuffer);
return; return;
} }
@ -192,6 +192,11 @@ void RateTransposer::clear()
outputBuffer.clear(); outputBuffer.clear();
midBuffer.clear(); midBuffer.clear();
inputBuffer.clear(); inputBuffer.clear();
pTransposer->resetRegisters();
// prefill buffer to avoid losing first samples at beginning of stream
int prefill = getLatency();
inputBuffer.addSilent(prefill);
} }
@ -209,7 +214,8 @@ int RateTransposer::isEmpty() const
/// Return approximate initial input-output latency /// Return approximate initial input-output latency
int RateTransposer::getLatency() const int RateTransposer::getLatency() const
{ {
return (bUseAAFilter) ? pAAFilter->getLength() : 0; return pTransposer->getLatency() +
((bUseAAFilter) ? (pAAFilter->getLength() / 2) : 0);
} }
@ -301,7 +307,7 @@ TransposerBase *TransposerBase::newInstance()
default: default:
assert(false); assert(false);
return NULL; return nullptr;
} }
#endif #endif
} }

View File

@ -59,8 +59,6 @@ public:
}; };
protected: protected:
virtual void resetRegisters() = 0;
virtual int transposeMono(SAMPLETYPE *dest, virtual int transposeMono(SAMPLETYPE *dest,
const SAMPLETYPE *src, const SAMPLETYPE *src,
int &srcSamples) = 0; int &srcSamples) = 0;
@ -83,6 +81,9 @@ public:
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src); virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);
virtual void setRate(double newRate); virtual void setRate(double newRate);
virtual void setChannels(int channels); virtual void setChannels(int channels);
virtual int getLatency() const = 0;
virtual void resetRegisters() = 0;
// static factory function // static factory function
static TransposerBase *newInstance(); static TransposerBase *newInstance();
@ -123,7 +124,7 @@ protected:
public: public:
RateTransposer(); RateTransposer();
virtual ~RateTransposer(); virtual ~RateTransposer() override;
/// Returns the output buffer object /// Returns the output buffer object
FIFOSamplePipe *getOutput() { return &outputBuffer; }; FIFOSamplePipe *getOutput() { return &outputBuffer; };
@ -146,13 +147,13 @@ public:
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into /// Adds 'numSamples' pcs of samples from the 'samples' memory position into
/// the input of the object. /// the input of the object.
void putSamples(const SAMPLETYPE *samples, uint numSamples); void putSamples(const SAMPLETYPE *samples, uint numSamples) override;
/// Clears all the samples in the object /// Clears all the samples in the object
void clear(); void clear() override;
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
int isEmpty() const; int isEmpty() const override;
/// Return approximate initial input-output latency /// Return approximate initial input-output latency
int getLatency() const; int getLatency() const;

View File

@ -413,15 +413,15 @@ int SoundTouch::getSetting(int settingId) const
return (uint)pTDStretch->isQuickSeekEnabled(); return (uint)pTDStretch->isQuickSeekEnabled();
case SETTING_SEQUENCE_MS: case SETTING_SEQUENCE_MS:
pTDStretch->getParameters(NULL, &temp, NULL, NULL); pTDStretch->getParameters(nullptr, &temp, nullptr, nullptr);
return temp; return temp;
case SETTING_SEEKWINDOW_MS: case SETTING_SEEKWINDOW_MS:
pTDStretch->getParameters(NULL, NULL, &temp, NULL); pTDStretch->getParameters(nullptr, nullptr, &temp, nullptr);
return temp; return temp;
case SETTING_OVERLAP_MS: case SETTING_OVERLAP_MS:
pTDStretch->getParameters(NULL, NULL, NULL, &temp); pTDStretch->getParameters(nullptr, nullptr, nullptr, &temp);
return temp; return temp;
case SETTING_NOMINAL_INPUT_SEQUENCE : case SETTING_NOMINAL_INPUT_SEQUENCE :

View File

@ -20,32 +20,32 @@
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{68A5DD20-7057-448B-8FE0-B6AC8D205509}</ProjectGuid> <ProjectGuid>{68A5DD20-7057-448B-8FE0-B6AC8D205509}</ProjectGuid>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType> <ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<UseOfMfc>false</UseOfMfc> <UseOfMfc>false</UseOfMfc>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
@ -112,6 +112,7 @@
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName> <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile> <BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -153,6 +154,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
</EnableEnhancedInstructionSet> </EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName> <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile> <BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -183,11 +185,12 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
<BrowseInformation>true</BrowseInformation> <BrowseInformation>true</BrowseInformation>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<SuppressStartupBanner>true</SuppressStartupBanner> <SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs> <CompileAs>Default</CompileAs>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName> <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile> <BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -227,6 +230,7 @@ copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
</EnableEnhancedInstructionSet> </EnableEnhancedInstructionSet>
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName> <XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
<BrowseInformationFile>$(IntDir)</BrowseInformationFile> <BrowseInformationFile>$(IntDir)</BrowseInformationFile>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile> </ClCompile>
<ResourceCompile> <ResourceCompile>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>

View File

@ -1,4 +1,4 @@
//////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/// ///
/// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo /// Sampled sound tempo changer/time stretch algorithm. Changes the sound tempo
/// while maintaining the original pitch by using a time domain WSOLA-like /// while maintaining the original pitch by using a time domain WSOLA-like
@ -54,26 +54,6 @@ using namespace soundtouch;
#define max(x, y) (((x) > (y)) ? (x) : (y)) #define max(x, y) (((x) > (y)) ? (x) : (y))
/*****************************************************************************
*
* Constant definitions
*
*****************************************************************************/
// Table for the hierarchical mixing position seeking algorithm
const short _scanOffsets[5][24]={
{ 124, 186, 248, 310, 372, 434, 496, 558, 620, 682, 744, 806,
868, 930, 992, 1054, 1116, 1178, 1240, 1302, 1364, 1426, 1488, 0},
{-100, -75, -50, -25, 25, 50, 75, 100, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ -20, -15, -10, -5, 5, 10, 15, 20, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ -4, -3, -2, -1, 1, 2, 3, 4, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ 121, 114, 97, 114, 98, 105, 108, 32, 104, 99, 117, 111,
116, 100, 110, 117, 111, 115, 0, 0, 0, 0, 0, 0}};
/***************************************************************************** /*****************************************************************************
* *
* Implementation of the class 'TDStretch' * Implementation of the class 'TDStretch'
@ -86,18 +66,13 @@ TDStretch::TDStretch() : FIFOProcessor(&outputBuffer)
bQuickSeek = false; bQuickSeek = false;
channels = 2; channels = 2;
pMidBuffer = NULL; pMidBuffer = nullptr;
pMidBufferUnaligned = NULL; pMidBufferUnaligned = nullptr;
overlapLength = 0; overlapLength = 0;
bAutoSeqSetting = true; bAutoSeqSetting = true;
bAutoSeekSetting = true; bAutoSeekSetting = true;
maxnorm = 0;
maxnormf = 1e8;
skipFract = 0;
tempo = 1.0f; tempo = 1.0f;
setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS); setParameters(44100, DEFAULT_SEQUENCE_MS, DEFAULT_SEEKWINDOW_MS, DEFAULT_OVERLAP_MS);
setTempo(1.0f); setTempo(1.0f);
@ -168,7 +143,7 @@ void TDStretch::setParameters(int aSampleRate, int aSequenceMS,
/// Get routine control parameters, see setParameters() function. /// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be NULL, in such case corresponding parameter /// Any of the parameters to this function can be nullptr, in such case corresponding parameter
/// value isn't returned. /// value isn't returned.
void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const void TDStretch::getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const
{ {
@ -224,6 +199,9 @@ void TDStretch::clearInput()
inputBuffer.clear(); inputBuffer.clear();
clearMidBuffer(); clearMidBuffer();
isBeginning = true; isBeginning = true;
maxnorm = 0;
maxnormf = 1e8;
skipFract = 0;
} }
@ -315,9 +293,10 @@ int TDStretch::seekBestOverlapPositionFull(const SAMPLETYPE *refPos)
{ {
double corr; double corr;
// Calculates correlation value for the mixing position corresponding to 'i' // Calculates correlation value for the mixing position corresponding to 'i'
#ifdef _OPENMP #if defined(_OPENMP) || defined(ST_SIMD_AVOID_UNALIGNED)
// in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't // in parallel OpenMP mode, can't use norm accumulator version as parallel executor won't
// iterate the loop in sequential order // iterate the loop in sequential order
// in SIMD mode, avoid accumulator version to allow avoiding unaligned positions
corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm); corr = calcCrossCorr(refPos + channels * i, pMidBuffer, norm);
#else #else
// In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same // In non-parallel version call "calcCrossCorrAccumulate" that is otherwise same
@ -675,11 +654,10 @@ void TDStretch::processSamples()
// Adjust processing offset at beginning of track by not perform initial overlapping // Adjust processing offset at beginning of track by not perform initial overlapping
// and compensating that in the 'input buffer skip' calculation // and compensating that in the 'input buffer skip' calculation
isBeginning = false; isBeginning = false;
int skip = (int)(tempo * overlapLength + 0.5); int skip = (int)(tempo * overlapLength + 0.5 * seekLength + 0.5);
#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION #ifdef ST_SIMD_AVOID_UNALIGNED
#ifdef SOUNDTOUCH_ALLOW_SSE // in SIMD mode, round the skip amount to value corresponding to aligned memory address
// if SSE mode, round the skip amount to value corresponding to aligned memory address
if (channels == 1) if (channels == 1)
{ {
skip &= -4; skip &= -4;
@ -689,9 +667,11 @@ void TDStretch::processSamples()
skip &= -2; skip &= -2;
} }
#endif #endif
#endif
skipFract -= skip; skipFract -= skip;
assert(nominalSkip >= -skipFract); if (skipFract <= -nominalSkip)
{
skipFract = -nominalSkip;
}
} }
// ... then copy sequence samples from 'inputBuffer' to output: // ... then copy sequence samples from 'inputBuffer' to output:
@ -760,7 +740,7 @@ void TDStretch::acceptNewOverlapLength(int newOverlapLength)
// Operator 'new' is overloaded so that it automatically creates a suitable instance // Operator 'new' is overloaded so that it automatically creates a suitable instance
// depending on if we've a MMX/SSE/etc-capable CPU available or not. // depending on if we've a MMX/SSE/etc-capable CPU available or not.
void * TDStretch::operator new(size_t s) void * TDStretch::operator new(size_t)
{ {
// Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead! // Notice! don't use "new TDStretch" directly, use "newInstance" to create a new instance instead!
ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!"); ST_THROW_RT_ERROR("Error in TDStretch::new: Don't use 'new TDStretch' directly, use 'newInstance' member instead!");
@ -773,6 +753,7 @@ TDStretch * TDStretch::newInstance()
uint uExtensions; uint uExtensions;
uExtensions = detectCPUextensions(); uExtensions = detectCPUextensions();
(void)uExtensions;
// Check if MMX/SSE instruction set extensions supported by CPU // Check if MMX/SSE instruction set extensions supported by CPU
@ -830,21 +811,19 @@ void TDStretch::overlapStereo(short *poutput, const short *input) const
// Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Multi' // Overlaps samples in 'midBuffer' with the samples in 'input'. The 'Multi'
// version of the routine. // version of the routine.
void TDStretch::overlapMulti(SAMPLETYPE *poutput, const SAMPLETYPE *input) const void TDStretch::overlapMulti(short *poutput, const short *input) const
{ {
SAMPLETYPE m1=(SAMPLETYPE)0; short m1;
SAMPLETYPE m2; int i = 0;
int i=0;
for (m2 = (SAMPLETYPE)overlapLength; m2; m2 --) for (m1 = 0; m1 < overlapLength; m1 ++)
{ {
short m2 = (short)(overlapLength - m1);
for (int c = 0; c < channels; c ++) for (int c = 0; c < channels; c ++)
{ {
poutput[i] = (input[i] * m1 + pMidBuffer[i] * m2) / overlapLength; poutput[i] = (input[i] * m1 + pMidBuffer[i] * m2) / overlapLength;
i++; i++;
} }
m1++;
} }
} }
@ -889,20 +868,23 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do
unsigned long lnorm; unsigned long lnorm;
int i; int i;
#ifdef ST_SIMD_AVOID_UNALIGNED
// in SIMD mode skip 'mixingPos' positions that aren't aligned to 16-byte boundary
if (((ulongptr)mixingPos) & 15) return -1e50;
#endif
// hint compiler autovectorization that loop length is divisible by 8
int ilength = (channels * overlapLength) & -8;
corr = lnorm = 0; corr = lnorm = 0;
// Same routine for stereo and mono. For stereo, unroll loop for better // Same routine for stereo and mono
// efficiency and gives slightly better resolution against rounding. for (i = 0; i < ilength; i += 2)
// For mono it same routine, just unrolls loop by factor of 4
for (i = 0; i < channels * overlapLength; i += 4)
{ {
corr += (mixingPos[i] * compare[i] + corr += (mixingPos[i] * compare[i] +
mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; // notice: do intermediate division here to avoid integer overflow mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;
corr += (mixingPos[i + 2] * compare[i + 2] +
mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBitsNorm;
lnorm += (mixingPos[i] * mixingPos[i] + lnorm += (mixingPos[i] * mixingPos[i] +
mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm; // notice: do intermediate division here to avoid integer overflow mixingPos[i + 1] * mixingPos[i + 1]) >> overlapDividerBitsNorm;
lnorm += (mixingPos[i + 2] * mixingPos[i + 2] + // do intermediate scalings to avoid integer overflow
mixingPos[i + 3] * mixingPos[i + 3]) >> overlapDividerBitsNorm;
} }
if (lnorm > maxnorm) if (lnorm > maxnorm)
@ -925,9 +907,12 @@ double TDStretch::calcCrossCorr(const short *mixingPos, const short *compare, do
double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm)
{ {
long corr; long corr;
unsigned long lnorm; long lnorm;
int i; int i;
// hint compiler autovectorization that loop length is divisible by 8
int ilength = (channels * overlapLength) & -8;
// cancel first normalizer tap from previous round // cancel first normalizer tap from previous round
lnorm = 0; lnorm = 0;
for (i = 1; i <= channels; i ++) for (i = 1; i <= channels; i ++)
@ -936,15 +921,11 @@ double TDStretch::calcCrossCorrAccumulate(const short *mixingPos, const short *c
} }
corr = 0; corr = 0;
// Same routine for stereo and mono. For stereo, unroll loop for better // Same routine for stereo and mono.
// efficiency and gives slightly better resolution against rounding. for (i = 0; i < ilength; i += 2)
// For mono it same routine, just unrolls loop by factor of 4
for (i = 0; i < channels * overlapLength; i += 4)
{ {
corr += (mixingPos[i] * compare[i] + corr += (mixingPos[i] * compare[i] +
mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm; // notice: do intermediate division here to avoid integer overflow mixingPos[i + 1] * compare[i + 1]) >> overlapDividerBitsNorm;
corr += (mixingPos[i + 2] * compare[i + 2] +
mixingPos[i + 3] * compare[i + 3]) >> overlapDividerBitsNorm;
} }
// update normalizer with last samples of this round // update normalizer with last samples of this round
@ -1045,27 +1026,24 @@ void TDStretch::calculateOverlapLength(int overlapInMsec)
/// Calculate cross-correlation /// Calculate cross-correlation
double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, double &anorm) double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, double &anorm)
{ {
double corr; float corr;
double norm; float norm;
int i; int i;
#ifdef ST_SIMD_AVOID_UNALIGNED
// in SIMD mode skip 'mixingPos' positions that aren't aligned to 16-byte boundary
if (((ulongptr)mixingPos) & 15) return -1e50;
#endif
// hint compiler autovectorization that loop length is divisible by 8
int ilength = (channels * overlapLength) & -8;
corr = norm = 0; corr = norm = 0;
// Same routine for stereo and mono. For Stereo, unroll by factor of 2. // Same routine for stereo and mono
// For mono it's same routine yet unrollsd by factor of 4. for (i = 0; i < ilength; i ++)
for (i = 0; i < channels * overlapLength; i += 4)
{ {
corr += mixingPos[i] * compare[i] + corr += mixingPos[i] * compare[i];
mixingPos[i + 1] * compare[i + 1]; norm += mixingPos[i] * mixingPos[i];
norm += mixingPos[i] * mixingPos[i] +
mixingPos[i + 1] * mixingPos[i + 1];
// unroll the loop for better CPU efficiency:
corr += mixingPos[i + 2] * compare[i + 2] +
mixingPos[i + 3] * compare[i + 3];
norm += mixingPos[i + 2] * mixingPos[i + 2] +
mixingPos[i + 3] * mixingPos[i + 3];
} }
anorm = norm; anorm = norm;
@ -1076,7 +1054,7 @@ double TDStretch::calcCrossCorr(const float *mixingPos, const float *compare, do
/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value /// Update cross-correlation by accumulating "norm" coefficient by previously calculated value
double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm)
{ {
double corr; float corr;
int i; int i;
corr = 0; corr = 0;
@ -1087,14 +1065,13 @@ double TDStretch::calcCrossCorrAccumulate(const float *mixingPos, const float *c
norm -= mixingPos[-i] * mixingPos[-i]; norm -= mixingPos[-i] * mixingPos[-i];
} }
// Same routine for stereo and mono. For Stereo, unroll by factor of 2. // hint compiler autovectorization that loop length is divisible by 8
// For mono it's same routine yet unrollsd by factor of 4. int ilength = (channels * overlapLength) & -8;
for (i = 0; i < channels * overlapLength; i += 4)
// Same routine for stereo and mono
for (i = 0; i < ilength; i ++)
{ {
corr += mixingPos[i] * compare[i] + corr += mixingPos[i] * compare[i];
mixingPos[i + 1] * compare[i + 1] +
mixingPos[i + 2] * compare[i + 2] +
mixingPos[i + 3] * compare[i + 3];
} }
// update normalizer with last samples of this round // update normalizer with last samples of this round

View File

@ -165,7 +165,7 @@ protected:
public: public:
TDStretch(); TDStretch();
virtual ~TDStretch(); virtual ~TDStretch() override;
/// Operator 'new' is overloaded so that it automatically creates a suitable instance /// Operator 'new' is overloaded so that it automatically creates a suitable instance
/// depending on if we've a MMX/SSE/etc-capable CPU available or not. /// depending on if we've a MMX/SSE/etc-capable CPU available or not.
@ -187,7 +187,7 @@ public:
void setTempo(double newTempo); void setTempo(double newTempo);
/// Returns nonzero if there aren't any samples available for outputting. /// Returns nonzero if there aren't any samples available for outputting.
virtual void clear(); virtual void clear() override;
/// Clears the input buffer /// Clears the input buffer
void clearInput(); void clearInput();
@ -217,7 +217,7 @@ public:
); );
/// Get routine control parameters, see setParameters() function. /// Get routine control parameters, see setParameters() function.
/// Any of the parameters to this function can be NULL, in such case corresponding parameter /// Any of the parameters to this function can be nullptr, in such case corresponding parameter
/// value isn't returned. /// value isn't returned.
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const; void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
@ -227,7 +227,7 @@ public:
const SAMPLETYPE *samples, ///< Input sample data const SAMPLETYPE *samples, ///< Input sample data
uint numSamples ///< Number of samples in 'samples' so that one sample uint numSamples ///< Number of samples in 'samples' so that one sample
///< contains both channels if stereo ///< contains both channels if stereo
); ) override;
/// return nominal input sample requirement for triggering a processing batch /// return nominal input sample requirement for triggering a processing batch
int getInputSampleReq() const int getInputSampleReq() const
@ -256,10 +256,10 @@ public:
class TDStretchMMX : public TDStretch class TDStretchMMX : public TDStretch
{ {
protected: protected:
double calcCrossCorr(const short *mixingPos, const short *compare, double &norm); double calcCrossCorr(const short *mixingPos, const short *compare, double &norm) override;
double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm); double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) override;
virtual void overlapStereo(short *output, const short *input) const; virtual void overlapStereo(short *output, const short *input) const override;
virtual void clearCrossCorrState(); virtual void clearCrossCorrState() override;
}; };
#endif /// SOUNDTOUCH_ALLOW_MMX #endif /// SOUNDTOUCH_ALLOW_MMX
@ -269,8 +269,8 @@ public:
class TDStretchSSE : public TDStretch class TDStretchSSE : public TDStretch
{ {
protected: protected:
double calcCrossCorr(const float *mixingPos, const float *compare, double &norm); double calcCrossCorr(const float *mixingPos, const float *compare, double &norm) override;
double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm); double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) override;
}; };
#endif /// SOUNDTOUCH_ALLOW_SSE #endif /// SOUNDTOUCH_ALLOW_SSE

View File

@ -294,8 +294,8 @@ void TDStretchMMX::overlapStereo(short *output, const short *input) const
FIRFilterMMX::FIRFilterMMX() : FIRFilter() FIRFilterMMX::FIRFilterMMX() : FIRFilter()
{ {
filterCoeffsAlign = NULL; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = NULL; filterCoeffsUnalign = nullptr;
} }

View File

@ -80,7 +80,7 @@ double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &a
// Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided // Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
// for choosing if this little cheating is allowed. // for choosing if this little cheating is allowed.
#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION #ifdef ST_SIMD_AVOID_UNALIGNED
// Little cheating allowed, return valid correlation only for // Little cheating allowed, return valid correlation only for
// aligned locations, meaning every second round for stereo sound. // aligned locations, meaning every second round for stereo sound.
@ -195,25 +195,22 @@ double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2,
FIRFilterSSE::FIRFilterSSE() : FIRFilter() FIRFilterSSE::FIRFilterSSE() : FIRFilter()
{ {
filterCoeffsAlign = NULL; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = NULL; filterCoeffsUnalign = nullptr;
} }
FIRFilterSSE::~FIRFilterSSE() FIRFilterSSE::~FIRFilterSSE()
{ {
delete[] filterCoeffsUnalign; delete[] filterCoeffsUnalign;
filterCoeffsAlign = NULL; filterCoeffsAlign = nullptr;
filterCoeffsUnalign = NULL; filterCoeffsUnalign = nullptr;
} }
// (overloaded) Calculates filter coefficients for SSE routine // (overloaded) Calculates filter coefficients for SSE routine
void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
{ {
uint i;
float fDivider;
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor); FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
// Scale the filter coefficients so that it won't be necessary to scale the filtering result // Scale the filter coefficients so that it won't be necessary to scale the filtering result
@ -223,13 +220,13 @@ void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uRe
filterCoeffsUnalign = new float[2 * newLength + 4]; filterCoeffsUnalign = new float[2 * newLength + 4];
filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign); filterCoeffsAlign = (float *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
fDivider = (float)resultDivider; const float scale = ::pow(0.5, (int)resultDivFactor);
// rearrange the filter coefficients for mmx routines // rearrange the filter coefficients for sse routines
for (i = 0; i < newLength; i ++) for (auto i = 0U; i < newLength; i ++)
{ {
filterCoeffsAlign[2 * i + 0] = filterCoeffsAlign[2 * i + 0] =
filterCoeffsAlign[2 * i + 1] = coeffs[i + 0] / fDivider; filterCoeffsAlign[2 * i + 1] = coeffs[i] * scale;
} }
} }
@ -245,10 +242,10 @@ uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint n
if (count < 2) return 0; if (count < 2) return 0;
assert(source != NULL); assert(source != nullptr);
assert(dest != NULL); assert(dest != nullptr);
assert((length % 8) == 0); assert((length % 8) == 0);
assert(filterCoeffsAlign != NULL); assert(filterCoeffsAlign != nullptr);
assert(((ulongptr)filterCoeffsAlign) % 16 == 0); assert(((ulongptr)filterCoeffsAlign) % 16 == 0);
// filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2' // filter is evaluated for two stereo samples with each iteration, thus use of 'j += 2'

View File

@ -16,9 +16,10 @@
#include "../../SoundStretch/WavFile.h" #include "../../SoundStretch/WavFile.h"
using namespace std; using namespace std;
using namespace soundstretch;
// DllTest main // DllTest main
int main(int argc, char *argv[]) int wmain(int argc, const wchar_t *argv[])
{ {
// Check program arguments // Check program arguments
if (argc < 4) if (argc < 4)
@ -27,22 +28,22 @@ int main(int argc, char *argv[])
return -1; return -1;
} }
const char *inFileName = argv[1]; wstring inFileName = argv[1];
const char *outFileName = argv[2]; wstring outFileName = argv[2];
string str_sampleType = argv[3]; wstring str_sampleType = argv[3];
bool floatSample; bool floatSample;
if (str_sampleType.compare("float") == 0) if (str_sampleType == L"float")
{ {
floatSample = true; floatSample = true;
} }
else if (str_sampleType.compare("short") == 0) else if (str_sampleType == L"short")
{ {
floatSample = false; floatSample = false;
} }
else else
{ {
cerr << "Missing or invalid sampletype '" << str_sampleType << "'. Expected either short or float" << endl; cerr << "Missing or invalid sampletype. Expected either short or float" << endl;
return -1; return -1;
} }

View File

@ -22,32 +22,32 @@
<ProjectGuid>{E3C0726F-28F4-4F0B-8183-B87CA60C063C}</ProjectGuid> <ProjectGuid>{E3C0726F-28F4-4F0B-8183-B87CA60C063C}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>DllTest</RootNamespace> <RootNamespace>DllTest</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>

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,11 +2,8 @@ unit SoundTouchDLL;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
// SoundTouch.dll wrapper for accessing SoundTouch routines from Delphi/Pascal // SoundTouch.dll / libSoundTouchDll.so wrapper for accessing SoundTouch
// // routines from Delphi/Pascal/Lazarus
// Module Author : Christian Budde
//
// 2014-01-12 fixes by Sandro Cumerlato <sandro.cumerlato 'at' gmail.com>
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
@ -33,8 +30,8 @@ unit SoundTouchDLL;
interface interface
uses //uses
Windows; //Windows;
type type
TSoundTouchHandle = THandle; TSoundTouchHandle = THandle;
@ -107,6 +104,13 @@ type
//< contains data for both channels. //< contains data for both channels.
); cdecl; ); 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 // Clears all the samples in the object's output and internal processing
// buffers. // buffers.
TSoundTouchClear = procedure (Handle: TSoundTouchHandle); cdecl; TSoundTouchClear = procedure (Handle: TSoundTouchHandle); cdecl;
@ -131,16 +135,20 @@ type
// Returns number of samples currently unprocessed. // Returns number of samples currently unprocessed.
TSoundTouchNumUnprocessedSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl; TSoundTouchNumUnprocessedSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;
// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Receive ready samples from the processing pipeline.
// sample buffer without copying them anywhere. ///
// /// if called with outBuffer=nullptr, just reduces amount of ready samples within the pipeline.
// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
// with 'ptrBegin' function.
TSoundTouchReceiveSamples = function (Handle: TSoundTouchHandle; TSoundTouchReceiveSamples = function (Handle: TSoundTouchHandle;
OutBuffer: PSingle; //< Buffer where to copy output samples. OutBuffer: PSingle; //< Buffer where to copy output samples.
MaxSamples: Integer //< How many samples to receive at max. MaxSamples: Integer //< How many samples to receive at max.
): Cardinal; cdecl; ): 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. // Returns number of samples currently available.
TSoundTouchNumSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl; TSoundTouchNumSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;
@ -170,6 +178,7 @@ var
SoundTouchGetSetting : TSoundTouchGetSetting; SoundTouchGetSetting : TSoundTouchGetSetting;
SoundTouchNumUnprocessedSamples : TSoundTouchNumUnprocessedSamples; SoundTouchNumUnprocessedSamples : TSoundTouchNumUnprocessedSamples;
SoundTouchReceiveSamples : TSoundTouchReceiveSamples; SoundTouchReceiveSamples : TSoundTouchReceiveSamples;
SoundTouchReceiveSamplesI16 : TSoundTouchReceiveSamplesI16;
SoundTouchNumSamples : TSoundTouchNumSamples; SoundTouchNumSamples : TSoundTouchNumSamples;
SoundTouchIsEmpty : TSoundTouchIsEmpty; SoundTouchIsEmpty : TSoundTouchIsEmpty;
@ -232,6 +241,9 @@ type
property IsEmpty: Integer read GetIsEmpty; property IsEmpty: Integer read GetIsEmpty;
end; end;
// list of exported functions and procedures
function IsSoundTouchLoaded: Boolean;
implementation implementation
{ TSoundTouch } { TSoundTouch }
@ -416,19 +428,23 @@ begin
end; end;
var var
SoundTouchLibHandle: HINST; SoundTouchLibHandle: THandle;
SoundTouchDLLFile: PAnsiChar = 'SoundTouch.dll'; SoundTouchDLLFile: AnsiString = 'libSoundTouchDll.so';
//SoundTouchDLLFile: AnsiString = 'SoundTouch.dll';
// bpm detect functions. untested -- if these don't work then remove: // bpm detect functions. untested -- if these don't work then remove:
bpm_createInstance: function(chan: CInt32; sampleRate : CInt32): THandle; cdecl; bpm_createInstance: function(chan: int32; sampleRate : int32): THandle; cdecl;
bpm_destroyInstance: procedure(h: THandle); cdecl; bpm_destroyInstance: procedure(h: THandle); cdecl;
bpm_getBpm: function(h: THandle): cfloat; cdecl; bpm_getBpm: function(h: THandle): Single; cdecl;
bpm_putSamples: procedure(h: THandle; const samples: pcfloat; bpm_putSamples: procedure(h: THandle; const samples: PSingle; numSamples: cardinal); cdecl;
numSamples: cardinal); cdecl;
procedure InitDLL; procedure InitDLL;
begin begin
SoundTouchLibHandle := LoadLibrary(SoundTouchDLLFile); {$ifdef mswindows} // Windows
SoundTouchLibHandle := LoadLibrary('.\SoundTouchDll.dll');
{$else} // Unix
SoundTouchLibHandle := LoadLibrary('./libSoundTouchDll.so');
{$endif}
if SoundTouchLibHandle <> 0 then if SoundTouchLibHandle <> 0 then
try try
Pointer(SoundTouchCreateInstance) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_createInstance'); Pointer(SoundTouchCreateInstance) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_createInstance');
@ -473,6 +489,12 @@ begin
if SoundTouchLibHandle <> 0 then FreeLibrary(SoundTouchLibHandle); if SoundTouchLibHandle <> 0 then FreeLibrary(SoundTouchLibHandle);
end; end;
// returns 'true' if SoundTouch dynamic library has been successfully loaded, otherwise 'false'
function IsSoundTouchLoaded: Boolean;
begin;
result := SoundTouchLibHandle <> 0
end;
initialization initialization
InitDLL; 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>

View File

@ -0,0 +1,25 @@
program soundtouchtest;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
{$IFDEF HASAMIGA}
athreads,
{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, main
{ you can add units after this };
{$R *.res}
begin
RequireDerivedFormResource:=True;
Application.Scaled:=True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="UTF-8"?>
<CONFIG>
<ProjectSession>
<Version Value="12"/>
<BuildModes Active="Default"/>
<Units>
<Unit>
<Filename Value="soundtouchtest.lpr"/>
<IsPartOfProject Value="True"/>
<EditorIndex Value="-1"/>
<WindowIndex Value="-1"/>
<TopLine Value="-1"/>
<CursorPos X="-1" Y="-1"/>
<UsageCount Value="21"/>
</Unit>
<Unit>
<Filename Value="main.pas"/>
<IsPartOfProject Value="True"/>
<ComponentName Value="Form1"/>
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
<IsVisibleTab Value="True"/>
<CursorPos X="26" Y="43"/>
<UsageCount Value="21"/>
<Loaded Value="True"/>
<LoadedDesigner Value="True"/>
</Unit>
<Unit>
<Filename Value="../SoundTouchDLL.pas"/>
<EditorIndex Value="-1"/>
<TopLine Value="37"/>
<CursorPos X="19"/>
<UsageCount Value="10"/>
</Unit>
<Unit>
<Filename Value="/usr/lib/lazarus/2.2.0/lcl/interfaces/gtk2/gtk2proc.inc"/>
<EditorIndex Value="-1"/>
<TopLine Value="7149"/>
<CursorPos X="3" Y="7184"/>
<UsageCount Value="10"/>
</Unit>
<Unit>
<Filename Value="/usr/lib/lazarus/2.2.0/components/freetype/easylazfreetype.pas"/>
<UnitName Value="EasyLazFreeType"/>
<EditorIndex Value="-1"/>
<TopLine Value="539"/>
<CursorPos X="16" Y="574"/>
<UsageCount Value="10"/>
</Unit>
<Unit>
<Filename Value="SoundTouchDLL.pas"/>
<EditorIndex Value="1"/>
<TopLine Value="326"/>
<CursorPos X="127" Y="379"/>
<UsageCount Value="10"/>
<Loaded Value="True"/>
</Unit>
</Units>
<JumpHistory HistoryIndex="29">
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="439" TopLine="403"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="427" Column="37" TopLine="403"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="439" TopLine="403"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="427" Column="32" TopLine="403"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="444" Column="48" TopLine="403"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="439" TopLine="403"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="416" Column="116" TopLine="403"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="439" TopLine="403"/>
</Position>
<Position>
<Filename Value="main.pas"/>
<Caret Line="45" Column="40"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="243" Column="38" TopLine="197"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="487" Column="38" TopLine="429"/>
</Position>
<Position>
<Filename Value="main.pas"/>
<Caret Line="42" Column="8"/>
</Position>
<Position>
<Filename Value="main.pas"/>
<Caret Line="41" Column="44"/>
</Position>
<Position>
<Filename Value="main.pas"/>
<Caret Line="44" Column="6"/>
</Position>
<Position>
<Filename Value="main.pas"/>
<Caret Line="43" Column="39"/>
</Position>
<Position>
<Filename Value="main.pas"/>
<Caret Line="44" Column="7"/>
</Position>
<Position>
<Filename Value="main.pas"/>
<Caret Line="38" Column="7"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="467" TopLine="423"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="212" Column="32" TopLine="78"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="361" Column="37" TopLine="308"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="466" Column="37" TopLine="413"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="467" Column="37" TopLine="413"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="466" Column="13" TopLine="413"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="361" Column="13" TopLine="326"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="110" Column="3" TopLine="74"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="180" Column="37" TopLine="145"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="179" Column="55" TopLine="145"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="146" Column="3" TopLine="145"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="149" TopLine="111"/>
</Position>
<Position>
<Filename Value="SoundTouchDLL.pas"/>
<Caret Line="151" Column="31" TopLine="116"/>
</Position>
</JumpHistory>
<RunParams>
<FormatVersion Value="2"/>
<Modes ActiveMode=""/>
</RunParams>
</ProjectSession>
</CONFIG>

View File

@ -0,0 +1,47 @@
## 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
noinst_HEADERS=../SoundTouch/AAFilter.h ../SoundTouch/cpu_detect.h ../SoundTouch/cpu_detect_x86.cpp ../SoundTouch/FIRFilter.h \
../SoundTouch/RateTransposer.h ../SoundTouch/TDStretch.h ../SoundTouch/PeakFinder.h ../SoundTouch/InterpolateCubic.h \
../SoundTouch/InterpolateLinear.h ../SoundTouch/InterpolateShannon.h
include_HEADERS=SoundTouchDLL.h
lib_LTLIBRARIES=libSoundTouchDll.la
#
libSoundTouchDll_la_SOURCES=../SoundTouch/AAFilter.cpp ../SoundTouch/FIRFilter.cpp \
../SoundTouch/FIFOSampleBuffer.cpp ../SoundTouch/RateTransposer.cpp ../SoundTouch/SoundTouch.cpp \
../SoundTouch/TDStretch.cpp ../SoundTouch/sse_optimized.cpp ../SoundTouch/cpu_detect_x86.cpp \
../SoundTouch/BPMDetect.cpp ../SoundTouch/PeakFinder.cpp ../SoundTouch/InterpolateLinear.cpp \
../SoundTouch/InterpolateCubic.cpp ../SoundTouch/InterpolateShannon.cpp SoundTouchDLL.cpp
# Compiler flags
# Modify the default 0.0.0 to LIB_SONAME.0.0
AM_LDFLAGS=$(LDFLAGS) -version-info @LIB_SONAME@
if X86
CXXFLAGS1=-mstackrealign -msse
endif
if X86_64
CXXFLAGS2=-fPIC
endif
AM_CXXFLAGS=$(CXXFLAGS) $(CXXFLAGS1) $(CXXFLAGS2) -shared -DDLL_EXPORTS -fvisibility=hidden

View File

@ -90,10 +90,10 @@ SOUNDTOUCHDLL_API HANDLE __cdecl soundtouch_createInstance()
{ {
tmp->dwMagic = STMAGIC; tmp->dwMagic = STMAGIC;
tmp->pst = new SoundTouch(); tmp->pst = new SoundTouch();
if (tmp->pst == NULL) if (tmp->pst == nullptr)
{ {
delete tmp; delete tmp;
tmp = NULL; tmp = nullptr;
} }
} }
return (HANDLE)tmp; return (HANDLE)tmp;
@ -107,7 +107,7 @@ SOUNDTOUCHDLL_API void __cdecl soundtouch_destroyInstance(HANDLE h)
sth->dwMagic = 0; sth->dwMagic = 0;
if (sth->pst) delete sth->pst; if (sth->pst) delete sth->pst;
sth->pst = NULL; sth->pst = nullptr;
delete sth; delete sth;
} }
@ -207,21 +207,37 @@ SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newP
/// Sets the number of channels, 1 = mono, 2 = stereo /// Sets the number of channels, 1 = mono, 2 = stereo
SOUNDTOUCHDLL_API void __cdecl soundtouch_setChannels(HANDLE h, uint numChannels) SOUNDTOUCHDLL_API int __cdecl soundtouch_setChannels(HANDLE h, uint numChannels)
{ {
STHANDLE *sth = (STHANDLE*)h; STHANDLE *sth = (STHANDLE*)h;
if (sth->dwMagic != STMAGIC) return; if (sth->dwMagic != STMAGIC) return 0;
try
{
sth->pst->setChannels(numChannels); sth->pst->setChannels(numChannels);
}
catch (const std::exception&)
{
return 0;
}
return 1;
} }
/// Sets sample rate. /// Sets sample rate.
SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, uint srate) SOUNDTOUCHDLL_API int __cdecl soundtouch_setSampleRate(HANDLE h, uint srate)
{ {
STHANDLE *sth = (STHANDLE*)h; STHANDLE *sth = (STHANDLE*)h;
if (sth->dwMagic != STMAGIC) return; if (sth->dwMagic != STMAGIC) return 0;
try
{
sth->pst->setSampleRate(srate); sth->pst->setSampleRate(srate);
}
catch (const std::exception&)
{
return 0;
}
return 1;
} }
/// Flushes the last samples from the processing pipeline to the output. /// Flushes the last samples from the processing pipeline to the output.
@ -231,18 +247,26 @@ SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, uint srate)
/// stream. This function may introduce additional blank samples in the end /// 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 /// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream. /// in the middle of a sound stream.
SOUNDTOUCHDLL_API void __cdecl soundtouch_flush(HANDLE h) SOUNDTOUCHDLL_API int __cdecl soundtouch_flush(HANDLE h)
{ {
STHANDLE *sth = (STHANDLE*)h; STHANDLE *sth = (STHANDLE*)h;
if (sth->dwMagic != STMAGIC) return; if (sth->dwMagic != STMAGIC) return 0;
try
{
sth->pst->flush(); sth->pst->flush();
}
catch (const std::exception&)
{
return 0;
}
return 1;
} }
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into /// 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 /// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception. /// calling this function, otherwise throws a runtime_error exception.
SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h, SOUNDTOUCHDLL_API int __cdecl soundtouch_putSamples(HANDLE h,
const SAMPLETYPE *samples, ///< Pointer to sample buffer. const SAMPLETYPE *samples, ///< Pointer to sample buffer.
unsigned int numSamples ///< Number of samples in buffer. Notice unsigned int numSamples ///< Number of samples in buffer. Notice
///< that in case of stereo-sound a single sample ///< that in case of stereo-sound a single sample
@ -250,9 +274,17 @@ SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h,
) )
{ {
STHANDLE *sth = (STHANDLE*)h; STHANDLE *sth = (STHANDLE*)h;
if (sth->dwMagic != STMAGIC) return; if (sth->dwMagic != STMAGIC) return 0;
try
{
sth->pst->putSamples(samples, numSamples); sth->pst->putSamples(samples, numSamples);
}
catch (const std::exception&)
{
return 0;
}
return 1;
} }
/// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data /// int16 version of soundtouch_putSamples(): This accept int16 (short) sample data
@ -341,11 +373,9 @@ SOUNDTOUCHDLL_API uint __cdecl soundtouch_numUnprocessedSamples(HANDLE h)
} }
/// Adjusts book-keeping so that given number of samples are removed from beginning of the /// Receive ready samples from the processing pipeline.
/// sample buffer without copying them anywhere.
/// ///
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly /// if called with outBuffer=nullptr, just reduces amount of ready samples within the pipeline.
/// with 'ptrBegin' function.
SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples(HANDLE h, SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples(HANDLE h,
SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples. SAMPLETYPE *outBuffer, ///< Buffer where to copy output samples.
unsigned int maxSamples ///< How many samples to receive at max. unsigned int maxSamples ///< How many samples to receive at max.
@ -376,7 +406,7 @@ SOUNDTOUCHDLL_API uint __cdecl soundtouch_receiveSamples_i16(HANDLE h,
if (sth->dwMagic != STMAGIC) return 0; if (sth->dwMagic != STMAGIC) return 0;
uint outTotal = 0; uint outTotal = 0;
if (outBuffer == NULL) if (outBuffer == nullptr)
{ {
// only reduce sample count, not receive samples // only reduce sample count, not receive samples
return sth->pst->receiveSamples(maxSamples); return sth->pst->receiveSamples(maxSamples);
@ -444,11 +474,18 @@ SOUNDTOUCHDLL_API HANDLE __cdecl bpm_createInstance(int numChannels, int sampleR
if (tmp) if (tmp)
{ {
tmp->dwMagic = BPMMAGIC; tmp->dwMagic = BPMMAGIC;
try
{
tmp->pbpm = new BPMDetect(numChannels, sampleRate); tmp->pbpm = new BPMDetect(numChannels, sampleRate);
if (tmp->pbpm == NULL) }
catch (const std::exception&)
{
tmp->pbpm = nullptr;
}
if (tmp->pbpm == nullptr)
{ {
delete tmp; delete tmp;
tmp = NULL; tmp = nullptr;
} }
} }
return (HANDLE)tmp; return (HANDLE)tmp;
@ -462,7 +499,7 @@ SOUNDTOUCHDLL_API void __cdecl bpm_destroyInstance(HANDLE h)
sth->dwMagic = 0; sth->dwMagic = 0;
if (sth->pbpm) delete sth->pbpm; if (sth->pbpm) delete sth->pbpm;
sth->pbpm = NULL; sth->pbpm = nullptr;
delete sth; delete sth;
} }
@ -525,3 +562,21 @@ SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h)
return bpmh->pbpm->getBpm(); return bpmh->pbpm->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.
SOUNDTOUCHDLL_API int __cdecl bpm_getBeats(HANDLE h, float* pos, float* strength, int count)
{
BPMHANDLE *bpmh = (BPMHANDLE *)h;
if (bpmh->dwMagic != BPMMAGIC) return 0;
return bpmh->pbpm->getBeats(pos, strength, count);
}

View File

@ -48,12 +48,12 @@
#else #else
// GNU version // GNU version
#ifdef DLL_EXPORTS #if defined(DLL_EXPORTS) || defined(SoundTouchDLL_EXPORTS)
// GCC declaration for exporting functions // GCC declaration for exporting functions
#define SOUNDTOUCHDLL_API extern "C" __attribute__((__visibility__("default"))) #define SOUNDTOUCHDLL_API extern "C" __attribute__((__visibility__("default")))
#else #else
// GCC doesn't require DLL imports // import function
#define SOUNDTOUCHDLL_API #define SOUNDTOUCHDLL_API extern "C"
#endif #endif
// Linux-replacements for Windows declarations: // Linux-replacements for Windows declarations:
@ -112,10 +112,10 @@ SOUNDTOUCHDLL_API void __cdecl soundtouch_setPitchSemiTones(HANDLE h, float newP
/// Sets the number of channels, 1 = mono, 2 = stereo, n = multichannel /// Sets the number of channels, 1 = mono, 2 = stereo, n = multichannel
SOUNDTOUCHDLL_API void __cdecl soundtouch_setChannels(HANDLE h, unsigned int numChannels); SOUNDTOUCHDLL_API int __cdecl soundtouch_setChannels(HANDLE h, unsigned int numChannels);
/// Sets sample rate. /// Sets sample rate.
SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, unsigned int srate); SOUNDTOUCHDLL_API int __cdecl soundtouch_setSampleRate(HANDLE h, unsigned int srate);
/// Flushes the last samples from the processing pipeline to the output. /// Flushes the last samples from the processing pipeline to the output.
/// Clears also the internal processing buffers. /// Clears also the internal processing buffers.
@ -124,12 +124,12 @@ SOUNDTOUCHDLL_API void __cdecl soundtouch_setSampleRate(HANDLE h, unsigned int s
/// stream. This function may introduce additional blank samples in the end /// 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 /// of the sound stream, and thus it's not recommended to call this function
/// in the middle of a sound stream. /// in the middle of a sound stream.
SOUNDTOUCHDLL_API void __cdecl soundtouch_flush(HANDLE h); SOUNDTOUCHDLL_API int __cdecl soundtouch_flush(HANDLE h);
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into /// 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 /// the input of the object. Notice that sample rate _has_to_ be set before
/// calling this function, otherwise throws a runtime_error exception. /// calling this function, otherwise throws a runtime_error exception.
SOUNDTOUCHDLL_API void __cdecl soundtouch_putSamples(HANDLE h, SOUNDTOUCHDLL_API int __cdecl soundtouch_putSamples(HANDLE h,
const float *samples, ///< Pointer to sample buffer. const float *samples, ///< Pointer to sample buffer.
unsigned int numSamples ///< Number of sample frames in buffer. Notice unsigned int numSamples ///< Number of sample frames in buffer. Notice
///< that in case of multi-channel sound a single ///< that in case of multi-channel sound a single
@ -225,5 +225,16 @@ SOUNDTOUCHDLL_API void __cdecl bpm_putSamples_i16(HANDLE h,
/// \return Beats-per-minute rate, or zero if detection failed. /// \return Beats-per-minute rate, or zero if detection failed.
SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h); SOUNDTOUCHDLL_API float __cdecl bpm_getBpm(HANDLE h);
/// 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.
SOUNDTOUCHDLL_API int __cdecl bpm_getBeats(HANDLE h, float *pos, float *strength, int count);
#endif // _SoundTouchDLL_h_ #endif // _SoundTouchDLL_h_

View File

@ -51,8 +51,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,0,0 FILEVERSION 2,3,2,0
PRODUCTVERSION 2,0,0,0 PRODUCTVERSION 2,3,2,0
FILEFLAGSMASK 0x17L FILEFLAGSMASK 0x17L
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -69,12 +69,12 @@ BEGIN
BEGIN BEGIN
VALUE "Comments", "SoundTouch Library licensed for 3rd party applications subject to LGPL license v2.1. Visit http://www.surina.net/soundtouch for more information about the SoundTouch library." VALUE "Comments", "SoundTouch Library licensed for 3rd party applications subject to LGPL license v2.1. Visit http://www.surina.net/soundtouch for more information about the SoundTouch library."
VALUE "FileDescription", "SoundTouch Dynamic Link Library" VALUE "FileDescription", "SoundTouch Dynamic Link Library"
VALUE "FileVersion", "2.0.0.0" VALUE "FileVersion", "2.3.3.0"
VALUE "InternalName", "SoundTouch" VALUE "InternalName", "SoundTouch"
VALUE "LegalCopyright", "Copyright (C) Olli Parviainen 2017" VALUE "LegalCopyright", "Copyright (C) Olli Parviainen 2024"
VALUE "OriginalFilename", "SoundTouch.dll" VALUE "OriginalFilename", "SoundTouch.dll"
VALUE "ProductName", " SoundTouch Dynamic Link Library" VALUE "ProductName", " SoundTouch Dynamic Link Library"
VALUE "ProductVersion", "2.0.0.0" VALUE "ProductVersion", "2.3.3.0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

View File

@ -21,28 +21,28 @@
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{164DE61D-6391-4265-8273-30740117D356}</ProjectGuid> <ProjectGuid>{164DE61D-6391-4265-8273-30740117D356}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v142</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
@ -95,7 +95,8 @@
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild> <MinimalRebuild>
</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader /> <PrecompiledHeader />
@ -106,6 +107,7 @@
<ObjectFileName>$(OutDir)</ObjectFileName> <ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@ -134,7 +136,8 @@ copy $(OutDir)$(TargetName).lib ..\..\lib
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild> <MinimalRebuild>
</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<PrecompiledHeader /> <PrecompiledHeader />
@ -144,6 +147,7 @@ copy $(OutDir)$(TargetName).lib ..\..\lib
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation> <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName> <ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@ -182,6 +186,8 @@ copy $(OutDir)$(TargetName).lib ..\..\lib
<ObjectFileName>$(OutDir)</ObjectFileName> <ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<MinimalRebuild />
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@ -223,6 +229,8 @@ copy $(OutDir)$(TargetName).lib ..\..\lib
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation> <AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
<ObjectFileName>$(OutDir)</ObjectFileName> <ObjectFileName>$(OutDir)</ObjectFileName>
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName> <ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
<MinimalRebuild />
<FloatingPointModel>Fast</FloatingPointModel>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile> <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>

View File

@ -1,5 +1,8 @@
#!/bin/bash #!/bin/bash
# #
# This script is deprecated. Don't use this, the makefile can now compile
# the dynamic-link library 'libSoundTouchDLL.so' automatically.
#
# This script compiles SoundTouch dynamic-link library for GNU environment # This script compiles SoundTouch dynamic-link library for GNU environment
# with wrapper functions that are easier to import to Java / Mono / etc # with wrapper functions that are easier to import to Java / Mono / etc
# #
@ -16,7 +19,11 @@ if [[ $arch == *"86"* ]]; then
fi fi
fi fi
echo "*************************************************************************"
echo "NOTE: Rather use the makefile that can now build the dynamic-link library"
echo "*************************************************************************"
echo ""
echo "Building SoundTouchDLL for $arch with flags:$flags" echo "Building SoundTouchDLL for $arch with flags:$flags"
g++ -O3 -shared $flags -DDLL_EXPORTS -fvisibility=hidden -I../../include \ g++ -O3 -ffast-math -shared $flags -DDLL_EXPORTS -fvisibility=hidden -I../../include \
-I../SoundTouch -o SoundTouchDll.so SoundTouchDLL.cpp ../SoundTouch/*.cpp -I../SoundTouch -o SoundTouchDll.so SoundTouchDLL.cpp ../SoundTouch/*.cpp

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8"?>
<configuration> <configuration>
<startup> <startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1"/>
</startup> </startup>
</configuration> </configuration>

View File

@ -12,7 +12,7 @@ using System.Windows;
[assembly: AssemblyConfiguration("")] [assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("csharp-example")] [assembly: AssemblyProduct("csharp-example")]
[assembly: AssemblyCopyright("Copyright Olli Parviainen © 2017")] [assembly: AssemblyCopyright("Copyright © Olli Parviainen")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]

View File

@ -8,8 +8,8 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace csharp_example.Properties namespace csharp_example.Properties {
{ using System;
/// <summary> /// <summary>
@ -19,31 +19,26 @@ namespace csharp_example.Properties
// class via a tool like ResGen or Visual Studio. // class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen // To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project. // with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources internal class Resources {
{
private static global::System.Resources.ResourceManager resourceMan; private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture; private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() internal Resources() {
{
} }
/// <summary> /// <summary>
/// Returns the cached ResourceManager instance used by this class. /// Returns the cached ResourceManager instance used by this class.
/// </summary> /// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager internal static global::System.Resources.ResourceManager ResourceManager {
{ get {
get if (object.ReferenceEquals(resourceMan, null)) {
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("csharp_example.Properties.Resources", typeof(Resources).Assembly); global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("csharp_example.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp; resourceMan = temp;
} }
@ -56,14 +51,11 @@ namespace csharp_example.Properties
/// resource lookups using this strongly typed resource class. /// resource lookups using this strongly typed resource class.
/// </summary> /// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture internal static global::System.Globalization.CultureInfo Culture {
{ get {
get
{
return resourceCulture; return resourceCulture;
} }
set set {
{
resourceCulture = value; resourceCulture = value;
} }
} }

View File

@ -8,21 +8,17 @@
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
namespace csharp_example.Properties namespace csharp_example.Properties {
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default public static Settings Default {
{ get {
get
{
return defaultInstance; return defaultInstance;
} }
} }

Binary file not shown.

View File

@ -9,14 +9,15 @@
<AppDesignerFolder>Properties</AppDesignerFolder> <AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>csharp_example</RootNamespace> <RootNamespace>csharp_example</RootNamespace>
<AssemblyName>csharp-example</AssemblyName> <AssemblyName>csharp-example</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> <TargetFrameworkVersion>v4.8.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment> <FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>false</Optimize>
@ -24,6 +25,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>