mirror of
https://github.com/azahar-emu/soundtouch
synced 2025-11-13 10:30:19 +01:00
Compare commits
262 Commits
soundtouch
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ef8458d85 | ||
|
|
16956b94b9 | ||
|
|
5dede763ff | ||
|
|
e31e1715fb | ||
|
|
bc2a2f73ff | ||
|
|
d3f7e2530b | ||
|
|
ddf28667c9 | ||
|
|
7f35604eda | ||
|
|
4ae091f54f | ||
|
|
e83424d592 | ||
|
|
0095a3d933 | ||
|
|
077e73422f | ||
|
|
f0ef4cd853 | ||
|
|
7dce7268cd | ||
|
|
63002027de | ||
|
|
290b0b13e2 | ||
|
|
2a24e3b454 | ||
|
|
02c22eceea | ||
|
|
ba1cb7727e | ||
|
|
17b63eeb3e | ||
|
|
2e83c770b0 | ||
|
|
5e624fff73 | ||
|
|
1c6a90804b | ||
|
|
f921e5b586 | ||
|
|
6872a2b6d0 | ||
|
|
d90844f67d | ||
|
|
375e6ccfe9 | ||
|
|
74514f5597 | ||
|
|
3781ff5d55 | ||
|
|
e56457728c | ||
|
|
c4c922c7b9 | ||
|
|
28df544c48 | ||
|
|
dd2252e9af | ||
|
|
55bd933dba | ||
|
|
8726394399 | ||
|
|
170349af69 | ||
|
|
b477936716 | ||
|
|
cc24adfc6d | ||
|
|
808bf021e6 | ||
|
|
63db6bf344 | ||
|
|
05d2835f65 | ||
|
|
1eda9c0b01 | ||
|
|
230ae2f9a9 | ||
|
|
a88c82d0ab | ||
|
|
82cb3f99bb | ||
|
|
4070166f4a | ||
|
|
4bcbb3556f | ||
|
|
29fba832a7 | ||
|
|
9e798c0f7f | ||
|
|
ddc351bfb6 | ||
|
|
774257ab5f | ||
|
|
eaa9090f65 | ||
|
|
17925302ae | ||
|
|
8562287944 | ||
|
|
9f14bd8b6e | ||
|
|
64760eb34e | ||
|
|
bb0434dd6e | ||
|
|
1a07a649e4 | ||
|
|
bdafd3b08c | ||
|
|
ab2b8ca91f | ||
|
|
9fedba866e | ||
|
|
0afe414a18 | ||
|
|
b9092339f5 | ||
|
|
85c03d6063 | ||
|
|
7ede48e436 | ||
|
|
8a9d4acb12 | ||
|
|
d063c0d9f9 | ||
|
|
b9afe0ac11 | ||
|
|
572d12c3e9 | ||
|
|
e016ebfcd5 | ||
|
|
4fd8e1acb9 | ||
|
|
afb0e4a73f | ||
|
|
77cbbb2227 | ||
|
|
e1f315f535 | ||
|
|
82e9ebd075 | ||
|
|
fd8e4c6835 | ||
|
|
d7b7a2f3a1 | ||
|
|
7df5617a4b | ||
|
|
2e606befef | ||
|
|
268a91494b | ||
|
|
2adf2ae71d | ||
|
|
9f72a8aa6b | ||
|
|
d11a3adb2d | ||
|
|
847edf4548 | ||
|
|
3148382fa8 | ||
|
|
c65afe49f6 | ||
|
|
28b32c0fbb | ||
|
|
bd2149daf6 | ||
|
|
776443f914 | ||
|
|
65caafdc5f | ||
|
|
6dce1068d9 | ||
|
|
eb6d970970 | ||
|
|
f974b28682 | ||
|
|
220eb7857c | ||
|
|
dae91683bc | ||
|
|
fa223609d2 | ||
|
|
3617bd166b | ||
|
|
d8d86e1a92 | ||
|
|
e0e00878fc | ||
|
|
17a63e99d5 | ||
|
|
6533514372 | ||
|
|
81b0d74727 | ||
|
|
5e76cf2f6d | ||
|
|
f38cfa6850 | ||
|
|
762f56024b | ||
|
|
1d42d899ab | ||
|
|
bf3cec0244 | ||
|
|
a911a1e986 | ||
|
|
3e74d1d18f | ||
|
|
f382149086 | ||
|
|
308c3484f6 | ||
|
|
3d7bf376fd | ||
|
|
1e56c65ea5 | ||
|
|
fe15975a21 | ||
|
|
a046b6971d | ||
|
|
c4f1602474 | ||
|
|
244fbeac24 | ||
|
|
12cb25ed7b | ||
|
|
fb3ea4d9f0 | ||
|
|
2b2585bc74 | ||
|
|
eef1220d72 | ||
|
|
9205fc971e | ||
|
|
b9659b64c6 | ||
|
|
7f594f8b7d | ||
|
|
6d700259b9 | ||
|
|
dad1d566c4 | ||
|
|
41a2cd3e6b | ||
|
|
09e04252dd | ||
|
|
59129fa33d | ||
|
|
a1c400eb2c | ||
|
|
12eaa21e14 | ||
|
|
bdbe1bf551 | ||
|
|
1d63bbf8e1 | ||
|
|
79cbdb1140 | ||
|
|
3ea4f5c7b3 | ||
|
|
68df82bd5b | ||
|
|
00241ebba1 | ||
|
|
1e9ec6f54b | ||
|
|
50348640f7 | ||
|
|
1e9c3bce2d | ||
|
|
5e3ca30225 | ||
|
|
46531e5b92 | ||
|
|
e024068905 | ||
|
|
c38f0506da | ||
|
|
cca9271e98 | ||
|
|
9e02d9b04f | ||
|
|
1ab7e7ccd0 | ||
|
|
4aaac92874 | ||
|
|
107f2c5d20 | ||
|
|
4b6060adfe | ||
|
|
1f7f681f9d | ||
|
|
81cf74cf4c | ||
|
|
5c168a55ff | ||
|
|
f71db0d2c3 | ||
|
|
0093b63141 | ||
|
|
6ee56b1c17 | ||
|
|
6b6c36d3e1 | ||
|
|
8f6f91f9b3 | ||
|
|
007481d711 | ||
|
|
47f74e83ef | ||
|
|
c4154b063f | ||
|
|
3f2ad229bb | ||
|
|
3feea728d5 | ||
|
|
e765f8146f | ||
|
|
669ab8c974 | ||
|
|
7b097533a9 | ||
|
|
30b017d112 | ||
|
|
20e4bf0b04 | ||
|
|
ec9ba968f5 | ||
|
|
407f516e0d | ||
|
|
05a3403137 | ||
|
|
80281c8e1b | ||
|
|
5f8720dae6 | ||
|
|
6e8d58cbcc | ||
|
|
b56859a3fe | ||
|
|
bbeab39f0a | ||
|
|
cd74dccaf1 | ||
|
|
bd0a806285 | ||
|
|
59e6726118 | ||
|
|
92bfdd1e8d | ||
|
|
c31fca9c9f | ||
|
|
6f82bdebdb | ||
|
|
5d9bc2fdf3 | ||
|
|
1049304b5d | ||
|
|
e302cd7123 | ||
|
|
753848865d | ||
|
|
ac03757ec8 | ||
|
|
62d63e7881 | ||
|
|
f574c92dcf | ||
|
|
8023db738f | ||
|
|
882f248a0c | ||
|
|
9287800b65 | ||
|
|
e1c7cffbcd | ||
|
|
81cb7a3406 | ||
|
|
089edd12f4 | ||
|
|
fe44590ab6 | ||
|
|
5f84fe3eb7 | ||
|
|
18a230a54c | ||
|
|
04b96e6b52 | ||
|
|
8c06711f86 | ||
|
|
db04025351 | ||
|
|
c9507ff7f1 | ||
|
|
da748228b9 | ||
|
|
2e8250d03a | ||
|
|
1a3c1cd50e | ||
|
|
2f2b3d756a | ||
|
|
2cbd68c32b | ||
|
|
9ff52beba7 | ||
|
|
55dcf4a956 | ||
|
|
76f76ffb84 | ||
|
|
83e46b5644 | ||
|
|
5ad8994798 | ||
|
|
4bc115df86 | ||
|
|
d44723ea57 | ||
|
|
92973bc18e | ||
|
|
1040bd1d28 | ||
|
|
708f1d7e0b | ||
|
|
cbfec4188e | ||
|
|
32dcebc1d7 | ||
|
|
c36e2fa958 | ||
|
|
3e9cc3fd4b | ||
|
|
123e3299fe | ||
|
|
6935032a52 | ||
|
|
d7d0a5c0f9 | ||
|
|
126d1ac41d | ||
|
|
bfc89b45a9 | ||
|
|
5100cefbb0 | ||
|
|
0715880b1f | ||
|
|
099a6240eb | ||
|
|
1da2f8e700 | ||
|
|
e23bd6d093 | ||
|
|
f68f8e9e09 | ||
|
|
01ba661351 | ||
|
|
9406cf5b28 | ||
|
|
b2ff6711d0 | ||
|
|
33638a2243 | ||
|
|
4da3b1eaf9 | ||
|
|
2d91306ac0 | ||
|
|
1f6391a9ca | ||
|
|
afdfb293f6 | ||
|
|
746a90d610 | ||
|
|
a61c28e36a | ||
|
|
026ebe3841 | ||
|
|
f16b062219 | ||
|
|
a09135884a | ||
|
|
abfeb3fcc9 | ||
|
|
8174f6bc10 | ||
|
|
510a94e990 | ||
|
|
510ac08657 | ||
|
|
70d7518295 | ||
|
|
55aa6f15e9 | ||
|
|
8c65661b91 | ||
|
|
9bb265e3cd | ||
|
|
c6bf1c7585 | ||
|
|
7a0a940953 | ||
|
|
4d8825ef6d | ||
|
|
7dea63e0e1 | ||
|
|
46a7dc3c39 | ||
|
|
9b902ef3b7 | ||
|
|
c3f4ff9532 | ||
|
|
91305a5806 | ||
|
|
fbc2ace440 |
55
.gitignore
vendored
Normal file
55
.gitignore
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
bin
|
||||||
|
lib
|
||||||
|
|
||||||
|
# Win build files
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# GNU build files
|
||||||
|
*.o
|
||||||
|
*.so*
|
||||||
|
*.lo
|
||||||
|
*.P*
|
||||||
|
*.la*
|
||||||
|
*.a
|
||||||
|
*.pc
|
||||||
|
*config*
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
|
.libs
|
||||||
|
aclocal.m4
|
||||||
|
autom4te.cache
|
||||||
|
stamp-*
|
||||||
|
libtool
|
||||||
|
soundstretch
|
||||||
|
|
||||||
|
# Files generated by MSVC
|
||||||
|
*.bsc
|
||||||
|
*.suo
|
||||||
|
*.sdf
|
||||||
|
*.filters
|
||||||
|
*.user
|
||||||
|
source/SoundTouch/Win32/
|
||||||
|
source/SoundTouch/x64/
|
||||||
|
source/SoundStretch/Win32/
|
||||||
|
source/SoundStretch/x64/
|
||||||
|
source/SoundTouchDll/Win32/
|
||||||
|
source/SoundTouchDll/x64/
|
||||||
|
source/SoundTouchDll/DllTest/Win32/
|
||||||
|
source/SoundTouchDll/DllTest/x64/
|
||||||
|
.vs
|
||||||
|
|
||||||
|
# Files generated by Android Studio
|
||||||
|
source/android-lib/.gradle
|
||||||
|
source/android-lib/.idea
|
||||||
|
**/*.iml
|
||||||
|
source/android-lib/local.properties
|
||||||
|
source/android-lib/build
|
||||||
|
source/android-lib/.externalNativeBuild
|
||||||
|
|
||||||
|
# CMake build directory
|
||||||
|
build*
|
||||||
|
CMakeFiles
|
||||||
|
CMakeCache.txt
|
||||||
|
*.cmake
|
||||||
32
.vscode/tasks.json
vendored
Normal file
32
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
// This is build task definition file for MS VisualStudio Code.
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "echo",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "echo Hello"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "configure",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "./bootstrap && ./configure"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make -j4",
|
||||||
|
"problemMatcher": [
|
||||||
|
"$gcc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "clean",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "make clean",
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
191
CMakeLists.txt
Normal file
191
CMakeLists.txt
Normal 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
|
||||||
|
)
|
||||||
@ -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".
|
||||||
|
|
||||||
@ -455,4 +455,4 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
|||||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
DAMAGES.
|
DAMAGES.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
13
Makefile.am
13
Makefile.am
@ -1,20 +1,16 @@
|
|||||||
## Process this file with automake to create Makefile.in
|
## Process this file with automake to create Makefile.in
|
||||||
##
|
##
|
||||||
## $Id$
|
|
||||||
##
|
|
||||||
## Copyright (C) 2003 - David W. Durham
|
|
||||||
##
|
|
||||||
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
## 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
|
## 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
|
## 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
|
## Foundation; either version 2 of the License, or (at your option) any later
|
||||||
## version.
|
## version.
|
||||||
##
|
##
|
||||||
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
## 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
|
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
## 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
|
## 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
|
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
## Place - Suite 330, Boston, MA 02111-1307, USA
|
## Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
@ -26,9 +22,8 @@ include $(top_srcdir)/config/am_include.mk
|
|||||||
## subdirectories Start at frontend_fox/Makefile.am to see how everything works.
|
## subdirectories Start at frontend_fox/Makefile.am to see how everything works.
|
||||||
SUBDIRS=include source
|
SUBDIRS=include source
|
||||||
|
|
||||||
|
|
||||||
# list files that are documentation to be packaged in a release tarball and installed
|
# list files that are documentation to be packaged in a release tarball and installed
|
||||||
pkgdoc_DATA=COPYING.TXT README.html
|
dist_doc_DATA=COPYING.TXT README.html
|
||||||
|
|
||||||
# extra data files that are to be pacakged in a release tarball and installed into the data directory
|
# extra data files that are to be pacakged in a release tarball and installed into the data directory
|
||||||
#pkgdata_DATA=
|
#pkgdata_DATA=
|
||||||
|
|||||||
1763
README.html
1763
README.html
File diff suppressed because it is too large
Load Diff
14
SoundTouchConfig.cmake.in
Normal file
14
SoundTouchConfig.cmake.in
Normal 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()
|
||||||
@ -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%
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# $Id$
|
|
||||||
|
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
|
unset ACLOCAL
|
||||||
|
|
||||||
if [ "$1" = "--clean" ]
|
if [ "$1" = "--clean" ]
|
||||||
then
|
then
|
||||||
if [ -a Makefile ]
|
if [ -a Makefile ]
|
||||||
@ -10,15 +10,12 @@ then
|
|||||||
elif [ -a configure ]
|
elif [ -a configure ]
|
||||||
then
|
then
|
||||||
configure && $0 --clean
|
configure && $0 --clean
|
||||||
else
|
else
|
||||||
bootstrap && configure && $0 --clean
|
bootstrap && configure && $0 --clean
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf configure libtool aclocal.m4 `find . -name Makefile.in` autom4te*.cache config/config.guess config/config.h.in config/config.sub config/depcomp config/install-sh config/ltmain.sh config/missing config/mkinstalldirs config/stamp-h config/stamp-h.in
|
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
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
## vim:tw=78
|
## vim:tw=78
|
||||||
## Process this file with automake to create Makefile.in
|
## Process this file with automake to create Makefile.in
|
||||||
##
|
##
|
||||||
## $Id$
|
|
||||||
##
|
|
||||||
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
## 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
|
## SoundTouch is free software; you can redistribute it and/or modify it under the
|
||||||
@ -19,16 +17,10 @@
|
|||||||
## Place - Suite 330, Boston, MA 02111-1307, USA
|
## Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
|
||||||
## These are common definitions used in all Makefiles
|
## These are common definitions used in all Makefiles
|
||||||
## It is actually included when a makefile.am is coverted to Makefile.in
|
## It is actually included when a makefile.am is converted to Makefile.in
|
||||||
## by automake, so it's ok to have @MACROS@ that will be set by configure
|
## by automake, so it's ok to have @MACROS@ that will be set by configure
|
||||||
|
|
||||||
|
AM_CPPFLAGS=-I$(top_srcdir)/include
|
||||||
## INCLUDES is automatically added to CXXFLAGS at compile time. The
|
|
||||||
## $(top_srcdir) macro is set by configure. It's important to use $(top_srcdir)
|
|
||||||
## in case a user decides to build in a separate directory from the base package
|
|
||||||
## directory. Using absolute, or relative paths is a bad idea.
|
|
||||||
INCLUDES=-I$(top_srcdir)/include
|
|
||||||
|
|
||||||
|
|
||||||
# doc directory
|
# doc directory
|
||||||
pkgdocdir=$(prefix)/doc/@PACKAGE@
|
pkgdocdir=$(prefix)/doc/@PACKAGE@
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
Starting from SoundTouch 1.6.0, the "configure" file is removed from the source code package due to autoconf/automake version conflicts.
|
|
||||||
|
|
||||||
Instead, generate the "configure" file using local tools by invoking "./bootstrap" script, then configure & compile as usual.
|
|
||||||
156
configure.ac
156
configure.ac
@ -1,36 +1,41 @@
|
|||||||
dnl SoundTouch configure.ac, by David W. Durham
|
|
||||||
dnl
|
|
||||||
dnl $Id$
|
|
||||||
dnl
|
|
||||||
dnl This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
dnl This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
||||||
dnl
|
dnl
|
||||||
dnl SoundTouch is free software; you can redistribute it and/or modify it under the
|
dnl SoundTouch is free software; you can redistribute it and/or modify it under the
|
||||||
dnl terms of the GNU General Public License as published by the Free Software
|
dnl terms of the GNU General Public License as published by the Free Software
|
||||||
dnl Foundation; either version 2 of the License, or (at your option) any later
|
dnl Foundation; either version 2 of the License, or (at your option) any later
|
||||||
dnl version.
|
dnl version.
|
||||||
dnl
|
dnl
|
||||||
dnl SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
dnl SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
dnl FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
dnl FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
dnl details.
|
dnl details.
|
||||||
dnl
|
dnl
|
||||||
dnl You should have received a copy of the GNU General Public License along with
|
dnl You should have received a copy of the GNU General Public License along with
|
||||||
dnl this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
dnl 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, 1.7.0, [http://www.surina.net/soundtouch])
|
AC_INIT([SoundTouch],[2.3.2],[http://www.surina.net/soundtouch])
|
||||||
|
dnl Default to libSoundTouch.so.$LIB_SONAME.0.0
|
||||||
|
LIB_SONAME=1
|
||||||
|
AC_SUBST(LIB_SONAME)
|
||||||
|
|
||||||
AC_CONFIG_AUX_DIR(config)
|
AC_CONFIG_AUX_DIR(config)
|
||||||
AM_CONFIG_HEADER([include/soundtouch_config.h])
|
AC_CONFIG_MACRO_DIR([config/m4])
|
||||||
|
AC_CONFIG_HEADERS([config.h include/soundtouch_config.h])
|
||||||
AM_INIT_AUTOMAKE
|
AM_INIT_AUTOMAKE
|
||||||
#AC_DISABLE_SHARED dnl This makes libtool only build static libs
|
AM_SILENT_RULES([yes])
|
||||||
|
#AC_DISABLE_SHARED dnl This makes libtool only build static libs
|
||||||
AC_DISABLE_STATIC dnl This makes libtool only build shared libs
|
AC_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')"
|
||||||
|
AR_FLAGS='cr'
|
||||||
|
|
||||||
|
|
||||||
dnl ############################################################################
|
dnl ############################################################################
|
||||||
@ -45,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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -53,17 +58,18 @@ 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
|
||||||
|
AC_MSG_WARN([The cpuid.h file was not found therefore the x86 optimizations will be disabled.])
|
||||||
|
AC_MSG_WARN([If using a x86 architecture and optimizations are desired then please install gcc (>= 4.3).])
|
||||||
|
AC_MSG_WARN([If using a non-x86 architecture then this is expected and can be ignored.])
|
||||||
|
fi
|
||||||
|
|
||||||
if test "x$ac_cv_header_cpuid_h" = "xno"; then
|
|
||||||
AC_MSG_WARN([The cpuid.h file was not found therefore the x86 optimizations will be disabled.])
|
|
||||||
AC_MSG_WARN([If using a x86 architecture and optimizations are desired then please install gcc (>= 4.3).])
|
|
||||||
AC_MSG_WARN([If using a non-x86 architecture then this is expected and can be ignored.])
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
dnl ############################################################################
|
dnl ############################################################################
|
||||||
dnl # Checks for typedefs, structures, and compiler characteristics $
|
dnl # Checks for typedefs, structures, and compiler characteristics $
|
||||||
@ -75,26 +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=yes]])],,
|
|
||||||
[enable_integer_samples=no])
|
[enable_integer_samples=no])
|
||||||
|
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(openmp,
|
||||||
|
[AS_HELP_STRING([--enable-openmp],[use parallel multicore calculation through OpenMP [default=no]])],,
|
||||||
|
[enable_openmp=no])
|
||||||
|
|
||||||
# Let the user enable/disable the x86 optimizations.
|
# 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])
|
||||||
@ -102,16 +116,23 @@ 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
|
||||||
|
echo "****** openmp optimizations enabled ******"
|
||||||
|
AM_CXXFLAGS="-fopenmp $AM_CXXFLAGS"
|
||||||
|
else
|
||||||
|
echo "****** openmp optimizations disabled ******"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
# Check if optimizations are supported in the system at build time.
|
# Check if optimizations are supported in the system at build time.
|
||||||
if test "x$enable_x86_optimizations" = "xyes" -a "x$ac_cv_header_cpuid_h" = "xyes"; then
|
if test "x$enable_x86_optimizations" = "xyes" -a "x$ac_cv_header_cpuid_h" = "xyes"; then
|
||||||
echo "****** x86 optimizations enabled ******"
|
echo "****** x86 optimizations enabled ******"
|
||||||
|
|
||||||
original_saved_CXXFLAGS=$CXXFLAGS
|
original_saved_CXXFLAGS=$CXXFLAGS
|
||||||
have_mmx_intrinsics=no
|
have_mmx_intrinsics=no
|
||||||
OPT_CXXFLAGS="-mmmx -Winline"
|
CXXFLAGS="-mmmx -Winline $CXXFLAGS"
|
||||||
CXXFLAGS="$OPT_CXXFLAGS $CXXFLAGS"
|
|
||||||
|
|
||||||
# Check if the user can compile MMX code using intrinsics.
|
# Check if the user can compile MMX code using intrinsics.
|
||||||
# GCC supports MMX intrinsics since version 3.3
|
# GCC supports MMX intrinsics since version 3.3
|
||||||
@ -137,14 +158,15 @@ if test "x$enable_x86_optimizations" = "xyes" -a "x$ac_cv_header_cpuid_h" = "xye
|
|||||||
echo "****** No MMX support found ******"
|
echo "****** No MMX support found ******"
|
||||||
if test "x$enable_integer_samples" = "xyes"; then
|
if test "x$enable_integer_samples" = "xyes"; then
|
||||||
echo "****** Disabling optimizations. Using integer samples with no MMX support ******"
|
echo "****** Disabling optimizations. Using integer samples with no MMX support ******"
|
||||||
AC_DEFINE([SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS],[1],[Do not use x86 optimizations])
|
CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# SSE support
|
||||||
|
original_saved_CXXFLAGS=$CXXFLAGS
|
||||||
have_sse_intrinsics=no
|
have_sse_intrinsics=no
|
||||||
OPT_CXXFLAGS="-msse -Winline"
|
CXXFLAGS="-msse -Winline $CXXFLAGS"
|
||||||
CXXFLAGS="$OPT_CXXFLAGS $CXXFLAGS"
|
|
||||||
|
|
||||||
# Check if the user can compile SSE code using intrinsics.
|
# Check if the user can compile SSE code using intrinsics.
|
||||||
# GCC supports SSE intrinsics since version 3.3
|
# GCC supports SSE intrinsics since version 3.3
|
||||||
@ -170,16 +192,69 @@ if test "x$enable_x86_optimizations" = "xyes" -a "x$ac_cv_header_cpuid_h" = "xye
|
|||||||
echo "****** No SSE support found ******"
|
echo "****** No SSE support found ******"
|
||||||
if test "x$enable_integer_samples" != "xyes"; then
|
if test "x$enable_integer_samples" != "xyes"; then
|
||||||
echo "****** Disabling optimizations. Using float samples with no SSE support ******"
|
echo "****** Disabling optimizations. Using float samples with no SSE support ******"
|
||||||
AC_DEFINE([SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS],[1],[Do not use x86 optimizations])
|
CPPFLAGS="-DSOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS $CPPFLAGS"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
else
|
else
|
||||||
# Disable optimizations in SSTypes.h since the user requested it.
|
# Disable optimizations in SSTypes.h since the user requested it.
|
||||||
echo "****** x86 optimizations disabled ******"
|
echo "****** x86 optimizations disabled ******"
|
||||||
AC_DEFINE([SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS],[1],[Do not use x86 optimizations])
|
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
|
||||||
|
AC_SUBST([AM_CXXFLAGS], [$AM_CXXFLAGS])
|
||||||
|
|
||||||
|
# Empty default CXXFLAGS so user can set them if desirable
|
||||||
|
#AC_SUBST([CXXFLAGS], [ ])
|
||||||
|
|
||||||
|
|
||||||
# SSTypes.h by default enables optimizations. Those already got disabled if
|
# SSTypes.h by default enables optimizations. Those already got disabled if
|
||||||
# the user requested for it or if the system does not support them.
|
# the user requested for it or if the system does not support them.
|
||||||
#
|
#
|
||||||
@ -195,11 +270,9 @@ AM_CONDITIONAL([HAVE_SSE], [test "x$have_sse_intrinsics" = "xyes"])
|
|||||||
dnl ############################################################################
|
dnl ############################################################################
|
||||||
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]))
|
||||||
|
|
||||||
dnl add whatever functions you might want to check for here
|
dnl add whatever functions you might want to check for here
|
||||||
#AC_CHECK_FUNCS([floor ftruncate memmove memset mkdir modf pow realpath sqrt strchr strdup strerror strrchr strstr strtol])
|
#AC_CHECK_FUNCS([floor ftruncate memmove memset mkdir modf pow realpath sqrt strchr strdup strerror strrchr strstr strtol])
|
||||||
@ -229,11 +302,12 @@ AC_CONFIG_FILES([
|
|||||||
source/Makefile
|
source/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
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
# Helper script for building a source code release package
|
# Helper script for building a source code release package
|
||||||
# $Id$
|
|
||||||
|
|
||||||
rm -Rf soundtouch
|
rm -Rf soundtouch
|
||||||
rm soundtouch.zip
|
rm soundtouch.zip
|
||||||
|
|||||||
@ -1,164 +1,205 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Beats-per-minute (BPM) detection routine.
|
/// Beats-per-minute (BPM) detection routine.
|
||||||
///
|
///
|
||||||
/// The beat detection algorithm works as follows:
|
/// The beat detection algorithm works as follows:
|
||||||
/// - Use function 'inputSamples' to input a chunks of samples to the class for
|
/// - Use function 'inputSamples' to input a chunks of samples to the class for
|
||||||
/// analysis. It's a good idea to enter a large sound file or stream in smallish
|
/// analysis. It's a good idea to enter a large sound file or stream in smallish
|
||||||
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
|
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
|
||||||
/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden,
|
/// - Input sound data is decimated to approx 500 Hz to reduce calculation burden,
|
||||||
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
|
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
|
||||||
/// Simple averaging is used for anti-alias filtering because the resulting signal
|
/// Simple averaging is used for anti-alias filtering because the resulting signal
|
||||||
/// quality isn't of that high importance.
|
/// quality isn't of that high importance.
|
||||||
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
|
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
|
||||||
/// taking absolute value that's smoothed by sliding average. Signal levels that
|
/// taking absolute value that's smoothed by sliding average. Signal levels that
|
||||||
/// are below a couple of times the general RMS amplitude level are cut away to
|
/// are below a couple of times the general RMS amplitude level are cut away to
|
||||||
/// leave only notable peaks there.
|
/// leave only notable peaks there.
|
||||||
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
|
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
|
||||||
/// autocorrelation function of the enveloped signal.
|
/// autocorrelation function of the enveloped signal.
|
||||||
/// - After whole sound data file has been analyzed as above, the bpm level is
|
/// - After whole sound data file has been analyzed as above, the bpm level is
|
||||||
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
|
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
|
||||||
/// function, calculates it's precise location and converts this reading to bpm's.
|
/// function, calculates it's precise location and converts this reading to bpm's.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef _BPMDetect_H_
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define _BPMDetect_H_
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <vector>
|
||||||
//
|
#include "STTypes.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "FIFOSampleBuffer.h"
|
||||||
|
|
||||||
#ifndef _BPMDetect_H_
|
namespace soundtouch
|
||||||
#define _BPMDetect_H_
|
{
|
||||||
|
|
||||||
#include "STTypes.h"
|
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
|
||||||
#include "FIFOSampleBuffer.h"
|
#define MIN_BPM 45
|
||||||
|
|
||||||
namespace soundtouch
|
/// Maximum allowed BPM rate range. Used for calculating algorithm parametrs
|
||||||
{
|
#define MAX_BPM_RANGE 200
|
||||||
|
|
||||||
/// Minimum allowed BPM rate. Used to restrict accepted result above a reasonable limit.
|
/// Maximum allowed BPM rate range. Used to restrict accepted result below a reasonable limit.
|
||||||
#define MIN_BPM 29
|
#define MAX_BPM_VALID 190
|
||||||
|
|
||||||
/// Maximum allowed BPM rate. Used to restrict accepted result below a reasonable limit.
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
#define MAX_BPM 200
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
/// Class for calculating BPM rate for audio data.
|
float pos;
|
||||||
class BPMDetect
|
float strength;
|
||||||
{
|
} BEAT;
|
||||||
protected:
|
|
||||||
/// Auto-correlation accumulator bins.
|
|
||||||
float *xcorr;
|
class IIR2_filter
|
||||||
|
{
|
||||||
/// Amplitude envelope sliding average approximation level accumulator
|
double coeffs[5];
|
||||||
double envelopeAccu;
|
double prev[5];
|
||||||
|
|
||||||
/// RMS volume sliding average approximation level accumulator
|
public:
|
||||||
double RMSVolumeAccu;
|
IIR2_filter(const double *lpf_coeffs);
|
||||||
|
float update(float x);
|
||||||
/// Sample average counter.
|
};
|
||||||
int decimateCount;
|
|
||||||
|
|
||||||
/// Sample average accumulator for FIFO-like decimation.
|
/// Class for calculating BPM rate for audio data.
|
||||||
soundtouch::LONG_SAMPLETYPE decimateSum;
|
class BPMDetect
|
||||||
|
{
|
||||||
/// Decimate sound by this coefficient to reach approx. 500 Hz.
|
protected:
|
||||||
int decimateBy;
|
/// Auto-correlation accumulator bins.
|
||||||
|
float *xcorr;
|
||||||
/// Auto-correlation window length
|
|
||||||
int windowLen;
|
/// Sample average counter.
|
||||||
|
int decimateCount;
|
||||||
/// Number of channels (1 = mono, 2 = stereo)
|
|
||||||
int channels;
|
/// Sample average accumulator for FIFO-like decimation.
|
||||||
|
soundtouch::LONG_SAMPLETYPE decimateSum;
|
||||||
/// sample rate
|
|
||||||
int sampleRate;
|
/// Decimate sound by this coefficient to reach approx. 500 Hz.
|
||||||
|
int decimateBy;
|
||||||
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for
|
|
||||||
/// the first these many correlation bins.
|
/// Auto-correlation window length
|
||||||
int windowStart;
|
int windowLen;
|
||||||
|
|
||||||
/// FIFO-buffer for decimated processing samples.
|
/// Number of channels (1 = mono, 2 = stereo)
|
||||||
soundtouch::FIFOSampleBuffer *buffer;
|
int channels;
|
||||||
|
|
||||||
/// Updates auto-correlation function for given number of decimated samples that
|
/// sample rate
|
||||||
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
|
int sampleRate;
|
||||||
/// though).
|
|
||||||
void updateXCorr(int process_samples /// How many samples are processed.
|
/// Beginning of auto-correlation window: Autocorrelation isn't being updated for
|
||||||
);
|
/// the first these many correlation bins.
|
||||||
|
int windowStart;
|
||||||
/// Decimates samples to approx. 500 Hz.
|
|
||||||
///
|
/// window functions for data preconditioning
|
||||||
/// \return Number of output samples.
|
float *hamw;
|
||||||
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
|
float *hamw2;
|
||||||
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
|
|
||||||
int numsamples ///< Number of source samples.
|
// beat detection variables
|
||||||
);
|
int pos;
|
||||||
|
int peakPos;
|
||||||
/// Calculates amplitude envelope for the buffer of samples.
|
int beatcorr_ringbuffpos;
|
||||||
/// Result is output to 'samples'.
|
int init_scaler;
|
||||||
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
|
float peakVal;
|
||||||
int numsamples ///< Number of samples in buffer
|
float *beatcorr_ringbuff;
|
||||||
);
|
|
||||||
|
/// FIFO-buffer for decimated processing samples.
|
||||||
/// remove constant bias from xcorr data
|
soundtouch::FIFOSampleBuffer *buffer;
|
||||||
void removeBias();
|
|
||||||
|
/// Collection of detected beat positions
|
||||||
public:
|
//BeatCollection beats;
|
||||||
/// Constructor.
|
std::vector<BEAT> beats;
|
||||||
BPMDetect(int numChannels, ///< Number of channels in sample data.
|
|
||||||
int sampleRate ///< Sample rate in Hz.
|
// 2nd order low-pass-filter
|
||||||
);
|
IIR2_filter beat_lpf;
|
||||||
|
|
||||||
/// Destructor.
|
/// Updates auto-correlation function for given number of decimated samples that
|
||||||
virtual ~BPMDetect();
|
/// are read from the internal 'buffer' pipe (samples aren't removed from the pipe
|
||||||
|
/// though).
|
||||||
/// Inputs a block of samples for analyzing: Envelopes the samples and then
|
void updateXCorr(int process_samples /// How many samples are processed.
|
||||||
/// updates the autocorrelation estimation. When whole song data has been input
|
);
|
||||||
/// in smaller blocks using this function, read the resulting bpm with 'getBpm'
|
|
||||||
/// function.
|
/// Decimates samples to approx. 500 Hz.
|
||||||
///
|
///
|
||||||
/// Notice that data in 'samples' array can be disrupted in processing.
|
/// \return Number of output samples.
|
||||||
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
|
int decimate(soundtouch::SAMPLETYPE *dest, ///< Destination buffer
|
||||||
int numSamples ///< Number of samples in buffer
|
const soundtouch::SAMPLETYPE *src, ///< Source sample buffer
|
||||||
);
|
int numsamples ///< Number of source samples.
|
||||||
|
);
|
||||||
|
|
||||||
/// Analyzes the results and returns the BPM rate. Use this function to read result
|
/// Calculates amplitude envelope for the buffer of samples.
|
||||||
/// after whole song data has been input to the class by consecutive calls of
|
/// Result is output to 'samples'.
|
||||||
/// 'inputSamples' function.
|
void calcEnvelope(soundtouch::SAMPLETYPE *samples, ///< Pointer to input/output data buffer
|
||||||
///
|
int numsamples ///< Number of samples in buffer
|
||||||
/// \return Beats-per-minute rate, or zero if detection failed.
|
);
|
||||||
float getBpm();
|
|
||||||
};
|
/// remove constant bias from xcorr data
|
||||||
|
void removeBias();
|
||||||
}
|
|
||||||
|
// Detect individual beat positions
|
||||||
#endif // _BPMDetect_H_
|
void updateBeatPos(int process_samples);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Constructor.
|
||||||
|
BPMDetect(int numChannels, ///< Number of channels in sample data.
|
||||||
|
int sampleRate ///< Sample rate in Hz.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Destructor.
|
||||||
|
virtual ~BPMDetect();
|
||||||
|
|
||||||
|
/// Inputs a block of samples for analyzing: Envelopes the samples and then
|
||||||
|
/// updates the autocorrelation estimation. When whole song data has been input
|
||||||
|
/// in smaller blocks using this function, read the resulting bpm with 'getBpm'
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// Notice that data in 'samples' array can be disrupted in processing.
|
||||||
|
void inputSamples(const soundtouch::SAMPLETYPE *samples, ///< Pointer to input/working data buffer
|
||||||
|
int numSamples ///< Number of samples in buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Analyzes the results and returns the BPM rate. Use this function to read result
|
||||||
|
/// after whole song data has been input to the class by consecutive calls of
|
||||||
|
/// 'inputSamples' function.
|
||||||
|
///
|
||||||
|
/// \return Beats-per-minute rate, or zero if detection failed.
|
||||||
|
float getBpm();
|
||||||
|
|
||||||
|
/// Get beat position arrays. Note: The array includes also really low beat detection values
|
||||||
|
/// in absence of clear strong beats. Consumer may wish to filter low values away.
|
||||||
|
/// - "pos" receive array of beat positions
|
||||||
|
/// - "values" receive array of beat detection strengths
|
||||||
|
/// - max_num indicates max.size of "pos" and "values" array.
|
||||||
|
///
|
||||||
|
/// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
|
||||||
|
///
|
||||||
|
/// \return number of beats in the arrays.
|
||||||
|
int getBeats(float *pos, float *strength, int max_num);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // _BPMDetect_H_
|
||||||
|
|||||||
@ -1,178 +1,180 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// A buffer class for temporarily storaging sound samples, operates as a
|
/// A buffer class for temporarily storaging sound samples, operates as a
|
||||||
/// first-in-first-out pipe.
|
/// first-in-first-out pipe.
|
||||||
///
|
///
|
||||||
/// Samples are added to the end of the sample buffer with the 'putSamples'
|
/// Samples are added to the end of the sample buffer with the 'putSamples'
|
||||||
/// function, and are received from the beginning of the buffer by calling
|
/// function, and are received from the beginning of the buffer by calling
|
||||||
/// the 'receiveSamples' function. The class automatically removes the
|
/// the 'receiveSamples' function. The class automatically removes the
|
||||||
/// output samples from the buffer as well as grows the storage size
|
/// output samples from the buffer as well as grows the storage size
|
||||||
/// whenever necessary.
|
/// whenever necessary.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef FIFOSampleBuffer_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define FIFOSampleBuffer_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include "FIFOSamplePipe.h"
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
namespace soundtouch
|
||||||
|
{
|
||||||
#ifndef FIFOSampleBuffer_H
|
|
||||||
#define FIFOSampleBuffer_H
|
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
|
||||||
|
/// care of storage size adjustment and data moving during input/output operations.
|
||||||
#include "FIFOSamplePipe.h"
|
///
|
||||||
|
/// Notice that in case of stereo audio, one sample is considered to consist of
|
||||||
namespace soundtouch
|
/// both channel data.
|
||||||
{
|
class FIFOSampleBuffer : public FIFOSamplePipe
|
||||||
|
{
|
||||||
/// Sample buffer working in FIFO (first-in-first-out) principle. The class takes
|
private:
|
||||||
/// care of storage size adjustment and data moving during input/output operations.
|
/// Sample buffer.
|
||||||
///
|
SAMPLETYPE *buffer;
|
||||||
/// Notice that in case of stereo audio, one sample is considered to consist of
|
|
||||||
/// both channel data.
|
// Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
|
||||||
class FIFOSampleBuffer : public FIFOSamplePipe
|
// 16-byte aligned location of this buffer
|
||||||
{
|
SAMPLETYPE *bufferUnaligned;
|
||||||
private:
|
|
||||||
/// Sample buffer.
|
/// Sample buffer size in bytes
|
||||||
SAMPLETYPE *buffer;
|
uint sizeInBytes;
|
||||||
|
|
||||||
// Raw unaligned buffer memory. 'buffer' is made aligned by pointing it to first
|
/// How many samples are currently in buffer.
|
||||||
// 16-byte aligned location of this buffer
|
uint samplesInBuffer;
|
||||||
SAMPLETYPE *bufferUnaligned;
|
|
||||||
|
/// Channels, 1=mono, 2=stereo.
|
||||||
/// Sample buffer size in bytes
|
uint channels;
|
||||||
uint sizeInBytes;
|
|
||||||
|
/// Current position pointer to the buffer. This pointer is increased when samples are
|
||||||
/// How many samples are currently in buffer.
|
/// removed from the pipe so that it's necessary to actually rewind buffer (move data)
|
||||||
uint samplesInBuffer;
|
/// only new data when is put to the pipe.
|
||||||
|
uint bufferPos;
|
||||||
/// Channels, 1=mono, 2=stereo.
|
|
||||||
uint channels;
|
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
|
||||||
|
/// beginning of the buffer.
|
||||||
/// Current position pointer to the buffer. This pointer is increased when samples are
|
void rewind();
|
||||||
/// removed from the pipe so that it's necessary to actually rewind buffer (move data)
|
|
||||||
/// only new data when is put to the pipe.
|
/// Ensures that the buffer has capacity for at least this many samples.
|
||||||
uint bufferPos;
|
void ensureCapacity(uint capacityRequirement);
|
||||||
|
|
||||||
/// Rewind the buffer by moving data from position pointed by 'bufferPos' to real
|
/// Returns current capacity.
|
||||||
/// beginning of the buffer.
|
uint getCapacity() const;
|
||||||
void rewind();
|
|
||||||
|
public:
|
||||||
/// Ensures that the buffer has capacity for at least this many samples.
|
|
||||||
void ensureCapacity(uint capacityRequirement);
|
/// Constructor
|
||||||
|
FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
|
||||||
/// Returns current capacity.
|
///< Default is stereo.
|
||||||
uint getCapacity() const;
|
);
|
||||||
|
|
||||||
public:
|
/// destructor
|
||||||
|
~FIFOSampleBuffer() override;
|
||||||
/// Constructor
|
|
||||||
FIFOSampleBuffer(int numChannels = 2 ///< Number of channels, 1=mono, 2=stereo.
|
/// Returns a pointer to the beginning of the output samples.
|
||||||
///< Default is stereo.
|
/// This function is provided for accessing the output samples directly.
|
||||||
);
|
/// Please be careful for not to corrupt the book-keeping!
|
||||||
|
///
|
||||||
/// destructor
|
/// When using this function to output samples, also remember to 'remove' the
|
||||||
~FIFOSampleBuffer();
|
/// output samples from the buffer by calling the
|
||||||
|
/// 'receiveSamples(numSamples)' function
|
||||||
/// Returns a pointer to the beginning of the output samples.
|
virtual SAMPLETYPE *ptrBegin() override;
|
||||||
/// This function is provided for accessing the output samples directly.
|
|
||||||
/// Please be careful for not to corrupt the book-keeping!
|
/// 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
|
||||||
/// When using this function to output samples, also remember to 'remove' the
|
/// inserting new samples into the sample buffer directly. Please be careful
|
||||||
/// output samples from the buffer by calling the
|
/// not corrupt the book-keeping!
|
||||||
/// 'receiveSamples(numSamples)' function
|
///
|
||||||
virtual SAMPLETYPE *ptrBegin();
|
/// When using this function as means for inserting new samples, also remember
|
||||||
|
/// to increase the sample count afterwards, by calling the
|
||||||
/// Returns a pointer to the end of the used part of the sample buffer (i.e.
|
/// 'putSamples(numSamples)' function.
|
||||||
/// where the new samples are to be inserted). This function may be used for
|
SAMPLETYPE *ptrEnd(
|
||||||
/// inserting new samples into the sample buffer directly. Please be careful
|
uint slackCapacity ///< How much free capacity (in samples) there _at least_
|
||||||
/// not corrupt the book-keeping!
|
///< should be so that the caller can successfully insert the
|
||||||
///
|
///< desired samples to the buffer. If necessary, the function
|
||||||
/// When using this function as means for inserting new samples, also remember
|
///< grows the buffer size to comply with this requirement.
|
||||||
/// to increase the sample count afterwards, by calling the
|
);
|
||||||
/// 'putSamples(numSamples)' function.
|
|
||||||
SAMPLETYPE *ptrEnd(
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
||||||
uint slackCapacity ///< How much free capacity (in samples) there _at least_
|
/// the sample buffer.
|
||||||
///< should be so that the caller can succesfully insert the
|
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
|
||||||
///< desired samples to the buffer. If necessary, the function
|
uint numSamples ///< Number of samples to insert.
|
||||||
///< grows the buffer size to comply with this requirement.
|
) override;
|
||||||
);
|
|
||||||
|
/// Adjusts the book-keeping to increase number of samples in the buffer without
|
||||||
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
/// copying any actual samples.
|
||||||
/// the sample buffer.
|
///
|
||||||
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
|
/// This function is used to update the number of samples in the sample buffer
|
||||||
uint numSamples ///< Number of samples to insert.
|
/// when accessing the buffer directly with 'ptrEnd' function. Please be
|
||||||
);
|
/// careful though!
|
||||||
|
virtual void putSamples(uint numSamples ///< Number of samples been inserted.
|
||||||
/// Adjusts the book-keeping to increase number of samples in the buffer without
|
);
|
||||||
/// copying any actual samples.
|
|
||||||
///
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
/// This function is used to update the number of samples in the sample buffer
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
/// when accessing the buffer directly with 'ptrEnd' function. Please be
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
/// careful though!
|
///
|
||||||
virtual void putSamples(uint numSamples ///< Number of samples been inserted.
|
/// \return Number of samples returned.
|
||||||
);
|
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
||||||
|
uint maxSamples ///< How many samples to receive at max.
|
||||||
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
) override;
|
||||||
/// output buffer and removes them from the sample buffer. If there are less than
|
|
||||||
/// 'numsample' samples in the buffer, returns all that available.
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
///
|
/// sample buffer without copying them anywhere.
|
||||||
/// \return Number of samples returned.
|
///
|
||||||
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
uint maxSamples ///< How many samples to receive at max.
|
/// with 'ptrBegin' function.
|
||||||
);
|
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
||||||
|
) override;
|
||||||
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
|
||||||
/// sample buffer without copying them anywhere.
|
/// Returns number of samples currently available.
|
||||||
///
|
virtual uint numSamples() const override;
|
||||||
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
|
||||||
/// with 'ptrBegin' function.
|
/// Sets number of channels, 1 = mono, 2 = stereo.
|
||||||
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
void setChannels(int numChannels);
|
||||||
);
|
|
||||||
|
/// Get number of channels
|
||||||
/// Returns number of samples currently available.
|
int getChannels()
|
||||||
virtual uint numSamples() const;
|
{
|
||||||
|
return channels;
|
||||||
/// Sets number of channels, 1 = mono, 2 = stereo.
|
}
|
||||||
void setChannels(int numChannels);
|
|
||||||
|
/// 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 override;
|
||||||
virtual int isEmpty() const;
|
|
||||||
|
/// Clears all the samples.
|
||||||
/// Clears all the samples.
|
virtual void clear() override;
|
||||||
virtual void clear();
|
|
||||||
|
/// 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) override;
|
||||||
uint adjustAmountOfSamples(uint numSamples);
|
|
||||||
};
|
/// Add silence to end of buffer
|
||||||
|
void addSilent(uint nSamples);
|
||||||
}
|
};
|
||||||
|
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,234 +1,230 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
|
/// 'FIFOSamplePipe' : An abstract base class for classes that manipulate sound
|
||||||
/// samples by operating like a first-in-first-out pipe: New samples are fed
|
/// samples by operating like a first-in-first-out pipe: New samples are fed
|
||||||
/// into one end of the pipe with the 'putSamples' function, and the processed
|
/// into one end of the pipe with the 'putSamples' function, and the processed
|
||||||
/// samples are received from the other end with the 'receiveSamples' function.
|
/// samples are received from the other end with the 'receiveSamples' function.
|
||||||
///
|
///
|
||||||
/// 'FIFOProcessor' : A base class for classes the do signal processing with
|
/// 'FIFOProcessor' : A base class for classes the do signal processing with
|
||||||
/// the samples while operating like a first-in-first-out pipe. When samples
|
/// the samples while operating like a first-in-first-out pipe. When samples
|
||||||
/// are input with the 'putSamples' function, the class processes them
|
/// are input with the 'putSamples' function, the class processes them
|
||||||
/// and moves the processed samples to the given 'output' pipe object, which
|
/// and moves the processed samples to the given 'output' pipe object, which
|
||||||
/// may be either another processing stage, or a fifo sample buffer object.
|
/// may be either another processing stage, or a fifo sample buffer object.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef FIFOSamplePipe_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define FIFOSamplePipe_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <assert.h>
|
||||||
//
|
#include <stdlib.h>
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "STTypes.h"
|
||||||
|
|
||||||
#ifndef FIFOSamplePipe_H
|
namespace soundtouch
|
||||||
#define FIFOSamplePipe_H
|
{
|
||||||
|
|
||||||
#include <assert.h>
|
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
|
||||||
#include <stdlib.h>
|
class FIFOSamplePipe
|
||||||
#include "STTypes.h"
|
{
|
||||||
|
protected:
|
||||||
namespace soundtouch
|
|
||||||
{
|
bool verifyNumberOfChannels(int nChannels) const
|
||||||
|
{
|
||||||
/// Abstract base class for FIFO (first-in-first-out) sample processing classes.
|
if ((nChannels > 0) && (nChannels <= SOUNDTOUCH_MAX_CHANNELS))
|
||||||
class FIFOSamplePipe
|
{
|
||||||
{
|
return true;
|
||||||
public:
|
}
|
||||||
// virtual default destructor
|
ST_THROW_RT_ERROR("Error: Illegal number of channels");
|
||||||
virtual ~FIFOSamplePipe() {}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a pointer to the beginning of the output samples.
|
public:
|
||||||
/// This function is provided for accessing the output samples directly.
|
// virtual default destructor
|
||||||
/// Please be careful for not to corrupt the book-keeping!
|
virtual ~FIFOSamplePipe() {}
|
||||||
///
|
|
||||||
/// When using this function to output samples, also remember to 'remove' the
|
|
||||||
/// output samples from the buffer by calling the
|
/// Returns a pointer to the beginning of the output samples.
|
||||||
/// 'receiveSamples(numSamples)' function
|
/// This function is provided for accessing the output samples directly.
|
||||||
virtual SAMPLETYPE *ptrBegin() = 0;
|
/// Please be careful for not to corrupt the book-keeping!
|
||||||
|
///
|
||||||
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
/// When using this function to output samples, also remember to 'remove' the
|
||||||
/// the sample buffer.
|
/// output samples from the buffer by calling the
|
||||||
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
|
/// 'receiveSamples(numSamples)' function
|
||||||
uint numSamples ///< Number of samples to insert.
|
virtual SAMPLETYPE *ptrBegin() = 0;
|
||||||
) = 0;
|
|
||||||
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
||||||
|
/// the sample buffer.
|
||||||
// Moves samples from the 'other' pipe instance to this instance.
|
virtual void putSamples(const SAMPLETYPE *samples, ///< Pointer to samples.
|
||||||
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
|
uint numSamples ///< Number of samples to insert.
|
||||||
)
|
) = 0;
|
||||||
{
|
|
||||||
int oNumSamples = other.numSamples();
|
|
||||||
|
// Moves samples from the 'other' pipe instance to this instance.
|
||||||
putSamples(other.ptrBegin(), oNumSamples);
|
void moveSamples(FIFOSamplePipe &other ///< Other pipe instance where from the receive the data.
|
||||||
other.receiveSamples(oNumSamples);
|
)
|
||||||
};
|
{
|
||||||
|
const uint oNumSamples = other.numSamples();
|
||||||
/// 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
|
putSamples(other.ptrBegin(), oNumSamples);
|
||||||
/// 'numsample' samples in the buffer, returns all that available.
|
other.receiveSamples(oNumSamples);
|
||||||
///
|
}
|
||||||
/// \return Number of samples returned.
|
|
||||||
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
uint maxSamples ///< How many samples to receive at max.
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
) = 0;
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
|
///
|
||||||
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
/// \return Number of samples returned.
|
||||||
/// sample buffer without copying them anywhere.
|
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
||||||
///
|
uint maxSamples ///< How many samples to receive at max.
|
||||||
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
) = 0;
|
||||||
/// with 'ptrBegin' function.
|
|
||||||
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
) = 0;
|
/// sample buffer without copying them anywhere.
|
||||||
|
///
|
||||||
/// Returns number of samples currently available.
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
virtual uint numSamples() const = 0;
|
/// with 'ptrBegin' function.
|
||||||
|
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
||||||
// Returns nonzero if there aren't any samples available for outputting.
|
) = 0;
|
||||||
virtual int isEmpty() const = 0;
|
|
||||||
|
/// Returns number of samples currently available.
|
||||||
/// Clears all the samples.
|
virtual uint numSamples() const = 0;
|
||||||
virtual void clear() = 0;
|
|
||||||
|
// Returns nonzero if there aren't any samples available for outputting.
|
||||||
/// allow trimming (downwards) amount of samples in pipeline.
|
virtual int isEmpty() const = 0;
|
||||||
/// Returns adjusted amount of samples
|
|
||||||
virtual uint adjustAmountOfSamples(uint numSamples) = 0;
|
/// Clears all the samples.
|
||||||
|
virtual void clear() = 0;
|
||||||
};
|
|
||||||
|
/// allow trimming (downwards) amount of samples in pipeline.
|
||||||
|
/// Returns adjusted amount of samples
|
||||||
|
virtual uint adjustAmountOfSamples(uint numSamples) = 0;
|
||||||
/// Base-class for sound processing routines working in FIFO principle. With this base
|
|
||||||
/// class it's easy to implement sound processing stages that can be chained together,
|
};
|
||||||
/// so that samples that are fed into beginning of the pipe automatically go through
|
|
||||||
/// all the processing stages.
|
|
||||||
///
|
/// Base-class for sound processing routines working in FIFO principle. With this base
|
||||||
/// When samples are input to this class, they're first processed and then put to
|
/// class it's easy to implement sound processing stages that can be chained together,
|
||||||
/// the FIFO pipe that's defined as output of this class. This output pipe can be
|
/// so that samples that are fed into beginning of the pipe automatically go through
|
||||||
/// either other processing stage or a FIFO sample buffer.
|
/// all the processing stages.
|
||||||
class FIFOProcessor :public FIFOSamplePipe
|
///
|
||||||
{
|
/// When samples are input to this class, they're first processed and then put to
|
||||||
protected:
|
/// the FIFO pipe that's defined as output of this class. This output pipe can be
|
||||||
/// Internal pipe where processed samples are put.
|
/// either other processing stage or a FIFO sample buffer.
|
||||||
FIFOSamplePipe *output;
|
class FIFOProcessor :public FIFOSamplePipe
|
||||||
|
{
|
||||||
/// Sets output pipe.
|
protected:
|
||||||
void setOutPipe(FIFOSamplePipe *pOutput)
|
/// Internal pipe where processed samples are put.
|
||||||
{
|
FIFOSamplePipe *output;
|
||||||
assert(output == NULL);
|
|
||||||
assert(pOutput != NULL);
|
/// Sets output pipe.
|
||||||
output = pOutput;
|
void setOutPipe(FIFOSamplePipe *pOutput)
|
||||||
}
|
{
|
||||||
|
assert(output == nullptr);
|
||||||
|
assert(pOutput != nullptr);
|
||||||
/// Constructor. Doesn't define output pipe; it has to be set be
|
output = pOutput;
|
||||||
/// 'setOutPipe' function.
|
}
|
||||||
FIFOProcessor()
|
|
||||||
{
|
/// Constructor. Doesn't define output pipe; it has to be set be
|
||||||
output = NULL;
|
/// 'setOutPipe' function.
|
||||||
}
|
FIFOProcessor()
|
||||||
|
{
|
||||||
|
output = nullptr;
|
||||||
/// Constructor. Configures output pipe.
|
}
|
||||||
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
|
|
||||||
)
|
/// Constructor. Configures output pipe.
|
||||||
{
|
FIFOProcessor(FIFOSamplePipe *pOutput ///< Output pipe.
|
||||||
output = pOutput;
|
)
|
||||||
}
|
{
|
||||||
|
output = pOutput;
|
||||||
|
}
|
||||||
/// Destructor.
|
|
||||||
virtual ~FIFOProcessor()
|
/// Destructor.
|
||||||
{
|
virtual ~FIFOProcessor() 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.
|
||||||
/// Please be careful for not to corrupt the book-keeping!
|
/// Please be careful for not to corrupt the book-keeping!
|
||||||
///
|
///
|
||||||
/// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
/// output buffer and removes them from the sample buffer. If there are less than
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
/// 'numsample' samples in the buffer, returns all that available.
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
///
|
///
|
||||||
/// \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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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.
|
///
|
||||||
///
|
/// 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.
|
||||||
|
virtual uint numSamples() const override
|
||||||
/// Returns number of samples currently available.
|
{
|
||||||
virtual uint numSamples() const
|
return output->numSamples();
|
||||||
{
|
}
|
||||||
return output->numSamples();
|
|
||||||
}
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
virtual int isEmpty() const override
|
||||||
|
{
|
||||||
/// Returns nonzero if there aren't any samples available for outputting.
|
return output->isEmpty();
|
||||||
virtual int isEmpty() const
|
}
|
||||||
{
|
|
||||||
return output->isEmpty();
|
/// allow trimming (downwards) amount of samples in pipeline.
|
||||||
}
|
/// Returns adjusted amount of samples
|
||||||
|
virtual uint adjustAmountOfSamples(uint numSamples) override
|
||||||
/// allow trimming (downwards) amount of samples in pipeline.
|
{
|
||||||
/// Returns adjusted amount of samples
|
return output->adjustAmountOfSamples(numSamples);
|
||||||
virtual uint adjustAmountOfSamples(uint numSamples)
|
}
|
||||||
{
|
};
|
||||||
return output->adjustAmountOfSamples(numSamples);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
#endif
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -1,26 +1,22 @@
|
|||||||
## Process this file with automake to create Makefile.in
|
## Process this file with automake to create Makefile.in
|
||||||
##
|
##
|
||||||
## $Id$
|
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
||||||
##
|
##
|
||||||
## Copyright (C) 2003 - David W. Durham
|
## 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
|
||||||
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
## Foundation; either version 2 of the License, or (at your option) any later
|
||||||
##
|
## version.
|
||||||
## 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
|
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
## Foundation; either version 2 of the License, or (at your option) any later
|
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
## version.
|
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
##
|
##
|
||||||
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
## You should have received a copy of the GNU General Public License along with
|
||||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
## Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU General Public License along with
|
## I used config/am_include.mk for common definitions
|
||||||
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
include $(top_srcdir)/config/am_include.mk
|
||||||
## Place - Suite 330, Boston, MA 02111-1307, USA
|
|
||||||
|
pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h
|
||||||
## I used config/am_include.mk for common definitions
|
|
||||||
include $(top_srcdir)/config/am_include.mk
|
|
||||||
|
|
||||||
pkginclude_HEADERS=FIFOSampleBuffer.h FIFOSamplePipe.h SoundTouch.h STTypes.h BPMDetect.h soundtouch_config.h
|
|
||||||
|
|
||||||
|
|||||||
@ -1,167 +1,191 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Common type definitions for SoundTouch audio processing library.
|
/// Common type definitions for SoundTouch audio processing library.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 3 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef STTypes_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define STTypes_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
typedef unsigned int uint;
|
||||||
//
|
typedef unsigned long ulong;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
// Patch for MinGW: on Win64 long is 32-bit
|
||||||
#ifndef STTypes_H
|
#ifdef _WIN64
|
||||||
#define STTypes_H
|
typedef unsigned long long ulongptr;
|
||||||
|
#else
|
||||||
typedef unsigned int uint;
|
typedef ulong ulongptr;
|
||||||
typedef unsigned long ulong;
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
// In GCC, include soundtouch_config.h made by config scritps
|
// Helper macro for aligning pointer up to next 16-byte boundary
|
||||||
#include "soundtouch_config.h"
|
#define SOUNDTOUCH_ALIGN_POINTER_16(x) ( ( (ulongptr)(x) + 15 ) & ~(ulongptr)15 )
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef _WINDEF_
|
#if (defined(__GNUC__) && !defined(ANDROID))
|
||||||
// if these aren't defined already by Windows headers, define now
|
// In GCC, include soundtouch_config.h made by config scritps.
|
||||||
|
// Skip this in Android compilation that uses GCC but without configure scripts.
|
||||||
typedef int BOOL;
|
#include "soundtouch_config.h"
|
||||||
|
#endif
|
||||||
#define FALSE 0
|
|
||||||
#define TRUE 1
|
|
||||||
|
namespace soundtouch
|
||||||
#endif // _WINDEF_
|
{
|
||||||
|
/// Max allowed number of channels. This is not a hard limit but to have some
|
||||||
|
/// maximum value for argument sanity checks -- can be increased if necessary
|
||||||
namespace soundtouch
|
#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:
|
||||||
//#undef SOUNDTOUCH_INTEGER_SAMPLES
|
//#undef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
//#undef SOUNDTOUCH_FLOAT_SAMPLES
|
//#undef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
|
||||||
#if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
|
/// If following flag is defined, always uses multichannel processing
|
||||||
|
/// routines also for mono and stero sound. This is for routine testing
|
||||||
/// Choose either 32bit floating point or 16bit integer sampletype
|
/// purposes; output should be same with either routines, yet disabling
|
||||||
/// by choosing one of the following defines, unless this selection
|
/// the dedicated mono/stereo processing routines will result in slower
|
||||||
/// has already been done in some other file.
|
/// runtime performance so recommendation is to keep this off.
|
||||||
////
|
// #define USE_MULTICH_ALWAYS
|
||||||
/// Notes:
|
|
||||||
/// - In Windows environment, choose the sample format with the
|
#if (defined(__SOFTFP__) && defined(ANDROID))
|
||||||
/// following defines.
|
// For Android compilation: Force use of Integer samples in case that
|
||||||
/// - In GNU environment, the floating point samples are used by
|
// compilation uses soft-floating point emulation - soft-fp is way too slow
|
||||||
/// default, but integer samples can be chosen by giving the
|
#undef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
/// following switch to the configure script:
|
#define SOUNDTOUCH_INTEGER_SAMPLES 1
|
||||||
/// ./configure --enable-integer-samples
|
#endif
|
||||||
/// However, if you still prefer to select the sample format here
|
|
||||||
/// also in GNU environment, then please #undef the INTEGER_SAMPLE
|
#if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
|
||||||
/// and FLOAT_SAMPLE defines first as in comments above.
|
|
||||||
//#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples
|
/// Choose either 32bit floating point or 16bit integer sampletype
|
||||||
#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples
|
/// by choosing one of the following defines, unless this selection
|
||||||
|
/// has already been done in some other file.
|
||||||
#endif
|
////
|
||||||
|
/// Notes:
|
||||||
#if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)
|
/// - In Windows environment, choose the sample format with the
|
||||||
/// Define this to allow X86-specific assembler/intrinsic optimizations.
|
/// following defines.
|
||||||
/// Notice that library contains also usual C++ versions of each of these
|
/// - In GNU environment, the floating point samples are used by
|
||||||
/// these routines, so if you're having difficulties getting the optimized
|
/// default, but integer samples can be chosen by giving the
|
||||||
/// routines compiled for whatever reason, you may disable these optimizations
|
/// following switch to the configure script:
|
||||||
/// to make the library compile.
|
/// ./configure --enable-integer-samples
|
||||||
|
/// However, if you still prefer to select the sample format here
|
||||||
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
|
/// also in GNU environment, then please #undef the INTEGER_SAMPLE
|
||||||
|
/// and FLOAT_SAMPLE defines first as in comments above.
|
||||||
/// In GNU environment, allow the user to override this setting by
|
//#define SOUNDTOUCH_INTEGER_SAMPLES 1 //< 16bit integer samples
|
||||||
/// giving the following switch to the configure script:
|
#define SOUNDTOUCH_FLOAT_SAMPLES 1 //< 32bit float samples
|
||||||
/// ./configure --disable-x86-optimizations
|
|
||||||
/// ./configure --enable-x86-optimizations=no
|
#endif
|
||||||
#ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
|
|
||||||
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
#if (_M_IX86 || __i386__ || __x86_64__ || _M_X64)
|
||||||
#endif
|
/// Define this to allow X86-specific assembler/intrinsic optimizations.
|
||||||
#else
|
/// Notice that library contains also usual C++ versions of each of these
|
||||||
/// Always disable optimizations when not using a x86 systems.
|
/// these routines, so if you're having difficulties getting the optimized
|
||||||
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
/// routines compiled for whatever reason, you may disable these optimizations
|
||||||
|
/// to make the library compile.
|
||||||
#endif
|
|
||||||
|
#define SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS 1
|
||||||
// If defined, allows the SIMD-optimized routines to take minor shortcuts
|
|
||||||
// for improved performance. Undefine to require faithfully similar SIMD
|
/// In GNU environment, allow the user to override this setting by
|
||||||
// calculations as in normal C implementation.
|
/// giving the following switch to the configure script:
|
||||||
#define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
|
/// ./configure --disable-x86-optimizations
|
||||||
|
/// ./configure --enable-x86-optimizations=no
|
||||||
|
#ifdef SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
// 16bit integer sample type
|
#endif
|
||||||
typedef short SAMPLETYPE;
|
#else
|
||||||
// data type for sample accumulation: Use 32bit integer to prevent overflows
|
/// Always disable optimizations when not using a x86 systems.
|
||||||
typedef long LONG_SAMPLETYPE;
|
#undef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
|
|
||||||
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
#endif
|
||||||
// check that only one sample type is defined
|
|
||||||
#error "conflicting sample types defined"
|
// If defined, allows the SIMD-optimized routines to skip unevenly aligned
|
||||||
#endif // SOUNDTOUCH_FLOAT_SAMPLES
|
// memory offsets that can cause performance penalty in some SIMD implementations.
|
||||||
|
// Causes slight compromise in sound quality.
|
||||||
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
// #define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION 1
|
||||||
// Allow MMX optimizations
|
|
||||||
#define SOUNDTOUCH_ALLOW_MMX 1
|
|
||||||
#endif
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
// 16bit integer sample type
|
||||||
#else
|
typedef short SAMPLETYPE;
|
||||||
|
// data type for sample accumulation: Use 32bit integer to prevent overflows
|
||||||
// floating point samples
|
typedef long LONG_SAMPLETYPE;
|
||||||
typedef float SAMPLETYPE;
|
|
||||||
// data type for sample accumulation: Use double to utilize full precision.
|
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
typedef double LONG_SAMPLETYPE;
|
// check that only one sample type is defined
|
||||||
|
#error "conflicting sample types defined"
|
||||||
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
#endif // SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
// Allow SSE optimizations
|
|
||||||
#define SOUNDTOUCH_ALLOW_SSE 1
|
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
#endif
|
// Allow MMX optimizations (not available in X64 mode)
|
||||||
|
#if (!_M_X64)
|
||||||
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
#define SOUNDTOUCH_ALLOW_MMX 1
|
||||||
|
#endif
|
||||||
};
|
#endif
|
||||||
|
|
||||||
// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions:
|
#else
|
||||||
// #define ST_NO_EXCEPTION_HANDLING 1
|
|
||||||
#ifdef ST_NO_EXCEPTION_HANDLING
|
// floating point samples
|
||||||
// Exceptions disabled. Throw asserts instead if enabled.
|
typedef float SAMPLETYPE;
|
||||||
#include <assert.h>
|
// data type for sample accumulation: Use float also here to enable
|
||||||
#define ST_THROW_RT_ERROR(x) {assert((const char *)x);}
|
// efficient autovectorization
|
||||||
#else
|
typedef float LONG_SAMPLETYPE;
|
||||||
// use c++ standard exceptions
|
|
||||||
#include <stdexcept>
|
#ifdef SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS
|
||||||
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
|
// Allow SSE optimizations
|
||||||
#endif
|
#define SOUNDTOUCH_ALLOW_SSE 1
|
||||||
|
#endif
|
||||||
// When this #define is active, eliminates a clicking sound when the "rate" or "pitch"
|
|
||||||
// parameter setting crosses from value <1 to >=1 or vice versa during processing.
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
// Default is off as such crossover is untypical case and involves a slight sound
|
|
||||||
// quality compromise.
|
#if ((SOUNDTOUCH_ALLOW_SSE) || (__SSE__) || (SOUNDTOUCH_USE_NEON))
|
||||||
//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1
|
#if SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION
|
||||||
|
#define ST_SIMD_AVOID_UNALIGNED
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// define ST_NO_EXCEPTION_HANDLING switch to disable throwing std exceptions:
|
||||||
|
// #define ST_NO_EXCEPTION_HANDLING 1
|
||||||
|
#ifdef ST_NO_EXCEPTION_HANDLING
|
||||||
|
// Exceptions disabled. Throw asserts instead if enabled.
|
||||||
|
#include <assert.h>
|
||||||
|
#define ST_THROW_RT_ERROR(x) {assert((const char *)x);}
|
||||||
|
#else
|
||||||
|
// use c++ standard exceptions
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#define ST_THROW_RT_ERROR(x) {throw std::runtime_error(x);}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// When this #define is active, eliminates a clicking sound when the "rate" or "pitch"
|
||||||
|
// parameter setting crosses from value <1 to >=1 or vice versa during processing.
|
||||||
|
// Default is off as such crossover is untypical case and involves a slight sound
|
||||||
|
// quality compromise.
|
||||||
|
//#define SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER 1
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,277 +1,348 @@
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
|
/// SoundTouch - main class for tempo/pitch/rate adjusting routines.
|
||||||
///
|
///
|
||||||
/// Notes:
|
/// Notes:
|
||||||
/// - Initialize the SoundTouch object instance by setting up the sound stream
|
/// - Initialize the SoundTouch object instance by setting up the sound stream
|
||||||
/// parameters with functions 'setSampleRate' and 'setChannels', then set
|
/// parameters with functions 'setSampleRate' and 'setChannels', then set
|
||||||
/// desired tempo/pitch/rate settings with the corresponding functions.
|
/// desired tempo/pitch/rate settings with the corresponding functions.
|
||||||
///
|
///
|
||||||
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
|
/// - The SoundTouch class behaves like a first-in-first-out pipeline: The
|
||||||
/// samples that are to be processed are fed into one of the pipe by calling
|
/// samples that are to be processed are fed into one of the pipe by calling
|
||||||
/// function 'putSamples', while the ready processed samples can be read
|
/// function 'putSamples', while the ready processed samples can be read
|
||||||
/// from the other end of the pipeline with function 'receiveSamples'.
|
/// from the other end of the pipeline with function 'receiveSamples'.
|
||||||
///
|
///
|
||||||
/// - The SoundTouch processing classes require certain sized 'batches' of
|
/// - The SoundTouch processing classes require certain sized 'batches' of
|
||||||
/// samples in order to process the sound. For this reason the classes buffer
|
/// samples in order to process the sound. For this reason the classes buffer
|
||||||
/// incoming samples until there are enough of samples available for
|
/// incoming samples until there are enough of samples available for
|
||||||
/// processing, then they carry out the processing step and consequently
|
/// processing, then they carry out the processing step and consequently
|
||||||
/// make the processed samples available for outputting.
|
/// make the processed samples available for outputting.
|
||||||
///
|
///
|
||||||
/// - For the above reason, the processing routines introduce a certain
|
/// - For the above reason, the processing routines introduce a certain
|
||||||
/// 'latency' between the input and output, so that the samples input to
|
/// 'latency' between the input and output, so that the samples input to
|
||||||
/// SoundTouch may not be immediately available in the output, and neither
|
/// SoundTouch may not be immediately available in the output, and neither
|
||||||
/// the amount of outputtable samples may not immediately be in direct
|
/// the amount of outputtable samples may not immediately be in direct
|
||||||
/// relationship with the amount of previously input samples.
|
/// relationship with the amount of previously input samples.
|
||||||
///
|
///
|
||||||
/// - The tempo/pitch/rate control parameters can be altered during processing.
|
/// - The tempo/pitch/rate control parameters can be altered during processing.
|
||||||
/// Please notice though that they aren't currently protected by semaphores,
|
/// Please notice though that they aren't currently protected by semaphores,
|
||||||
/// so in multi-thread application external semaphore protection may be
|
/// so in multi-thread application external semaphore protection may be
|
||||||
/// required.
|
/// required.
|
||||||
///
|
///
|
||||||
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
|
/// - This class utilizes classes 'TDStretch' for tempo change (without modifying
|
||||||
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
|
/// pitch) and 'RateTransposer' for changing the playback rate (that is, both
|
||||||
/// tempo and pitch in the same ratio) of the sound. The third available control
|
/// tempo and pitch in the same ratio) of the sound. The third available control
|
||||||
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
|
/// 'pitch' (change pitch but maintain tempo) is produced by a combination of
|
||||||
/// combining the two other controls.
|
/// combining the two other controls.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef SoundTouch_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define SoundTouch_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include "FIFOSamplePipe.h"
|
||||||
//
|
#include "STTypes.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
namespace soundtouch
|
||||||
#ifndef SoundTouch_H
|
{
|
||||||
#define SoundTouch_H
|
|
||||||
|
/// Soundtouch library version string
|
||||||
#include "FIFOSamplePipe.h"
|
#define SOUNDTOUCH_VERSION "2.3.3"
|
||||||
#include "STTypes.h"
|
|
||||||
|
/// SoundTouch library version id
|
||||||
namespace soundtouch
|
#define SOUNDTOUCH_VERSION_ID (20303)
|
||||||
{
|
|
||||||
|
//
|
||||||
/// Soundtouch library version string
|
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
||||||
#define SOUNDTOUCH_VERSION "1.7.0"
|
|
||||||
|
/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
|
||||||
/// SoundTouch library version id
|
#define SETTING_USE_AA_FILTER 0
|
||||||
#define SOUNDTOUCH_VERSION_ID (10700)
|
|
||||||
|
/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
|
||||||
//
|
#define SETTING_AA_FILTER_LENGTH 1
|
||||||
// Available setting IDs for the 'setSetting' & 'get_setting' functions:
|
|
||||||
|
/// Enable/disable quick seeking algorithm in tempo changer routine
|
||||||
/// Enable/disable anti-alias filter in pitch transposer (0 = disable)
|
/// (enabling quick seeking lowers CPU utilization but causes a minor sound
|
||||||
#define SETTING_USE_AA_FILTER 0
|
/// quality compromising)
|
||||||
|
#define SETTING_USE_QUICKSEEK 2
|
||||||
/// Pitch transposer anti-alias filter length (8 .. 128 taps, default = 32)
|
|
||||||
#define SETTING_AA_FILTER_LENGTH 1
|
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
|
||||||
|
/// to how long sequences the original sound is chopped in the time-stretch algorithm.
|
||||||
/// Enable/disable quick seeking algorithm in tempo changer routine
|
/// See "STTypes.h" or README for more information.
|
||||||
/// (enabling quick seeking lowers CPU utilization but causes a minor sound
|
#define SETTING_SEQUENCE_MS 3
|
||||||
/// quality compromising)
|
|
||||||
#define SETTING_USE_QUICKSEEK 2
|
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
|
||||||
|
/// best possible overlapping location. This determines from how wide window the algorithm
|
||||||
/// Time-stretch algorithm single processing sequence length in milliseconds. This determines
|
/// may look for an optimal joining location when mixing the sound sequences back together.
|
||||||
/// to how long sequences the original sound is chopped in the time-stretch algorithm.
|
/// See "STTypes.h" or README for more information.
|
||||||
/// See "STTypes.h" or README for more information.
|
#define SETTING_SEEKWINDOW_MS 4
|
||||||
#define SETTING_SEQUENCE_MS 3
|
|
||||||
|
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
|
||||||
/// Time-stretch algorithm seeking window length in milliseconds for algorithm that finds the
|
/// are mixed back together, to form a continuous sound stream, this parameter defines over
|
||||||
/// best possible overlapping location. This determines from how wide window the algorithm
|
/// how long period the two consecutive sequences are let to overlap each other.
|
||||||
/// may look for an optimal joining location when mixing the sound sequences back together.
|
/// See "STTypes.h" or README for more information.
|
||||||
/// See "STTypes.h" or README for more information.
|
#define SETTING_OVERLAP_MS 5
|
||||||
#define SETTING_SEEKWINDOW_MS 4
|
|
||||||
|
|
||||||
/// Time-stretch algorithm overlap length in milliseconds. When the chopped sound sequences
|
/// Call "getSetting" with this ID to query processing sequence size in samples.
|
||||||
/// are mixed back together, to form a continuous sound stream, this parameter defines over
|
/// This value gives approximate value of how many input samples you'll need to
|
||||||
/// how long period the two consecutive sequences are let to overlap each other.
|
/// feed into SoundTouch after initial buffering to get out a new batch of
|
||||||
/// See "STTypes.h" or README for more information.
|
/// output samples.
|
||||||
#define SETTING_OVERLAP_MS 5
|
///
|
||||||
|
/// This value does not include initial buffering at beginning of a new processing
|
||||||
|
/// stream, use SETTING_INITIAL_LATENCY to get the initial buffering size.
|
||||||
/// Call "getSetting" with this ID to query nominal average processing sequence
|
///
|
||||||
/// size in samples. This value tells approcimate value how many input samples
|
/// Notices:
|
||||||
/// SoundTouch needs to gather before it does DSP processing run for the sample batch.
|
/// - This is read-only parameter, i.e. setSetting ignores this parameter
|
||||||
///
|
/// - This parameter value is not constant but change depending on
|
||||||
/// Notices:
|
/// tempo/pitch/rate/samplerate settings.
|
||||||
/// - This is read-only parameter, i.e. setSetting ignores this parameter
|
#define SETTING_NOMINAL_INPUT_SEQUENCE 6
|
||||||
/// - Returned value is approximate average value, exact processing batch
|
|
||||||
/// size may wary from time to time
|
|
||||||
/// - This parameter value is not constant but may change depending on
|
/// Call "getSetting" with this ID to query nominal average processing output
|
||||||
/// tempo/pitch/rate/samplerate settings.
|
/// size in samples. This value tells approcimate value how many output samples
|
||||||
#define SETTING_NOMINAL_INPUT_SEQUENCE 6
|
/// SoundTouch outputs once it does DSP processing run for a batch of input samples.
|
||||||
|
///
|
||||||
|
/// Notices:
|
||||||
/// Call "getSetting" with this ID to query nominal average processing output
|
/// - This is read-only parameter, i.e. setSetting ignores this parameter
|
||||||
/// size in samples. This value tells approcimate value how many output samples
|
/// - This parameter value is not constant but change depending on
|
||||||
/// SoundTouch outputs once it does DSP processing run for a batch of input samples.
|
/// tempo/pitch/rate/samplerate settings.
|
||||||
///
|
#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7
|
||||||
/// Notices:
|
|
||||||
/// - This is read-only parameter, i.e. setSetting ignores this parameter
|
|
||||||
/// - Returned value is approximate average value, exact processing batch
|
/// Call "getSetting" with this ID to query initial processing latency, i.e.
|
||||||
/// size may wary from time to time
|
/// approx. how many samples you'll need to enter to SoundTouch pipeline before
|
||||||
/// - This parameter value is not constant but may change depending on
|
/// you can expect to get first batch of ready output samples out.
|
||||||
/// tempo/pitch/rate/samplerate settings.
|
///
|
||||||
#define SETTING_NOMINAL_OUTPUT_SEQUENCE 7
|
/// After the first output batch, you can then expect to get approx.
|
||||||
|
/// SETTING_NOMINAL_OUTPUT_SEQUENCE ready samples out for every
|
||||||
class SoundTouch : public FIFOProcessor
|
/// SETTING_NOMINAL_INPUT_SEQUENCE samples that you enter into SoundTouch.
|
||||||
{
|
///
|
||||||
private:
|
/// Example:
|
||||||
/// Rate transposer class instance
|
/// processing with parameter -tempo=5
|
||||||
class RateTransposer *pRateTransposer;
|
/// => initial latency = 5509 samples
|
||||||
|
/// input sequence = 4167 samples
|
||||||
/// Time-stretch class instance
|
/// output sequence = 3969 samples
|
||||||
class TDStretch *pTDStretch;
|
///
|
||||||
|
/// Accordingly, you can expect to feed in approx. 5509 samples at beginning of
|
||||||
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
/// the stream, and then you'll get out the first 3969 samples. After that, for
|
||||||
float virtualRate;
|
/// every approx. 4167 samples that you'll put in, you'll receive again approx.
|
||||||
|
/// 3969 samples out.
|
||||||
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
///
|
||||||
float virtualTempo;
|
/// This also means that average latency during stream processing is
|
||||||
|
/// INITIAL_LATENCY-OUTPUT_SEQUENCE/2, in the above example case 5509-3969/2
|
||||||
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
/// = 3524 samples
|
||||||
float virtualPitch;
|
///
|
||||||
|
/// Notices:
|
||||||
/// Flag: Has sample rate been set?
|
/// - This is read-only parameter, i.e. setSetting ignores this parameter
|
||||||
BOOL bSrateSet;
|
/// - This parameter value is not constant but change depending on
|
||||||
|
/// tempo/pitch/rate/samplerate settings.
|
||||||
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
|
#define SETTING_INITIAL_LATENCY 8
|
||||||
/// 'virtualPitch' parameters.
|
|
||||||
void calcEffectiveRateAndTempo();
|
|
||||||
|
class SoundTouch : public FIFOProcessor
|
||||||
protected :
|
{
|
||||||
/// Number of channels
|
private:
|
||||||
uint channels;
|
/// Rate transposer class instance
|
||||||
|
class RateTransposer *pRateTransposer;
|
||||||
/// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
|
|
||||||
float rate;
|
/// Time-stretch class instance
|
||||||
|
class TDStretch *pTDStretch;
|
||||||
/// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
|
|
||||||
float tempo;
|
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
||||||
|
double virtualRate;
|
||||||
public:
|
|
||||||
SoundTouch();
|
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
||||||
virtual ~SoundTouch();
|
double virtualTempo;
|
||||||
|
|
||||||
/// Get SoundTouch library version string
|
/// Virtual pitch parameter. Effective rate & tempo are calculated from these parameters.
|
||||||
static const char *getVersionString();
|
double virtualPitch;
|
||||||
|
|
||||||
/// Get SoundTouch library version Id
|
/// Flag: Has sample rate been set?
|
||||||
static uint getVersionId();
|
bool bSrateSet;
|
||||||
|
|
||||||
/// Sets new rate control value. Normal rate = 1.0, smaller values
|
/// Accumulator for how many samples in total will be expected as output vs. samples put in,
|
||||||
/// represent slower rate, larger faster rates.
|
/// considering current processing settings.
|
||||||
void setRate(float newRate);
|
double samplesExpectedOut;
|
||||||
|
|
||||||
/// Sets new tempo control value. Normal tempo = 1.0, smaller values
|
/// Accumulator for how many samples in total have been read out from the processing so far
|
||||||
/// represent slower tempo, larger faster tempo.
|
long samplesOutput;
|
||||||
void setTempo(float newTempo);
|
|
||||||
|
/// Calculates effective rate & tempo valuescfrom 'virtualRate', 'virtualTempo' and
|
||||||
/// Sets new rate control value as a difference in percents compared
|
/// 'virtualPitch' parameters.
|
||||||
/// to the original rate (-50 .. +100 %)
|
void calcEffectiveRateAndTempo();
|
||||||
void setRateChange(float newRate);
|
|
||||||
|
protected :
|
||||||
/// Sets new tempo control value as a difference in percents compared
|
/// Number of channels
|
||||||
/// to the original tempo (-50 .. +100 %)
|
uint channels;
|
||||||
void setTempoChange(float newTempo);
|
|
||||||
|
/// Effective 'rate' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
|
||||||
/// Sets new pitch control value. Original pitch = 1.0, smaller values
|
double rate;
|
||||||
/// represent lower pitches, larger values higher pitch.
|
|
||||||
void setPitch(float newPitch);
|
/// Effective 'tempo' value calculated from 'virtualRate', 'virtualTempo' and 'virtualPitch'
|
||||||
|
double tempo;
|
||||||
/// Sets pitch change in octaves compared to the original pitch
|
|
||||||
/// (-1.00 .. +1.00)
|
public:
|
||||||
void setPitchOctaves(float newPitch);
|
SoundTouch();
|
||||||
|
virtual ~SoundTouch() override;
|
||||||
/// Sets pitch change in semi-tones compared to the original pitch
|
|
||||||
/// (-12 .. +12)
|
/// Get SoundTouch library version string
|
||||||
void setPitchSemiTones(int newPitch);
|
static const char *getVersionString();
|
||||||
void setPitchSemiTones(float newPitch);
|
|
||||||
|
/// Get SoundTouch library version Id
|
||||||
/// Sets the number of channels, 1 = mono, 2 = stereo
|
static uint getVersionId();
|
||||||
void setChannels(uint numChannels);
|
|
||||||
|
/// Sets new rate control value. Normal rate = 1.0, smaller values
|
||||||
/// Sets sample rate.
|
/// represent slower rate, larger faster rates.
|
||||||
void setSampleRate(uint srate);
|
void setRate(double newRate);
|
||||||
|
|
||||||
/// Flushes the last samples from the processing pipeline to the output.
|
/// Sets new tempo control value. Normal tempo = 1.0, smaller values
|
||||||
/// Clears also the internal processing buffers.
|
/// represent slower tempo, larger faster tempo.
|
||||||
//
|
void setTempo(double newTempo);
|
||||||
/// Note: This function is meant for extracting the last samples of a sound
|
|
||||||
/// stream. This function may introduce additional blank samples in the end
|
/// Sets new rate control value as a difference in percents compared
|
||||||
/// of the sound stream, and thus it's not recommended to call this function
|
/// to the original rate (-50 .. +100 %)
|
||||||
/// in the middle of a sound stream.
|
void setRateChange(double newRate);
|
||||||
void flush();
|
|
||||||
|
/// Sets new tempo control value as a difference in percents compared
|
||||||
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
/// to the original tempo (-50 .. +100 %)
|
||||||
/// the input of the object. Notice that sample rate _has_to_ be set before
|
void setTempoChange(double newTempo);
|
||||||
/// calling this function, otherwise throws a runtime_error exception.
|
|
||||||
virtual void putSamples(
|
/// Sets new pitch control value. Original pitch = 1.0, smaller values
|
||||||
const SAMPLETYPE *samples, ///< Pointer to sample buffer.
|
/// represent lower pitches, larger values higher pitch.
|
||||||
uint numSamples ///< Number of samples in buffer. Notice
|
void setPitch(double newPitch);
|
||||||
///< that in case of stereo-sound a single sample
|
|
||||||
///< contains data for both channels.
|
/// Sets pitch change in octaves compared to the original pitch
|
||||||
);
|
/// (-1.00 .. +1.00)
|
||||||
|
void setPitchOctaves(double newPitch);
|
||||||
/// Clears all the samples in the object's output and internal processing
|
|
||||||
/// buffers.
|
/// Sets pitch change in semi-tones compared to the original pitch
|
||||||
virtual void clear();
|
/// (-12 .. +12)
|
||||||
|
void setPitchSemiTones(int newPitch);
|
||||||
/// Changes a setting controlling the processing system behaviour. See the
|
void setPitchSemiTones(double newPitch);
|
||||||
/// 'SETTING_...' defines for available setting ID's.
|
|
||||||
///
|
/// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
/// \return 'TRUE' if the setting was succesfully changed
|
void setChannels(uint numChannels);
|
||||||
BOOL setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
|
|
||||||
int value ///< New setting value.
|
/// Sets sample rate.
|
||||||
);
|
void setSampleRate(uint srate);
|
||||||
|
|
||||||
/// Reads a setting controlling the processing system behaviour. See the
|
/// Get ratio between input and output audio durations, useful for calculating
|
||||||
/// 'SETTING_...' defines for available setting ID's.
|
/// processed output duration: if you'll process a stream of N samples, then
|
||||||
///
|
/// you can expect to get out N * getInputOutputSampleRatio() samples.
|
||||||
/// \return the setting value.
|
///
|
||||||
int getSetting(int settingId ///< Setting ID number, see SETTING_... defines.
|
/// This ratio will give accurate target duration ratio for a full audio track,
|
||||||
) const;
|
/// given that the the whole track is processed with same processing parameters.
|
||||||
|
///
|
||||||
/// Returns number of samples currently unprocessed.
|
/// If this ratio is applied to calculate intermediate offsets inside a processing
|
||||||
virtual uint numUnprocessedSamples() const;
|
/// stream, then this ratio is approximate and can deviate +- some tens of milliseconds
|
||||||
|
/// from ideal offset, yet by end of the audio stream the duration ratio will become
|
||||||
|
/// exact.
|
||||||
/// Other handy functions that are implemented in the ancestor classes (see
|
///
|
||||||
/// classes 'FIFOProcessor' and 'FIFOSamplePipe')
|
/// Example: if processing with parameters "-tempo=15 -pitch=-3", the function
|
||||||
///
|
/// will return value 0.8695652... Now, if processing an audio stream whose duration
|
||||||
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
|
/// is exactly one million audio samples, then you can expect the processed
|
||||||
/// - numSamples() : Get number of 'ready' samples that can be received with
|
/// output duration be 0.869565 * 1000000 = 869565 samples.
|
||||||
/// function 'receiveSamples()'
|
double getInputOutputSampleRatio();
|
||||||
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
|
|
||||||
/// - clear() : Clears all samples from ready/processing buffers.
|
/// Flushes the last samples from the processing pipeline to the output.
|
||||||
};
|
/// Clears also the internal processing buffers.
|
||||||
|
//
|
||||||
}
|
/// Note: This function is meant for extracting the last samples of a sound
|
||||||
#endif
|
/// stream. This function may introduce additional blank samples in the end
|
||||||
|
/// of the sound stream, and thus it's not recommended to call this function
|
||||||
|
/// in the middle of a sound stream.
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
||||||
|
/// the input of the object. Notice that sample rate _has_to_ be set before
|
||||||
|
/// calling this function, otherwise throws a runtime_error exception.
|
||||||
|
virtual void putSamples(
|
||||||
|
const SAMPLETYPE *samples, ///< Pointer to sample buffer.
|
||||||
|
uint numSamples ///< Number of samples in buffer. Notice
|
||||||
|
///< that in case of stereo-sound a single sample
|
||||||
|
///< contains data for both channels.
|
||||||
|
) override;
|
||||||
|
|
||||||
|
/// Output samples from beginning of the sample buffer. Copies requested samples to
|
||||||
|
/// output buffer and removes them from the sample buffer. If there are less than
|
||||||
|
/// 'numsample' samples in the buffer, returns all that available.
|
||||||
|
///
|
||||||
|
/// \return Number of samples returned.
|
||||||
|
virtual uint receiveSamples(SAMPLETYPE *output, ///< Buffer where to copy output samples.
|
||||||
|
uint maxSamples ///< How many samples to receive at max.
|
||||||
|
) override;
|
||||||
|
|
||||||
|
/// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
||||||
|
/// sample buffer without copying them anywhere.
|
||||||
|
///
|
||||||
|
/// Used to reduce the number of samples in the buffer when accessing the sample buffer directly
|
||||||
|
/// with 'ptrBegin' function.
|
||||||
|
virtual uint receiveSamples(uint maxSamples ///< Remove this many samples from the beginning of pipe.
|
||||||
|
) override;
|
||||||
|
|
||||||
|
/// Clears all the samples in the object's output and internal processing
|
||||||
|
/// buffers.
|
||||||
|
virtual void clear() override;
|
||||||
|
|
||||||
|
/// Changes a setting controlling the processing system behaviour. See the
|
||||||
|
/// 'SETTING_...' defines for available setting ID's.
|
||||||
|
///
|
||||||
|
/// \return 'true' if the setting was successfully changed
|
||||||
|
bool setSetting(int settingId, ///< Setting ID number. see SETTING_... defines.
|
||||||
|
int value ///< New setting value.
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Reads a setting controlling the processing system behaviour. See the
|
||||||
|
/// 'SETTING_...' defines for available setting ID's.
|
||||||
|
///
|
||||||
|
/// \return the setting value.
|
||||||
|
int getSetting(int settingId ///< Setting ID number, see SETTING_... defines.
|
||||||
|
) const;
|
||||||
|
|
||||||
|
/// Returns number of samples currently unprocessed.
|
||||||
|
virtual uint numUnprocessedSamples() const;
|
||||||
|
|
||||||
|
/// Return number of channels
|
||||||
|
uint numChannels() const
|
||||||
|
{
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Other handy functions that are implemented in the ancestor classes (see
|
||||||
|
/// classes 'FIFOProcessor' and 'FIFOSamplePipe')
|
||||||
|
///
|
||||||
|
/// - receiveSamples() : Use this function to receive 'ready' processed samples from SoundTouch.
|
||||||
|
/// - numSamples() : Get number of 'ready' samples that can be received with
|
||||||
|
/// function 'receiveSamples()'
|
||||||
|
/// - isEmpty() : Returns nonzero if there aren't any 'ready' samples.
|
||||||
|
/// - clear() : Clears all samples from ready/processing buffers.
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
3
include/soundtouch_config.h
Normal file
3
include/soundtouch_config.h
Normal 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
|
||||||
8
include/soundtouch_config.h.in
Normal file
8
include/soundtouch_config.h.in
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* Use Float as Sample type */
|
||||||
|
#undef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
|
||||||
|
/* Use Integer as Sample type */
|
||||||
|
#undef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
|
||||||
|
/* Use ARM NEON extension */
|
||||||
|
#undef SOUNDTOUCH_USE_NEON
|
||||||
50
make-win.bat
50
make-win.bat
@ -5,42 +5,21 @@
|
|||||||
@REM "vcvars32.bat" in VC install directotry before running this one.
|
@REM "vcvars32.bat" in VC install directotry before running this one.
|
||||||
@REM
|
@REM
|
||||||
@REM Copyright (c) Olli Parviainen
|
@REM Copyright (c) Olli Parviainen
|
||||||
@REM File Created: 09/Sep/2003
|
|
||||||
@REM
|
@REM
|
||||||
@REM $Id$
|
|
||||||
|
|
||||||
@rem ****************************
|
|
||||||
@rem try first for VS6.0 support
|
|
||||||
|
|
||||||
@if "%MsDevDir%"=="" goto nomsdevdir
|
|
||||||
|
|
||||||
md bin
|
|
||||||
md lib
|
|
||||||
msdev source\SoundTouch\SoundTouch.dsw /MAKE ALL
|
|
||||||
msdev source\SoundStretch\SoundStretch.dsw /MAKE ALL
|
|
||||||
|
|
||||||
goto end
|
|
||||||
|
|
||||||
:nomsdevdir
|
|
||||||
|
|
||||||
@rem **********************************
|
|
||||||
@rem try with devenv for VS2003 support
|
|
||||||
|
|
||||||
@if "%DevEnvDir%"=="" goto nodevdir
|
@if "%DevEnvDir%"=="" goto nodevdir
|
||||||
|
|
||||||
md bin
|
@rem devenv source\SoundStretch\SoundStretch.sln /upgrade
|
||||||
md lib
|
devenv source\SoundStretch\SoundStretch.sln /build "Debug|Win32"
|
||||||
devenv source\SoundTouch\SoundTouch.vcproj /upgrade
|
devenv source\SoundStretch\SoundStretch.sln /build "Release|Win32"
|
||||||
devenv source\SoundTouch\SoundTouch.vcproj /build debug
|
devenv source\SoundStretch\SoundStretch.sln /build "Debug|x64"
|
||||||
devenv source\SoundTouch\SoundTouch.vcproj /build release
|
devenv source\SoundStretch\SoundStretch.sln /build "Release|x64"
|
||||||
|
|
||||||
devenv source\SoundStretch\SoundStretch.vcproj /upgrade
|
@rem devenv source\SoundTouchDll\SoundTouchDll.sln /upgrade
|
||||||
devenv source\SoundStretch\SoundStretch.vcproj /build debug
|
devenv source\SoundTouchDll\SoundTouchDll.sln /build "Debug|Win32"
|
||||||
devenv source\SoundStretch\SoundStretch.vcproj /build release
|
devenv source\SoundTouchDll\SoundTouchDll.sln /build "Release|Win32"
|
||||||
|
devenv source\SoundTouchDll\SoundTouchDll.sln /build "Debug|x64"
|
||||||
devenv source\SoundTouchDll\SoundTouchDll.vcproj /upgrade
|
devenv source\SoundTouchDll\SoundTouchDll.sln /build "Release|x64"
|
||||||
devenv source\SoundTouchDll\SoundTouchDll.vcproj /build debug
|
|
||||||
devenv source\SoundTouchDll\SoundTouchDll.vcproj /build release
|
|
||||||
|
|
||||||
@goto end
|
@goto end
|
||||||
|
|
||||||
@ -48,14 +27,15 @@ devenv source\SoundTouchDll\SoundTouchDll.vcproj /build release
|
|||||||
:nodevdir
|
:nodevdir
|
||||||
|
|
||||||
@echo off
|
@echo off
|
||||||
echo *********************************************************************
|
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
|
echo ** Open "tools"->"Developer Command Line" from Visual Studio IDE, or
|
||||||
echo ** directory, e.g. "\Program Files\Microsoft Visual Studio\VC98\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 ****************************************************************************
|
||||||
|
|
||||||
:end
|
:end
|
||||||
|
|||||||
66
readme.md
Normal file
66
readme.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# SoundTouch library
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
SoundTouch is an open-source audio processing library that allows changing the sound tempo, pitch and playback rate parameters independently from each other:
|
||||||
|
* Change **tempo** while maintaining the original pitch
|
||||||
|
* Change **pitch** while maintaining the original tempo
|
||||||
|
* Change **playback rate** that affects both tempo and pitch at the
|
||||||
|
same time
|
||||||
|
* Change any combination of tempo/pitch/rate
|
||||||
|
|
||||||
|
Visit [SoundTouch website](https://www.surina.net/soundtouch) and see the [README file](https://www.surina.net/soundtouch/readme.html) for more information and audio examples.
|
||||||
|
|
||||||
|
### The latest stable release is 2.3.3
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Use SoundStretch example app for modifying wav audio files, for example as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
soundstretch my_original_file.wav output_file.wav -tempo=+15 -pitch=-3
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [README file](http://soundtouch.surina.net/README.html) for more usage examples and instructions how to build SoundTouch + SoundStretch.
|
||||||
|
|
||||||
|
Ready [SoundStretch application executables](https://www.surina.net/soundtouch/download.html) are available for download for Windows and Mac OS.
|
||||||
|
|
||||||
|
## Language & Platforms
|
||||||
|
|
||||||
|
SoundTouch is written in C++ and compiles in virtually any platform:
|
||||||
|
* Windows
|
||||||
|
* Mac OS
|
||||||
|
* Linux & Unices (including also Raspberry, Beaglebone, Yocto etc embedded Linux flavors)
|
||||||
|
* Android
|
||||||
|
* iOS
|
||||||
|
* embedded systems
|
||||||
|
|
||||||
|
The source code package includes dynamic library import modules for C#, Java and Pascal/Delphi languages.
|
||||||
|
|
||||||
|
## Tarballs
|
||||||
|
|
||||||
|
Source code release tarballs:
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.3.3.tar.gz
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.3.2.tar.gz
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.3.1.tar.gz
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.3.0.tar.gz
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.2.0.tar.gz
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.1.2.tar.gz
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.1.1.tar.gz
|
||||||
|
* https://www.surina.net/soundtouch/soundtouch-2.0.0.tar.gz
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
SoundTouch is released under LGPL v2.1:
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
See [LGPL v2.1 full license text ](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) for details.
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
Also commercial license free of GPL limitations available upon request
|
||||||
@ -1,14 +0,0 @@
|
|||||||
# This file is obsoleted but provided for backwards compatibility
|
|
||||||
# with legacy package environments
|
|
||||||
|
|
||||||
prefix=@prefix@
|
|
||||||
exec_prefix=@exec_prefix@
|
|
||||||
libdir=@libdir@
|
|
||||||
includedir=@includedir@
|
|
||||||
|
|
||||||
Name: SoundTouch
|
|
||||||
Description: SoundTouch is an open-source audio processing library for changing the Tempo, Pitch and Playback Rates of audio streams or files
|
|
||||||
Version: @VERSION@
|
|
||||||
Libs: -L${libdir} -lSoundTouch
|
|
||||||
Cflags: -I${includedir}/soundtouch
|
|
||||||
|
|
||||||
@ -1,7 +1,4 @@
|
|||||||
# m4 configure test script for the SoundTouch library
|
# m4 configure test script for the SoundTouch library
|
||||||
# (c)2003 David W. Durham
|
|
||||||
#
|
|
||||||
# $Id$
|
|
||||||
#
|
#
|
||||||
# This file can be included with other packages that need to test
|
# This file can be included with other packages that need to test
|
||||||
# for libSoundTouch.
|
# for libSoundTouch.
|
||||||
@ -11,7 +8,7 @@
|
|||||||
# It also defines some flags to the configure script for specifying
|
# It also defines some flags to the configure script for specifying
|
||||||
# the location to search for libSoundTouch
|
# the location to search for libSoundTouch
|
||||||
#
|
#
|
||||||
# A user of libSoundTouch should add @SOUNDTOUCH_LIBS@ and
|
# A user of libSoundTouch should add @SOUNDTOUCH_LIBS@ and
|
||||||
# @SOUNDTOUCH_CXXFLAGS@ to the appropriate variables in his
|
# @SOUNDTOUCH_CXXFLAGS@ to the appropriate variables in his
|
||||||
# Makefile.am files
|
# Makefile.am files
|
||||||
#
|
#
|
||||||
@ -35,10 +32,10 @@ AC_DEFUN([AM_PATH_SOUNDTOUCH],[
|
|||||||
then
|
then
|
||||||
saved_CPPFLAGS="$CPPFLAGS"
|
saved_CPPFLAGS="$CPPFLAGS"
|
||||||
saved_LDFLAGS="$LDFLAGS"
|
saved_LDFLAGS="$LDFLAGS"
|
||||||
|
|
||||||
CPPFLAGS="$CPPFLAGS -I$soundtouch_prefix/include"
|
CPPFLAGS="$CPPFLAGS -I$soundtouch_prefix/include"
|
||||||
LDFLAGS="$LDFLAGS -L$soundtouch_prefix/lib"
|
LDFLAGS="$LDFLAGS -L$soundtouch_prefix/lib"
|
||||||
|
|
||||||
dnl make sure SoundTouch.h header file exists
|
dnl make sure SoundTouch.h header file exists
|
||||||
dnl could use AC_CHECK_HEADERS to check for all of them, but the supporting .h file names may change later
|
dnl could use AC_CHECK_HEADERS to check for all of them, but the supporting .h file names may change later
|
||||||
AC_CHECK_HEADER([soundtouch/SoundTouch.h],[
|
AC_CHECK_HEADER([soundtouch/SoundTouch.h],[
|
||||||
@ -52,7 +49,7 @@ AC_DEFUN([AM_PATH_SOUNDTOUCH],[
|
|||||||
|
|
||||||
dnl run action-if-found
|
dnl run action-if-found
|
||||||
ifelse([$2], , :, [$2])
|
ifelse([$2], , :, [$2])
|
||||||
],[
|
],[
|
||||||
dnl run action-if-not-found
|
dnl run action-if-not-found
|
||||||
ifelse([$3], , :, [$3])
|
ifelse([$3], , :, [$3])
|
||||||
])
|
])
|
||||||
|
|||||||
9
source/Android-lib/.classpath
Normal file
9
source/Android-lib/.classpath
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||||
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="gen"/>
|
||||||
|
<classpathentry kind="output" path="bin/classes"/>
|
||||||
|
</classpath>
|
||||||
33
source/Android-lib/.project
Normal file
33
source/Android-lib/.project
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>ExampleActivity</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
30
source/Android-lib/AndroidManifest.xml
Normal file
30
source/Android-lib/AndroidManifest.xml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="net.surina.soundtouchexample"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0" >
|
||||||
|
|
||||||
|
<uses-sdk
|
||||||
|
android:minSdkVersion="11"
|
||||||
|
android:targetSdkVersion="21" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme" >
|
||||||
|
<activity
|
||||||
|
android:name="net.surina.ExampleActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
128
source/Android-lib/README-SoundTouch-Android.html
Normal file
128
source/Android-lib/README-SoundTouch-Android.html
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>SoundTouch in Android</title>
|
||||||
|
<meta http-equiv="Content-Type"
|
||||||
|
content="text/html; charset=windows-1252">
|
||||||
|
<meta http-equiv="Content-Language" content="en-us">
|
||||||
|
<meta name="author" content="Olli Parviainen">
|
||||||
|
<meta name="description"
|
||||||
|
content="Readme file for SoundTouch library Android compilation">
|
||||||
|
<style> <!-- .normal { font-family: Arial }
|
||||||
|
--></style>
|
||||||
|
</head>
|
||||||
|
<body class="normal">
|
||||||
|
<hr>
|
||||||
|
<h1>SoundTouch in Android</h1>
|
||||||
|
<hr>
|
||||||
|
<h2>Compiling SoundTouch for Android</h2>
|
||||||
|
<p>SoundTouch source code package contains "Android-lib" example project that compiles SoundTouch
|
||||||
|
source codes into Android native library, and gives an example of JNI interface
|
||||||
|
for invoking
|
||||||
|
the native SoundTouch routines from an Android application written in Java.</p>
|
||||||
|
<p style="font-weight: 700">Software prerequisites:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Android SDK environment for developing your own Android application. Visit the <a href="http://developer.android.com/index.html">Android developers' site</a>
|
||||||
|
for more information about the Android SDK and developing Android applications.</li>
|
||||||
|
<li>Android NDK compiler kit for compiling native library binaries. The Android NDK
|
||||||
|
is <a href="http://developer.android.com/tools/sdk/ndk/index.html">
|
||||||
|
available for download</a> at the Android developer tools site.</li>
|
||||||
|
<li>In case you're working in Windows environment, install
|
||||||
|
<a href="http://cygwin.com/install.html">
|
||||||
|
Cygwin</a> to run the Android NDK/SDK compiler scripts</li>
|
||||||
|
<li>Latest SoundTouch source code package available at <a href="http://soundtouch.surina.net/sourcecode.html">
|
||||||
|
soundtouch.surina.net</a>.</li>
|
||||||
|
</ul>
|
||||||
|
<p><b>Hint: </b>As installing and configuring all the components for an Android SDK/NDK
|
||||||
|
environment requires fair effort, it's good idea to create a dedicated Virtual
|
||||||
|
Machine environment for the Android development environment installation.
|
||||||
|
Having the Android developer environment setup in dedicated Virtual Machine
|
||||||
|
allows keeping all these settings isolated from your other PC operations, and
|
||||||
|
eases taking backup snapshots of your full development environment.</p>
|
||||||
|
<p><b>Compiling</b></p>
|
||||||
|
<p>
|
||||||
|
To compile the SoundTouch library source codes into an Android native library,
|
||||||
|
open Cygwin/bash shell, go to directory <b>"soundtouch/source/Android-lib/jni"</b> and invoke the NDK
|
||||||
|
compiler with following command:</p>
|
||||||
|
<pre> $NDK/ndk-build</pre>
|
||||||
|
<p>This will build binaries for all the supported Android platforms (arm-v5, arm-v7, X86, MIPS etc) of SoundTouch library, plus the JNI wrapper interface as discussed below. The target binaries will be built into the "libs" subdirectory. As long as all these .so binary library versions are included in the APK Application delivery package, the target Android device can choose the correct library version to use. </p>
|
||||||
|
<p>Notice that to allow Cygwin/bash to locate the NDK compile scripts, you
|
||||||
|
need to define the location of the NDK installation defined in environment
|
||||||
|
variable "NDK". That's easiest done by adding the NDK path definition at end of
|
||||||
|
your <b>~/.bash_profile</b> file, for instance as follows:</p>
|
||||||
|
<pre> NDK=/cygdrive/d/Android/android-ndk-r6</pre>
|
||||||
|
<p><b>Enabling OpenMP parallel computing mode</b></p>
|
||||||
|
<p>
|
||||||
|
SoundTouch supports OpenMP for parallel computing in multi-core
|
||||||
|
environments, and these improvements can be enabled also in the Android
|
||||||
|
build. See the SoundTouch main README.html file for generic notes about the
|
||||||
|
OpenMP implementation.</p>
|
||||||
|
<p>
|
||||||
|
To enable OpenMP mode in Android compilation, edit file <strong>Android.mk</strong>
|
||||||
|
and enable the "-fopenmp" flag in LOCAL_CFLAGS and LOCAL_LDFLAGS variables.
|
||||||
|
This is done by removing hash # from before the following lines in the
|
||||||
|
Android.mk file, before compiling the library:</p>
|
||||||
|
<pre> LOCAL_CFLAGS += -fopenmp
|
||||||
|
LOCAL_LDFLAGS += -fopenmp</pre>
|
||||||
|
<p><strong>OpenMP COMPATIBILITY NOTE: </strong>Android NDK has a threading issue
|
||||||
|
(at least until NDK v10) that causes the native library crash with fatal signal
|
||||||
|
11 if calling OpenMP-improved routines from a background thread. SoundTouch has
|
||||||
|
a workaround for this issue in soundtouch-jni.cpp, and this workaround requires
|
||||||
|
calling function <strong>SoundTouch.getVersionString() </strong>from the Android
|
||||||
|
application's main thread at least once before calling other SoundTouch
|
||||||
|
processing routines. See the SoundTouch Android example application and comments
|
||||||
|
in the <strong>soundtouch-jni.cpp </strong>source code file for more details.</p>
|
||||||
|
<p>
|
||||||
|
<strong>SoundTouch performance in Android</strong></p>
|
||||||
|
<p>
|
||||||
|
See external blog articles for more discussion about the
|
||||||
|
<a href="http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices/">
|
||||||
|
SoundTouch OpenMP implementation</a> and the
|
||||||
|
<a href="http://www.softwarecoven.com/parallel-computing-with-openmp-in-android/">
|
||||||
|
SoundTouch performance benchmark tests in Android environment</a>.</p>
|
||||||
|
<hr />
|
||||||
|
<h2>
|
||||||
|
Calling SoundTouch native routines from Android application</h2>
|
||||||
|
<p>The NDK tools build the SoundTouch c++ routines into a native binary library, while
|
||||||
|
Android applications are written in Java language. To call the SoundTouch and other c/c++
|
||||||
|
routines from an Android java application code, you'll need to use Java Native
|
||||||
|
Interface (JNI).</p>
|
||||||
|
<p>
|
||||||
|
The SoundTouch source code package provides source code example how to
|
||||||
|
use JNI to call native c++ routines from a Java class, and provides source codes also for
|
||||||
|
a simple example Android application:<ul>
|
||||||
|
<li><b>ExampleActivity</b>: This is simple Android example application that
|
||||||
|
utilizes SoundTouch native routines for processing WAV audio files. To build the example
|
||||||
|
application, use Eclipse Android SDK environment to import the "ExampleActivity" project in the "Android-lib" folder into the Eclipse workspace.
|
||||||
|
<li><b>Android-lib/jni/soundtouch-jni.cpp</b>: This file contains c/c++ wrapper routines
|
||||||
|
for performing elementary audio file processing with adjusted tempo/pitch/speed parameters
|
||||||
|
from the Android application. The wrapper interface is not complete, but provides example
|
||||||
|
that is easy to extend when necessary. The NDK compiles this file along with the SoundTouch
|
||||||
|
routines into the native binary library.</li>
|
||||||
|
<li><b>Android-lib/src/net/surina/soundtouch/SoundTouch.java</b>: This file implements
|
||||||
|
the Java interface class that loasd & accesses the JNI routines in the natively compiled library.
|
||||||
|
The example Android application uses this class as interface for processing audio files
|
||||||
|
with SoundTouch.</li>
|
||||||
|
<li><b>Android-lib/build.gradle</b>: Top level build script file for Android Studio 3.1.4+</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
Feel free to examine and extend the provided cpp/java source code example file pair to
|
||||||
|
implement and integrate the desired SoundTouch library capabilities into your own Android application.</p>
|
||||||
|
<hr />
|
||||||
|
<h2>
|
||||||
|
Android floating-point performance considerations</h2>
|
||||||
|
<p>
|
||||||
|
The make process will build dedicated binaries for each supported Android CPU hardware platform type.
|
||||||
|
</p><p>SoundTouch uses floating-point algorithms for ideal sound quality on all other platform than in the lowest-end ARMv5. That is because lowest-end Android devices are not guaranteed to
|
||||||
|
have floating-point hardware in their CPUs, so that the ARMv5 compilation uses by default software-emulation for floating-point calculations to allow running the binary executables also in low-end devices without floating-point hardware.<p>
|
||||||
|
As floating point software-emulation is however several tens of times slower
|
||||||
|
than real hardware-level floating-point calculations, that would make running
|
||||||
|
floating-point-intensive applications such as SoundTouch infeasible in these low-end
|
||||||
|
devices. As workaround, the SoundTouch Android compilation builds the ARMv5 version using integer algorithm versions. The integer
|
||||||
|
algorithm version compromises the sound quality but provides good performance also
|
||||||
|
with low-end devices without hardware floating-point support in the CPU level.</p>
|
||||||
|
<p>When Android devices with more capable device is used, the device will automatically choose a proper library version for ideal sound quality.</p>
|
||||||
|
<hr />
|
||||||
|
<p style="text-align: center"><i>Copyright © Olli Parviainen</i></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
55
source/Android-lib/build.gradle
Normal file
55
source/Android-lib/build.gradle
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
source/Android-lib/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
source/Android-lib/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
source/Android-lib/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
source/Android-lib/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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
172
source/Android-lib/gradlew
vendored
Executable 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
84
source/Android-lib/gradlew.bat
vendored
Normal 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
|
||||||
37
source/Android-lib/jni/Android.mk
Normal file
37
source/Android-lib/jni/Android.mk
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../include $(LOCAL_PATH)/../../SoundStretch
|
||||||
|
# *** Remember: Change -O0 into -O2 in add-applications.mk ***
|
||||||
|
|
||||||
|
LOCAL_MODULE := soundtouch
|
||||||
|
LOCAL_SRC_FILES := soundtouch-jni.cpp ../../SoundTouch/AAFilter.cpp ../../SoundTouch/FIFOSampleBuffer.cpp \
|
||||||
|
../../SoundTouch/FIRFilter.cpp ../../SoundTouch/cpu_detect_x86.cpp \
|
||||||
|
../../SoundTouch/sse_optimized.cpp ../../SoundStretch/WavFile.cpp \
|
||||||
|
../../SoundTouch/RateTransposer.cpp ../../SoundTouch/SoundTouch.cpp \
|
||||||
|
../../SoundTouch/InterpolateCubic.cpp ../../SoundTouch/InterpolateLinear.cpp \
|
||||||
|
../../SoundTouch/InterpolateShannon.cpp ../../SoundTouch/TDStretch.cpp \
|
||||||
|
../../SoundTouch/BPMDetect.cpp ../../SoundTouch/PeakFinder.cpp
|
||||||
|
|
||||||
|
# for native audio
|
||||||
|
LOCAL_SHARED_LIBRARIES += -lgcc
|
||||||
|
# --whole-archive -lgcc
|
||||||
|
# for logging
|
||||||
|
LOCAL_LDLIBS += -llog
|
||||||
|
# for native asset manager
|
||||||
|
#LOCAL_LDLIBS += -landroid
|
||||||
|
|
||||||
|
# Custom Flags:
|
||||||
|
# -fvisibility=hidden : don't export all symbols
|
||||||
|
LOCAL_CFLAGS += -fvisibility=hidden -fdata-sections -ffunction-sections -ffast-math
|
||||||
|
|
||||||
|
# OpenMP mode : enable these flags to enable using OpenMP for parallel computation
|
||||||
|
#LOCAL_CFLAGS += -fopenmp
|
||||||
|
#LOCAL_LDFLAGS += -fopenmp
|
||||||
|
|
||||||
|
|
||||||
|
# Use ARM instruction set instead of Thumb for improved calculation performance in ARM CPUs
|
||||||
|
LOCAL_ARM_MODE := arm
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
9
source/Android-lib/jni/Application.mk
Normal file
9
source/Android-lib/jni/Application.mk
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Build library bilaries for all supported architectures
|
||||||
|
#
|
||||||
|
|
||||||
|
APP_ABI := all #armeabi-v7a armeabi
|
||||||
|
APP_OPTIM := release
|
||||||
|
APP_STL := c++_static
|
||||||
|
APP_CPPFLAGS := -fexceptions # -D SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS
|
||||||
|
|
||||||
258
source/Android-lib/jni/soundtouch-jni.cpp
Normal file
258
source/Android-lib/jni/soundtouch-jni.cpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Example Interface class for SoundTouch native compilation
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// WWW : http://www.surina.net
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#include "../../../include/SoundTouch.h"
|
||||||
|
#include "../source/SoundStretch/WavFile.h"
|
||||||
|
|
||||||
|
#define LOGV(...) __android_log_print((int)ANDROID_LOG_INFO, "SOUNDTOUCH", __VA_ARGS__)
|
||||||
|
//#define LOGV(...)
|
||||||
|
|
||||||
|
|
||||||
|
// String for keeping possible c++ exception error messages. Notice that this isn't
|
||||||
|
// thread-safe but it's expected that exceptions are special situations that won't
|
||||||
|
// occur in several threads in parallel.
|
||||||
|
static string _errMsg = "";
|
||||||
|
|
||||||
|
|
||||||
|
#define DLL_PUBLIC __attribute__ ((visibility ("default")))
|
||||||
|
#define BUFF_SIZE 4096
|
||||||
|
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
|
||||||
|
// Set error message to return
|
||||||
|
static void _setErrmsg(const char *msg)
|
||||||
|
{
|
||||||
|
_errMsg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0 // apparently following workaround not needed any more with concurrent Android SDKs
|
||||||
|
#ifdef _OPENMP
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
extern pthread_key_t gomp_tls_key;
|
||||||
|
static void * _p_gomp_tls = nullptr;
|
||||||
|
|
||||||
|
/// Function to initialize threading for OpenMP.
|
||||||
|
///
|
||||||
|
/// This is a workaround for bug in Android NDK v10 regarding OpenMP: OpenMP works only if
|
||||||
|
/// called from the Android App main thread because in the main thread the gomp_tls storage is
|
||||||
|
/// properly set, however, Android does not properly initialize gomp_tls storage for other threads.
|
||||||
|
/// Thus if OpenMP routines are invoked from some other thread than the main thread,
|
||||||
|
/// the OpenMP routine will crash the application due to nullptr access on uninitialized storage.
|
||||||
|
///
|
||||||
|
/// This workaround stores the gomp_tls storage from main thread, and copies to other threads.
|
||||||
|
/// In order this to work, the Application main thread needws to call at least "getVersionString"
|
||||||
|
/// routine.
|
||||||
|
static int _init_threading(bool warn)
|
||||||
|
{
|
||||||
|
void *ptr = pthread_getspecific(gomp_tls_key);
|
||||||
|
LOGV("JNI thread-specific TLS storage %ld", (long)ptr);
|
||||||
|
if (ptr == nullptr)
|
||||||
|
{
|
||||||
|
LOGV("JNI set missing TLS storage to %ld", (long)_p_gomp_tls);
|
||||||
|
pthread_setspecific(gomp_tls_key, _p_gomp_tls);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGV("JNI store this TLS storage");
|
||||||
|
_p_gomp_tls = ptr;
|
||||||
|
}
|
||||||
|
// Where critical, show warning if storage still not properly initialized
|
||||||
|
if ((warn) && (_p_gomp_tls == nullptr))
|
||||||
|
{
|
||||||
|
_setErrmsg("Error - OpenMP threading not properly initialized: Call SoundTouch.getVersionString() from the App main thread!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
static int _init_threading(bool warn)
|
||||||
|
{
|
||||||
|
// do nothing if not OpenMP build
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Processes the sound file
|
||||||
|
static void _processFile(SoundTouch *pSoundTouch, const char *inFileName, const char *outFileName)
|
||||||
|
{
|
||||||
|
int nSamples;
|
||||||
|
int nChannels;
|
||||||
|
int buffSizeSamples;
|
||||||
|
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
||||||
|
|
||||||
|
// open input file
|
||||||
|
WavInFile inFile(inFileName);
|
||||||
|
int sampleRate = inFile.getSampleRate();
|
||||||
|
int bits = inFile.getNumBits();
|
||||||
|
nChannels = inFile.getNumChannels();
|
||||||
|
|
||||||
|
// create output file
|
||||||
|
WavOutFile outFile(outFileName, sampleRate, bits, nChannels);
|
||||||
|
|
||||||
|
pSoundTouch->setSampleRate(sampleRate);
|
||||||
|
pSoundTouch->setChannels(nChannels);
|
||||||
|
|
||||||
|
assert(nChannels > 0);
|
||||||
|
buffSizeSamples = BUFF_SIZE / nChannels;
|
||||||
|
|
||||||
|
// Process samples read from the input file
|
||||||
|
while (inFile.eof() == 0)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
|
||||||
|
// Read a chunk of samples from the input file
|
||||||
|
num = inFile.read(sampleBuffer, BUFF_SIZE);
|
||||||
|
nSamples = num / nChannels;
|
||||||
|
|
||||||
|
// Feed the samples into SoundTouch processor
|
||||||
|
pSoundTouch->putSamples(sampleBuffer, nSamples);
|
||||||
|
|
||||||
|
// Read ready samples from SoundTouch processor & write them output file.
|
||||||
|
// NOTES:
|
||||||
|
// - 'receiveSamples' doesn't necessarily return any samples at all
|
||||||
|
// during some rounds!
|
||||||
|
// - On the other hand, during some round 'receiveSamples' may have more
|
||||||
|
// ready samples than would fit into 'sampleBuffer', and for this reason
|
||||||
|
// the 'receiveSamples' call is iterated for as many times as it
|
||||||
|
// outputs samples.
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
||||||
|
outFile.write(sampleBuffer, nSamples * nChannels);
|
||||||
|
} while (nSamples != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now the input file is processed, yet 'flush' few last samples that are
|
||||||
|
// hiding in the SoundTouch's internal processing pipeline.
|
||||||
|
pSoundTouch->flush();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
||||||
|
outFile.write(sampleBuffer, nSamples * nChannels);
|
||||||
|
} while (nSamples != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getVersionString(JNIEnv *env, jobject thiz)
|
||||||
|
{
|
||||||
|
const char *verStr;
|
||||||
|
|
||||||
|
LOGV("JNI call SoundTouch.getVersionString");
|
||||||
|
|
||||||
|
// Call example SoundTouch routine
|
||||||
|
verStr = SoundTouch::getVersionString();
|
||||||
|
|
||||||
|
// gomp_tls storage bug workaround - see comments in _init_threading() function!
|
||||||
|
// update: apparently this is not needed any more with concurrent Android SDKs
|
||||||
|
// _init_threading(false);
|
||||||
|
|
||||||
|
int threads = 0;
|
||||||
|
#pragma omp parallel
|
||||||
|
{
|
||||||
|
#pragma omp atomic
|
||||||
|
threads ++;
|
||||||
|
}
|
||||||
|
LOGV("JNI thread count %d", threads);
|
||||||
|
|
||||||
|
// return version as string
|
||||||
|
return env->NewStringUTF(verStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC jlong Java_net_surina_soundtouch_SoundTouch_newInstance(JNIEnv *env, jobject thiz)
|
||||||
|
{
|
||||||
|
return (jlong)(new SoundTouch());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_deleteInstance(JNIEnv *env, jobject thiz, jlong handle)
|
||||||
|
{
|
||||||
|
SoundTouch *ptr = (SoundTouch*)handle;
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setTempo(JNIEnv *env, jobject thiz, jlong handle, jfloat tempo)
|
||||||
|
{
|
||||||
|
SoundTouch *ptr = (SoundTouch*)handle;
|
||||||
|
ptr->setTempo(tempo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setPitchSemiTones(JNIEnv *env, jobject thiz, jlong handle, jfloat pitch)
|
||||||
|
{
|
||||||
|
SoundTouch *ptr = (SoundTouch*)handle;
|
||||||
|
ptr->setPitchSemiTones(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC void Java_net_surina_soundtouch_SoundTouch_setSpeed(JNIEnv *env, jobject thiz, jlong handle, jfloat speed)
|
||||||
|
{
|
||||||
|
SoundTouch *ptr = (SoundTouch*)handle;
|
||||||
|
ptr->setRate(speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC jstring Java_net_surina_soundtouch_SoundTouch_getErrorString(JNIEnv *env, jobject thiz)
|
||||||
|
{
|
||||||
|
jstring result = env->NewStringUTF(_errMsg.c_str());
|
||||||
|
_errMsg.clear();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" DLL_PUBLIC int Java_net_surina_soundtouch_SoundTouch_processFile(JNIEnv *env, jobject thiz, jlong handle, jstring jinputFile, jstring joutputFile)
|
||||||
|
{
|
||||||
|
SoundTouch *ptr = (SoundTouch*)handle;
|
||||||
|
|
||||||
|
const char *inputFile = env->GetStringUTFChars(jinputFile, 0);
|
||||||
|
const char *outputFile = env->GetStringUTFChars(joutputFile, 0);
|
||||||
|
|
||||||
|
LOGV("JNI process file %s", inputFile);
|
||||||
|
|
||||||
|
/// gomp_tls storage bug workaround - see comments in _init_threading() function!
|
||||||
|
// update: apparently this is not needed any more with concurrent Android SDKs
|
||||||
|
// if (_init_threading(true)) return -1;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_processFile(ptr, inputFile, outputFile);
|
||||||
|
}
|
||||||
|
catch (const runtime_error &e)
|
||||||
|
{
|
||||||
|
const char *err = e.what();
|
||||||
|
// An exception occurred during processing, return the error message
|
||||||
|
LOGV("JNI exception in SoundTouch::processFile: %s", err);
|
||||||
|
_setErrmsg(err);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
env->ReleaseStringUTFChars(jinputFile, inputFile);
|
||||||
|
env->ReleaseStringUTFChars(joutputFile, outputFile);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
3
source/Android-lib/lint.xml
Normal file
3
source/Android-lib/lint.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<lint>
|
||||||
|
</lint>
|
||||||
20
source/Android-lib/proguard-project.txt
Normal file
20
source/Android-lib/proguard-project.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# To enable ProGuard in your project, edit project.properties
|
||||||
|
# to define the proguard.config property as described in that file.
|
||||||
|
#
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the ProGuard
|
||||||
|
# include property in project.properties.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
14
source/Android-lib/project.properties
Normal file
14
source/Android-lib/project.properties
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system edit
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
#
|
||||||
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
|
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-19
|
||||||
BIN
source/Android-lib/res/drawable-hdpi/ic_launcher.png
Normal file
BIN
source/Android-lib/res/drawable-hdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
source/Android-lib/res/drawable-mdpi/ic_launcher.png
Normal file
BIN
source/Android-lib/res/drawable-mdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
source/Android-lib/res/drawable-xhdpi/ic_launcher.png
Normal file
BIN
source/Android-lib/res/drawable-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
source/Android-lib/res/drawable-xxhdpi/ic_launcher.png
Normal file
BIN
source/Android-lib/res/drawable-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
140
source/Android-lib/res/layout/activity_example.xml
Normal file
140
source/Android-lib/res/layout/activity_example.xml
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/linearLayout1"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TableLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<TableRow
|
||||||
|
android:id="@+id/tableRow1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Tempo %:"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextTempo"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="5"
|
||||||
|
android:inputType="text"
|
||||||
|
android:text="100" >
|
||||||
|
</EditText>
|
||||||
|
</TableRow>
|
||||||
|
|
||||||
|
<TableRow
|
||||||
|
android:id="@+id/tableRow2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Pitch half-steps:"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextPitch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ems="5"
|
||||||
|
android:inputType="text"
|
||||||
|
android:text="-0.318" >
|
||||||
|
</EditText>
|
||||||
|
</TableRow>
|
||||||
|
</TableLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Source file:"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextSrcFileName"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="/sdcard/Download/test.wav"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonSelectSrcFile"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Select" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Output file:"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/editTextOutFileName"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="/sdcard/Download/soundtouch-output.wav"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonSelectOutFile"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Select" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/checkBoxPlay"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="Play the output file after processing!" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonProcess"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="Process file!" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:text="Status console:"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/scrollView1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textViewResult"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:text="@string/hello_world" />
|
||||||
|
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
7
source/Android-lib/res/values/strings.xml
Normal file
7
source/Android-lib/res/values/strings.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<string name="app_name">SoundTouch Example</string>
|
||||||
|
<string name="hello_world">Hello world!</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
20
source/Android-lib/res/values/styles.xml
Normal file
20
source/Android-lib/res/values/styles.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Base application theme, dependent on API level. This theme is replaced
|
||||||
|
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||||
|
-->
|
||||||
|
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
|
||||||
|
<!--
|
||||||
|
Theme customizations available in newer API levels can go in
|
||||||
|
res/values-vXX/styles.xml, while customizations related to
|
||||||
|
backward-compatibility can go here.
|
||||||
|
-->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- Application theme. -->
|
||||||
|
<style name="AppTheme" parent="AppBaseTheme">
|
||||||
|
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
||||||
219
source/Android-lib/src/net/surina/ExampleActivity.java
Normal file
219
source/Android-lib/src/net/surina/ExampleActivity.java
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Example Android Application/Activity that allows processing WAV
|
||||||
|
/// audio files with SoundTouch library
|
||||||
|
///
|
||||||
|
/// Copyright (c) Olli Parviainen
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
package net.surina;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import net.surina.soundtouch.SoundTouch;
|
||||||
|
import net.surina.soundtouchexample.R;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
public class ExampleActivity extends Activity implements OnClickListener
|
||||||
|
{
|
||||||
|
TextView textViewConsole = null;
|
||||||
|
EditText editSourceFile = null;
|
||||||
|
EditText editOutputFile = null;
|
||||||
|
EditText editTempo = null;
|
||||||
|
EditText editPitch = null;
|
||||||
|
CheckBox checkBoxPlay = null;
|
||||||
|
|
||||||
|
StringBuilder consoleText = new StringBuilder();
|
||||||
|
|
||||||
|
|
||||||
|
/// Called when the activity is created
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_example);
|
||||||
|
|
||||||
|
textViewConsole = (TextView)findViewById(R.id.textViewResult);
|
||||||
|
editSourceFile = (EditText)findViewById(R.id.editTextSrcFileName);
|
||||||
|
editOutputFile = (EditText)findViewById(R.id.editTextOutFileName);
|
||||||
|
|
||||||
|
editTempo = (EditText)findViewById(R.id.editTextTempo);
|
||||||
|
editPitch = (EditText)findViewById(R.id.editTextPitch);
|
||||||
|
|
||||||
|
Button buttonFileSrc = (Button)findViewById(R.id.buttonSelectSrcFile);
|
||||||
|
Button buttonFileOutput = (Button)findViewById(R.id.buttonSelectOutFile);
|
||||||
|
Button buttonProcess = (Button)findViewById(R.id.buttonProcess);
|
||||||
|
buttonFileSrc.setOnClickListener(this);
|
||||||
|
buttonFileOutput.setOnClickListener(this);
|
||||||
|
buttonProcess.setOnClickListener(this);
|
||||||
|
|
||||||
|
checkBoxPlay = (CheckBox)findViewById(R.id.checkBoxPlay);
|
||||||
|
|
||||||
|
// Check soundtouch library presence & version
|
||||||
|
checkLibVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Function to append status text onto "console box" on the Activity
|
||||||
|
public void appendToConsole(final String text)
|
||||||
|
{
|
||||||
|
// run on UI thread to avoid conflicts
|
||||||
|
runOnUiThread(new Runnable()
|
||||||
|
{
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
consoleText.append(text);
|
||||||
|
consoleText.append("\n");
|
||||||
|
textViewConsole.setText(consoleText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// print SoundTouch native library version onto console
|
||||||
|
protected void checkLibVersion()
|
||||||
|
{
|
||||||
|
String ver = SoundTouch.getVersionString();
|
||||||
|
appendToConsole("SoundTouch native library version = " + ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Button click handler
|
||||||
|
@Override
|
||||||
|
public void onClick(View arg0)
|
||||||
|
{
|
||||||
|
switch (arg0.getId())
|
||||||
|
{
|
||||||
|
case R.id.buttonSelectSrcFile:
|
||||||
|
case R.id.buttonSelectOutFile:
|
||||||
|
// one of the file select buttons clicked ... we've not just implemented them ;-)
|
||||||
|
Toast.makeText(this, "File selector not implemented, sorry! Enter the file path manually ;-)", Toast.LENGTH_LONG).show();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case R.id.buttonProcess:
|
||||||
|
// button "process" pushed
|
||||||
|
process();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Play audio file
|
||||||
|
protected void playWavFile(String fileName)
|
||||||
|
{
|
||||||
|
File file2play = new File(fileName);
|
||||||
|
Intent i = new Intent();
|
||||||
|
i.setAction(android.content.Intent.ACTION_VIEW);
|
||||||
|
i.setDataAndType(Uri.fromFile(file2play), "audio/wav");
|
||||||
|
startActivity(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Helper class that will execute the SoundTouch processing. As the processing may take
|
||||||
|
/// some time, run it in background thread to avoid hanging of the UI.
|
||||||
|
protected class ProcessTask extends AsyncTask<ProcessTask.Parameters, Integer, Long>
|
||||||
|
{
|
||||||
|
/// Helper class to store the SoundTouch file processing parameters
|
||||||
|
public final class Parameters
|
||||||
|
{
|
||||||
|
String inFileName;
|
||||||
|
String outFileName;
|
||||||
|
float tempo;
|
||||||
|
float pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Function that does the SoundTouch processing
|
||||||
|
public final long doSoundTouchProcessing(Parameters params)
|
||||||
|
{
|
||||||
|
|
||||||
|
SoundTouch st = new SoundTouch();
|
||||||
|
st.setTempo(params.tempo);
|
||||||
|
st.setPitchSemiTones(params.pitch);
|
||||||
|
Log.i("SoundTouch", "process file " + params.inFileName);
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
int res = st.processFile(params.inFileName, params.outFileName);
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
float duration = (endTime - startTime) * 0.001f;
|
||||||
|
|
||||||
|
Log.i("SoundTouch", "process file done, duration = " + duration);
|
||||||
|
appendToConsole("Processing done, duration " + duration + " sec.");
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
String err = SoundTouch.getErrorString();
|
||||||
|
appendToConsole("Failure: " + err);
|
||||||
|
return -1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play file if so is desirable
|
||||||
|
if (checkBoxPlay.isChecked())
|
||||||
|
{
|
||||||
|
playWavFile(params.outFileName);
|
||||||
|
}
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Overloaded function that get called by the system to perform the background processing
|
||||||
|
@Override
|
||||||
|
protected Long doInBackground(Parameters... aparams)
|
||||||
|
{
|
||||||
|
return doSoundTouchProcessing(aparams[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// process a file with SoundTouch. Do the processing using a background processing
|
||||||
|
/// task to avoid hanging of the UI
|
||||||
|
protected void process()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessTask task = new ProcessTask();
|
||||||
|
ProcessTask.Parameters params = task.new Parameters();
|
||||||
|
// parse processing parameters
|
||||||
|
params.inFileName = editSourceFile.getText().toString();
|
||||||
|
params.outFileName = editOutputFile.getText().toString();
|
||||||
|
params.tempo = 0.01f * Float.parseFloat(editTempo.getText().toString());
|
||||||
|
params.pitch = Float.parseFloat(editPitch.getText().toString());
|
||||||
|
|
||||||
|
// update UI about status
|
||||||
|
appendToConsole("Process audio file :" + params.inFileName +" => " + params.outFileName);
|
||||||
|
appendToConsole("Tempo = " + params.tempo);
|
||||||
|
appendToConsole("Pitch adjust = " + params.pitch);
|
||||||
|
|
||||||
|
Toast.makeText(this, "Starting to process file " + params.inFileName + "...", Toast.LENGTH_SHORT).show();
|
||||||
|
|
||||||
|
// start SoundTouch processing in a background thread
|
||||||
|
task.execute(params);
|
||||||
|
// task.doSoundTouchProcessing(params); // this would run processing in main thread
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception exp)
|
||||||
|
{
|
||||||
|
exp.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
79
source/Android-lib/src/net/surina/soundtouch/SoundTouch.java
Normal file
79
source/Android-lib/src/net/surina/soundtouch/SoundTouch.java
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Example class that invokes native SoundTouch routines through the JNI
|
||||||
|
/// interface.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// WWW : http://www.surina.net
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
package net.surina.soundtouch;
|
||||||
|
|
||||||
|
public final class SoundTouch
|
||||||
|
{
|
||||||
|
// Native interface function that returns SoundTouch version string.
|
||||||
|
// This invokes the native c++ routine defined in "soundtouch-jni.cpp".
|
||||||
|
public native final static String getVersionString();
|
||||||
|
|
||||||
|
private native final void setTempo(long handle, float tempo);
|
||||||
|
|
||||||
|
private native final void setPitchSemiTones(long handle, float pitch);
|
||||||
|
|
||||||
|
private native final void setSpeed(long handle, float speed);
|
||||||
|
|
||||||
|
private native final int processFile(long handle, String inputFile, String outputFile);
|
||||||
|
|
||||||
|
public native final static String getErrorString();
|
||||||
|
|
||||||
|
private native final static long newInstance();
|
||||||
|
|
||||||
|
private native final void deleteInstance(long handle);
|
||||||
|
|
||||||
|
long handle = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public SoundTouch()
|
||||||
|
{
|
||||||
|
handle = newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
deleteInstance(handle);
|
||||||
|
handle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setTempo(float tempo)
|
||||||
|
{
|
||||||
|
setTempo(handle, tempo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setPitchSemiTones(float pitch)
|
||||||
|
{
|
||||||
|
setPitchSemiTones(handle, pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setSpeed(float speed)
|
||||||
|
{
|
||||||
|
setSpeed(handle, speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int processFile(String inputFile, String outputFile)
|
||||||
|
{
|
||||||
|
return processFile(handle, inputFile, outputFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Load the native library upon startup
|
||||||
|
static
|
||||||
|
{
|
||||||
|
System.loadLibrary("soundtouch");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,28 +1,25 @@
|
|||||||
## Process this file with automake to create Makefile.in
|
## Process this file with automake to create Makefile.in
|
||||||
##
|
##
|
||||||
## $Id$
|
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
||||||
##
|
##
|
||||||
## Copyright (C) 2003 - David W. Durham
|
## 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
|
||||||
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
## Foundation; either version 2 of the License, or (at your option) any later
|
||||||
##
|
## version.
|
||||||
## 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
|
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
## Foundation; either version 2 of the License, or (at your option) any later
|
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
## version.
|
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
##
|
##
|
||||||
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
## You should have received a copy of the GNU General Public License along with
|
||||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
## Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU General Public License along with
|
include $(top_srcdir)/config/am_include.mk
|
||||||
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
## Place - Suite 330, Boston, MA 02111-1307, USA
|
if SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
|
# build SoundTouchDLL only if float samples used
|
||||||
include $(top_srcdir)/config/am_include.mk
|
SUBDIRS=SoundTouch SoundStretch SoundTouchDLL
|
||||||
|
else
|
||||||
SUBDIRS=SoundTouch SoundStretch
|
SUBDIRS=SoundTouch SoundStretch
|
||||||
|
endif
|
||||||
# set to something if you want other stuff to be included in the distribution tarball
|
|
||||||
#EXTRA_DIST=
|
|
||||||
|
|
||||||
|
|||||||
@ -1,54 +1,50 @@
|
|||||||
## Process this file with automake to create Makefile.in
|
## Process this file with automake to create Makefile.in
|
||||||
##
|
##
|
||||||
## $Id$
|
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
||||||
##
|
##
|
||||||
## Copyright (C) 2003 - David W. Durham
|
## 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
|
||||||
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
## Foundation; either version 2 of the License, or (at your option) any later
|
||||||
##
|
## version.
|
||||||
## 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
|
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
## Foundation; either version 2 of the License, or (at your option) any later
|
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
## version.
|
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
##
|
##
|
||||||
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
## You should have received a copy of the GNU General Public License along with
|
||||||
## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
## Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
##
|
|
||||||
## You should have received a copy of the GNU General Public License along with
|
include $(top_srcdir)/config/am_include.mk
|
||||||
## this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
## Place - Suite 330, Boston, MA 02111-1307, USA
|
|
||||||
|
## bin_PROGRAMS is the macro that tells automake the name of the programs to
|
||||||
include $(top_srcdir)/config/am_include.mk
|
## install in the bin directory (/usr/local/bin) by default. By setting
|
||||||
|
## --prefix= at configure time the user can change this (eg: ./configure
|
||||||
|
## --prefix=/usr will install soundstretch under /usr/bin/soundstretch )
|
||||||
## bin_PROGRAMS is the macro that tells automake the name of the programs to
|
bin_PROGRAMS=soundstretch
|
||||||
## install in the bin directory (/usr/local/bin) by default. By setting
|
|
||||||
## --prefix= at configure time the user can change this (eg: ./configure
|
noinst_HEADERS=RunParameters.h WavFile.h
|
||||||
## --prefix=/usr will install soundstretch under /usr/bin/soundstretch )
|
|
||||||
bin_PROGRAMS=soundstretch
|
# extra files to include in distribution tarball
|
||||||
|
EXTRA_DIST=soundstretch.sln soundstretch.vcxproj
|
||||||
noinst_HEADERS=RunParameters.h WavFile.h
|
|
||||||
|
## for every name listed under bin_PROGRAMS, you have a <prog>_SOURCES. This lists
|
||||||
# extra files to include in distrubution tarball
|
## all the sources in the current directory that are used to build soundstretch.
|
||||||
EXTRA_DIST=soundstretch.dsp soundstretch.dsw soundstretch.sln soundstretch.vcproj
|
soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp
|
||||||
|
|
||||||
## for every name listed under bin_PROGRAMS, you have a <prog>_SOURCES. This lists
|
## soundstretch_LDADD is a list of extras to pass at link time. All the objects
|
||||||
## all the sources in the current directory that are used to build soundstretch.
|
## created by the above soundstretch_SOURCES are automatically linked in, so here I
|
||||||
soundstretch_SOURCES=main.cpp RunParameters.cpp WavFile.cpp
|
## list object files from other directories as well as flags passed to the
|
||||||
|
## linker.
|
||||||
## soundstretch_LDADD is a list of extras to pass at link time. All the objects
|
soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm
|
||||||
## created by the above soundstretch_SOURCES are automatically linked in, so here I
|
|
||||||
## list object files from other directories as well as flags passed to the
|
## linker flags.
|
||||||
## linker.
|
# Linker flag -s disabled to prevent stripping symbols by default
|
||||||
soundstretch_LDADD=../SoundTouch/libSoundTouch.la -lm
|
#soundstretch_LDFLAGS=-s
|
||||||
|
|
||||||
## linker flags.
|
## additional compiler flags
|
||||||
# OP 2011-7-17 Linker flags disabled to prevent stripping symbols by default
|
soundstretch_CXXFLAGS=$(AM_CXXFLAGS)
|
||||||
# soundstretch_LDFLAGS=-s
|
|
||||||
|
#clean-local:
|
||||||
## additional compiler flags
|
# -rm -f additional-files-to-remove-on-make-clean
|
||||||
soundstretch_CXXFLAGS=-O3
|
|
||||||
|
|
||||||
#clean-local:
|
|
||||||
# -rm -f additional-files-to-remove-on-make-clean
|
|
||||||
|
|||||||
@ -1,301 +1,292 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// A class for parsing the 'soundstretch' application command line parameters
|
/// A class for parsing the 'soundstretch' application command line parameters
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include <string>
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include <cstdlib>
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include "RunParameters.h"
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
using namespace std;
|
||||||
|
|
||||||
#include <string>
|
namespace soundstretch
|
||||||
#include <stdlib.h>
|
{
|
||||||
|
|
||||||
#include "RunParameters.h"
|
// Program usage instructions
|
||||||
|
|
||||||
using namespace std;
|
static const char licenseText[] =
|
||||||
|
" LICENSE:\n"
|
||||||
// Program usage instructions
|
" ========\n"
|
||||||
|
" \n"
|
||||||
static const char licenseText[] =
|
" SoundTouch sound processing library\n"
|
||||||
" LICENSE:\n"
|
" Copyright (c) Olli Parviainen\n"
|
||||||
" ========\n"
|
" \n"
|
||||||
" \n"
|
" This library is free software; you can redistribute it and/or\n"
|
||||||
" SoundTouch sound processing library\n"
|
" modify it under the terms of the GNU Lesser General Public\n"
|
||||||
" Copyright (c) Olli Parviainen\n"
|
" License version 2.1 as published by the Free Software Foundation.\n"
|
||||||
" \n"
|
" \n"
|
||||||
" This library is free software; you can redistribute it and/or\n"
|
" This library is distributed in the hope that it will be useful,\n"
|
||||||
" modify it under the terms of the GNU Lesser General Public\n"
|
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
||||||
" License version 2.1 as published by the Free Software Foundation.\n"
|
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
|
||||||
" \n"
|
" Lesser General Public License for more details.\n"
|
||||||
" This library is distributed in the hope that it will be useful,\n"
|
" \n"
|
||||||
" but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
|
" You should have received a copy of the GNU Lesser General Public\n"
|
||||||
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
|
" License along with this library; if not, write to the Free Software\n"
|
||||||
" Lesser General Public License for more details.\n"
|
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
|
||||||
" \n"
|
" \n"
|
||||||
" You should have received a copy of the GNU Lesser General Public\n"
|
"This application is distributed with full source codes; however, if you\n"
|
||||||
" License along with this library; if not, write to the Free Software\n"
|
"didn't receive them, please visit the author's homepage (see the link above).";
|
||||||
" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
|
|
||||||
" \n"
|
static const char whatText[] =
|
||||||
"This application is distributed with full source codes; however, if you\n"
|
"This application processes WAV audio files by modifying the sound tempo,\n"
|
||||||
"didn't receive them, please visit the author's homepage (see the link above).";
|
"pitch and playback rate properties independently from each other.\n"
|
||||||
|
"\n";
|
||||||
static const char whatText[] =
|
|
||||||
"This application processes WAV audio files by modifying the sound tempo,\n"
|
static const char usage[] =
|
||||||
"pitch and playback rate properties independently from each other.\n"
|
"Usage :\n"
|
||||||
"\n";
|
" soundstretch infilename outfilename [switches]\n"
|
||||||
|
"\n"
|
||||||
static const char usage[] =
|
"To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"
|
||||||
"Usage :\n"
|
"\n"
|
||||||
" soundstretch infilename outfilename [switches]\n"
|
"Available switches are:\n"
|
||||||
"\n"
|
" -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n"
|
||||||
"To use standard input/output pipes, give 'stdin' and 'stdout' as filenames.\n"
|
" -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"
|
||||||
"\n"
|
" -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n"
|
||||||
"Available switches are:\n"
|
" -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n"
|
||||||
" -tempo=n : Change sound tempo by n percents (n=-95..+5000 %)\n"
|
" If '=n' is omitted, just detects the BPM rate.\n"
|
||||||
" -pitch=n : Change sound pitch by n semitones (n=-60..+60 semitones)\n"
|
" -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n"
|
||||||
" -rate=n : Change sound rate by n percents (n=-95..+5000 %)\n"
|
" -naa : Don't use anti-alias filtering (gain speed, lose quality)\n"
|
||||||
" -bpm=n : Detect the BPM rate of sound and adjust tempo to meet 'n' BPMs.\n"
|
" -speech : Tune algorithm for speech processing (default is for music)\n"
|
||||||
" If '=n' is omitted, just detects the BPM rate.\n"
|
" -license : Display the program license text (LGPL)\n";
|
||||||
" -quick : Use quicker tempo change algorithm (gain speed, lose quality)\n"
|
|
||||||
" -naa : Don't use anti-alias filtering (gain speed, lose quality)\n"
|
|
||||||
" -speech : Tune algorithm for speech processing (default is for music)\n"
|
// Converts a char into lower case
|
||||||
" -license : Display the program license text (LGPL)\n";
|
static int _toLowerCase(int c)
|
||||||
|
{
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
// Converts a char into lower case
|
{
|
||||||
static int _toLowerCase(int c)
|
c += 'a' - 'A';
|
||||||
{
|
}
|
||||||
if (c >= 'A' && c <= 'Z')
|
return c;
|
||||||
{
|
}
|
||||||
c += 'a' - 'A';
|
|
||||||
}
|
// Constructor
|
||||||
return c;
|
RunParameters::RunParameters(int nParams, const CHARTYPE* paramStr[])
|
||||||
}
|
{
|
||||||
|
int i;
|
||||||
|
int nFirstParam;
|
||||||
// Constructor
|
|
||||||
RunParameters::RunParameters(const int nParams, const char * const paramStr[])
|
if (nParams < 3)
|
||||||
{
|
{
|
||||||
int i;
|
// Too few parameters
|
||||||
int nFirstParam;
|
if (nParams > 1 && paramStr[1][0] == '-' &&
|
||||||
|
_toLowerCase(paramStr[1][1]) == 'l')
|
||||||
if (nParams < 3)
|
{
|
||||||
{
|
// '-license' switch
|
||||||
// Too few parameters
|
throwLicense();
|
||||||
if (nParams > 1 && paramStr[1][0] == '-' &&
|
}
|
||||||
_toLowerCase(paramStr[1][1]) == 'l')
|
string msg = whatText;
|
||||||
{
|
msg += usage;
|
||||||
// '-license' switch
|
throw(msg);
|
||||||
throwLicense();
|
}
|
||||||
}
|
|
||||||
string msg = whatText;
|
// Get input & output file names
|
||||||
msg += usage;
|
inFileName = paramStr[1];
|
||||||
ST_THROW_RT_ERROR(msg.c_str());
|
outFileName = paramStr[2];
|
||||||
}
|
|
||||||
|
if (outFileName[0] == '-')
|
||||||
inFileName = NULL;
|
{
|
||||||
outFileName = NULL;
|
// outputfile name was omitted but other parameter switches given instead
|
||||||
tempoDelta = 0;
|
outFileName = STRING_CONST("");
|
||||||
pitchDelta = 0;
|
nFirstParam = 2;
|
||||||
rateDelta = 0;
|
}
|
||||||
quick = 0;
|
else
|
||||||
noAntiAlias = 0;
|
{
|
||||||
goalBPM = 0;
|
nFirstParam = 3;
|
||||||
speech = FALSE;
|
}
|
||||||
detectBPM = FALSE;
|
|
||||||
|
// parse switch parameters
|
||||||
// Get input & output file names
|
for (i = nFirstParam; i < nParams; i ++)
|
||||||
inFileName = (char*)paramStr[1];
|
{
|
||||||
outFileName = (char*)paramStr[2];
|
parseSwitchParam(paramStr[i]);
|
||||||
|
}
|
||||||
if (outFileName[0] == '-')
|
|
||||||
{
|
checkLimits();
|
||||||
// no outputfile name was given but parameters
|
}
|
||||||
outFileName = NULL;
|
|
||||||
nFirstParam = 2;
|
|
||||||
}
|
// Checks parameter limits
|
||||||
else
|
void RunParameters::checkLimits()
|
||||||
{
|
{
|
||||||
nFirstParam = 3;
|
if (tempoDelta < -95.0f)
|
||||||
}
|
{
|
||||||
|
tempoDelta = -95.0f;
|
||||||
// parse switch parameters
|
}
|
||||||
for (i = nFirstParam; i < nParams; i ++)
|
else if (tempoDelta > 5000.0f)
|
||||||
{
|
{
|
||||||
parseSwitchParam(paramStr[i]);
|
tempoDelta = 5000.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
checkLimits();
|
if (pitchDelta < -60.0f)
|
||||||
}
|
{
|
||||||
|
pitchDelta = -60.0f;
|
||||||
|
}
|
||||||
|
else if (pitchDelta > 60.0f)
|
||||||
// Checks parameter limits
|
{
|
||||||
void RunParameters::checkLimits()
|
pitchDelta = 60.0f;
|
||||||
{
|
}
|
||||||
if (tempoDelta < -95.0f)
|
|
||||||
{
|
if (rateDelta < -95.0f)
|
||||||
tempoDelta = -95.0f;
|
{
|
||||||
}
|
rateDelta = -95.0f;
|
||||||
else if (tempoDelta > 5000.0f)
|
}
|
||||||
{
|
else if (rateDelta > 5000.0f)
|
||||||
tempoDelta = 5000.0f;
|
{
|
||||||
}
|
rateDelta = 5000.0f;
|
||||||
|
}
|
||||||
if (pitchDelta < -60.0f)
|
}
|
||||||
{
|
|
||||||
pitchDelta = -60.0f;
|
// Convert STRING to std::string. Actually needed only if STRING is std::wstring, but conversion penalty is negligible
|
||||||
}
|
std::string convertString(const STRING& str)
|
||||||
else if (pitchDelta > 60.0f)
|
{
|
||||||
{
|
std::string res;
|
||||||
pitchDelta = 60.0f;
|
for (auto c : str)
|
||||||
}
|
{
|
||||||
|
res += (char)c;
|
||||||
if (rateDelta < -95.0f)
|
}
|
||||||
{
|
return res;
|
||||||
rateDelta = -95.0f;
|
}
|
||||||
}
|
|
||||||
else if (rateDelta > 5000.0f)
|
// Unknown switch parameter -- throws an exception with an error message
|
||||||
{
|
void RunParameters::throwIllegalParamExp(const STRING &str) const
|
||||||
rateDelta = 5000.0f;
|
{
|
||||||
}
|
string msg = "ERROR : Illegal parameter \"";
|
||||||
}
|
msg += convertString(str);
|
||||||
|
msg += "\".\n\n";
|
||||||
|
msg += usage;
|
||||||
|
ST_THROW_RT_ERROR(msg);
|
||||||
// Unknown switch parameter -- throws an exception with an error message
|
}
|
||||||
void RunParameters::throwIllegalParamExp(const string &str) const
|
|
||||||
{
|
void RunParameters::throwLicense() const
|
||||||
string msg = "ERROR : Illegal parameter \"";
|
{
|
||||||
msg += str;
|
ST_THROW_RT_ERROR(licenseText);
|
||||||
msg += "\".\n\n";
|
}
|
||||||
msg += usage;
|
|
||||||
ST_THROW_RT_ERROR(msg.c_str());
|
double RunParameters::parseSwitchValue(const STRING& str) const
|
||||||
}
|
{
|
||||||
|
int pos;
|
||||||
|
|
||||||
|
pos = (int)str.find_first_of('=');
|
||||||
void RunParameters::throwLicense() const
|
if (pos < 0)
|
||||||
{
|
{
|
||||||
ST_THROW_RT_ERROR(licenseText);
|
// '=' missing
|
||||||
}
|
throwIllegalParamExp(str);
|
||||||
|
}
|
||||||
|
|
||||||
float RunParameters::parseSwitchValue(const string &str) const
|
// Read numerical parameter value after '='
|
||||||
{
|
return stof(str.substr(pos + 1).c_str());
|
||||||
int pos;
|
}
|
||||||
|
|
||||||
pos = (int)str.find_first_of('=');
|
|
||||||
if (pos < 0)
|
// Interprets a single switch parameter string of format "-switch=xx"
|
||||||
{
|
// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
|
||||||
// '=' missing
|
// switch values into 'params' structure.
|
||||||
throwIllegalParamExp(str);
|
void RunParameters::parseSwitchParam(const STRING& str)
|
||||||
}
|
{
|
||||||
|
int upS;
|
||||||
// Read numerical parameter value after '='
|
|
||||||
return (float)atof(str.substr(pos + 1).c_str());
|
if (str[0] != '-')
|
||||||
}
|
{
|
||||||
|
// leading hyphen missing => not a valid parameter
|
||||||
|
throwIllegalParamExp(str);
|
||||||
// Interprets a single switch parameter string of format "-switch=xx"
|
}
|
||||||
// Valid switches are "-tempo=xx", "-pitch=xx" and "-rate=xx". Stores
|
|
||||||
// switch values into 'params' structure.
|
// Take the first character of switch name & change to lower case
|
||||||
void RunParameters::parseSwitchParam(const string &str)
|
upS = _toLowerCase(str[1]);
|
||||||
{
|
|
||||||
int upS;
|
// interpret the switch name & operate accordingly
|
||||||
|
switch (upS)
|
||||||
if (str[0] != '-')
|
{
|
||||||
{
|
case 't' :
|
||||||
// leading hyphen missing => not a valid parameter
|
// switch '-tempo=xx'
|
||||||
throwIllegalParamExp(str);
|
tempoDelta = parseSwitchValue(str);
|
||||||
}
|
break;
|
||||||
|
|
||||||
// Take the first character of switch name & change to lower case
|
case 'p' :
|
||||||
upS = _toLowerCase(str[1]);
|
// switch '-pitch=xx'
|
||||||
|
pitchDelta = parseSwitchValue(str);
|
||||||
// interpret the switch name & operate accordingly
|
break;
|
||||||
switch (upS)
|
|
||||||
{
|
case 'r' :
|
||||||
case 't' :
|
// switch '-rate=xx'
|
||||||
// switch '-tempo=xx'
|
rateDelta = parseSwitchValue(str);
|
||||||
tempoDelta = parseSwitchValue(str);
|
break;
|
||||||
break;
|
|
||||||
|
case 'b' :
|
||||||
case 'p' :
|
// switch '-bpm=xx'
|
||||||
// switch '-pitch=xx'
|
detectBPM = true;
|
||||||
pitchDelta = parseSwitchValue(str);
|
try
|
||||||
break;
|
{
|
||||||
|
goalBPM = parseSwitchValue(str);
|
||||||
case 'r' :
|
}
|
||||||
// switch '-rate=xx'
|
catch (const runtime_error &)
|
||||||
rateDelta = parseSwitchValue(str);
|
{
|
||||||
break;
|
// illegal or missing bpm value => just calculate bpm
|
||||||
|
goalBPM = 0;
|
||||||
case 'b' :
|
}
|
||||||
// switch '-bpm=xx'
|
break;
|
||||||
detectBPM = TRUE;
|
|
||||||
try
|
case 'q' :
|
||||||
{
|
// switch '-quick'
|
||||||
goalBPM = parseSwitchValue(str);
|
quick = 1;
|
||||||
}
|
break;
|
||||||
catch (const runtime_error)
|
|
||||||
{
|
case 'n' :
|
||||||
// illegal or missing bpm value => just calculate bpm
|
// switch '-naa'
|
||||||
goalBPM = 0;
|
noAntiAlias = 1;
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
case 'l' :
|
||||||
case 'q' :
|
// switch '-license'
|
||||||
// switch '-quick'
|
throwLicense();
|
||||||
quick = 1;
|
break;
|
||||||
break;
|
|
||||||
|
case 's' :
|
||||||
case 'n' :
|
// switch '-speech'
|
||||||
// switch '-naa'
|
speech = true;
|
||||||
noAntiAlias = 1;
|
break;
|
||||||
break;
|
|
||||||
|
default:
|
||||||
case 'l' :
|
// unknown switch
|
||||||
// switch '-license'
|
throwIllegalParamExp(str);
|
||||||
throwLicense();
|
}
|
||||||
break;
|
}
|
||||||
|
|
||||||
case 's' :
|
}
|
||||||
// switch '-speech'
|
|
||||||
speech = TRUE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// unknown switch
|
|
||||||
throwIllegalParamExp(str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,72 +1,70 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// A class for parsing the 'soundstretch' application command line parameters
|
/// A class for parsing the 'soundstretch' application command line parameters
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef RUNPARAMETERS_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define RUNPARAMETERS_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <string>
|
||||||
//
|
#include "STTypes.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "SS_CharTypes.h"
|
||||||
|
#include "WavFile.h"
|
||||||
#ifndef RUNPARAMETERS_H
|
|
||||||
#define RUNPARAMETERS_H
|
namespace soundstretch
|
||||||
|
{
|
||||||
#include "STTypes.h"
|
|
||||||
#include <string>
|
/// Parses command line parameters into program parameters
|
||||||
|
class RunParameters
|
||||||
using namespace std;
|
{
|
||||||
|
private:
|
||||||
/// Parses command line parameters into program parameters
|
void throwIllegalParamExp(const STRING& str) const;
|
||||||
class RunParameters
|
void throwLicense() const;
|
||||||
{
|
void parseSwitchParam(const STRING& str);
|
||||||
private:
|
void checkLimits();
|
||||||
void throwIllegalParamExp(const string &str) const;
|
double parseSwitchValue(const STRING& tr) const;
|
||||||
void throwLicense() const;
|
|
||||||
void parseSwitchParam(const string &str);
|
public:
|
||||||
void checkLimits();
|
STRING inFileName;
|
||||||
float parseSwitchValue(const string &str) const;
|
STRING outFileName;
|
||||||
|
double tempoDelta{ 0 };
|
||||||
public:
|
double pitchDelta{ 0 };
|
||||||
char *inFileName;
|
double rateDelta{ 0 };
|
||||||
char *outFileName;
|
int quick{ 0 };
|
||||||
float tempoDelta;
|
int noAntiAlias{ 0 };
|
||||||
float pitchDelta;
|
double goalBPM{ 0 };
|
||||||
float rateDelta;
|
bool detectBPM{ false };
|
||||||
int quick;
|
bool speech{ false };
|
||||||
int noAntiAlias;
|
|
||||||
float goalBPM;
|
RunParameters(int nParams, const CHARTYPE* paramStr[]);
|
||||||
BOOL detectBPM;
|
};
|
||||||
BOOL speech;
|
|
||||||
|
}
|
||||||
RunParameters(const int nParams, const char * const paramStr[]);
|
|
||||||
};
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
52
source/SoundStretch/SS_CharTypes.h
Normal file
52
source/SoundStretch/SS_CharTypes.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Char type for SoundStretch
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SS_CHARTYPE_H
|
||||||
|
#define SS_CHARTYPE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace soundstretch
|
||||||
|
{
|
||||||
|
#if _WIN32
|
||||||
|
// wide-char types for supporting non-latin file paths in Windows
|
||||||
|
using CHARTYPE = wchar_t;
|
||||||
|
using STRING = std::wstring;
|
||||||
|
#define STRING_CONST(x) (L"" x)
|
||||||
|
#else
|
||||||
|
// gnu platform can natively support UTF-8 paths using "char*" set
|
||||||
|
using CHARTYPE = char;
|
||||||
|
using STRING = std::string;
|
||||||
|
#define STRING_CONST(x) (x)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SS_CHARTYPE_H
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,276 +1,281 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Classes for easy reading & writing of WAV sound files.
|
/// Classes for easy reading & writing of WAV sound files.
|
||||||
///
|
///
|
||||||
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
|
/// For big-endian CPU, define BIG_ENDIAN during compile-time to correctly
|
||||||
/// parse the WAV files with such processors.
|
/// parse the WAV files with such processors.
|
||||||
///
|
///
|
||||||
/// Admittingly, more complete WAV reader routines may exist in public domain, but
|
/// Admittingly, more complete WAV reader routines may exist in public domain, but
|
||||||
/// the reason for 'yet another' one is that those generic WAV reader libraries are
|
/// the reason for 'yet another' one is that those generic WAV reader libraries are
|
||||||
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
|
/// exhaustingly large and cumbersome! Wanted to have something simpler here, i.e.
|
||||||
/// something that's not already larger than rest of the SoundTouch/SoundStretch program...
|
/// something that's not already larger than rest of the SoundTouch/SoundStretch program...
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef WAVFILE_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define WAVFILE_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <cstdio>
|
||||||
//
|
#include <string>
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "SS_CharTypes.h"
|
||||||
|
|
||||||
#ifndef WAVFILE_H
|
namespace soundstretch
|
||||||
#define WAVFILE_H
|
{
|
||||||
|
|
||||||
#include <stdio.h>
|
#ifndef uint
|
||||||
|
typedef unsigned int uint;
|
||||||
#ifndef uint
|
#endif
|
||||||
typedef unsigned int uint;
|
|
||||||
#endif
|
|
||||||
|
/// WAV audio file 'riff' section header
|
||||||
|
typedef struct
|
||||||
/// WAV audio file 'riff' section header
|
{
|
||||||
typedef struct
|
char riff_char[4];
|
||||||
{
|
uint package_len;
|
||||||
char riff_char[4];
|
char wave[4];
|
||||||
int package_len;
|
} WavRiff;
|
||||||
char wave[4];
|
|
||||||
} WavRiff;
|
/// WAV audio file 'format' section header
|
||||||
|
typedef struct
|
||||||
/// WAV audio file 'format' section header
|
{
|
||||||
typedef struct
|
char fmt[4];
|
||||||
{
|
unsigned int format_len;
|
||||||
char fmt[4];
|
unsigned short fixed;
|
||||||
int format_len;
|
unsigned short channel_number;
|
||||||
short fixed;
|
unsigned int sample_rate;
|
||||||
short channel_number;
|
unsigned int byte_rate;
|
||||||
int sample_rate;
|
unsigned short byte_per_sample;
|
||||||
int byte_rate;
|
unsigned short bits_per_sample;
|
||||||
short byte_per_sample;
|
} WavFormat;
|
||||||
short bits_per_sample;
|
|
||||||
} WavFormat;
|
/// WAV audio file 'fact' section header
|
||||||
|
typedef struct
|
||||||
/// WAV audio file 'data' section header
|
{
|
||||||
typedef struct
|
char fact_field[4];
|
||||||
{
|
uint fact_len;
|
||||||
char data_field[4];
|
uint fact_sample_len;
|
||||||
uint data_len;
|
} WavFact;
|
||||||
} WavData;
|
|
||||||
|
/// WAV audio file 'data' section header
|
||||||
|
typedef struct
|
||||||
/// WAV audio file header
|
{
|
||||||
typedef struct
|
char data_field[4];
|
||||||
{
|
uint data_len;
|
||||||
WavRiff riff;
|
} WavData;
|
||||||
WavFormat format;
|
|
||||||
WavData data;
|
|
||||||
} WavHeader;
|
/// WAV audio file header
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
/// Base class for processing WAV audio files.
|
WavRiff riff;
|
||||||
class WavFileBase
|
WavFormat format;
|
||||||
{
|
WavFact fact;
|
||||||
private:
|
WavData data;
|
||||||
/// Conversion working buffer;
|
} WavHeader;
|
||||||
char *convBuff;
|
|
||||||
int convBuffSize;
|
|
||||||
|
/// Base class for processing WAV audio files.
|
||||||
protected:
|
class WavFileBase
|
||||||
WavFileBase();
|
{
|
||||||
virtual ~WavFileBase();
|
private:
|
||||||
|
/// Conversion working buffer;
|
||||||
/// Get pointer to conversion buffer of at min. given size
|
char *convBuff;
|
||||||
void *getConvBuffer(int sizeByte);
|
int convBuffSize;
|
||||||
};
|
|
||||||
|
protected:
|
||||||
|
WavFileBase();
|
||||||
/// Class for reading WAV audio files.
|
virtual ~WavFileBase();
|
||||||
class WavInFile : protected WavFileBase
|
|
||||||
{
|
/// Get pointer to conversion buffer of at min. given size
|
||||||
private:
|
void *getConvBuffer(int sizeByte);
|
||||||
/// File pointer.
|
};
|
||||||
FILE *fptr;
|
|
||||||
|
|
||||||
/// Position within the audio stream
|
/// Class for reading WAV audio files.
|
||||||
long position;
|
class WavInFile : protected WavFileBase
|
||||||
|
{
|
||||||
/// Counter of how many bytes of sample data have been read from the file.
|
private:
|
||||||
long dataRead;
|
/// File pointer.
|
||||||
|
FILE *fptr;
|
||||||
/// WAV header information
|
|
||||||
WavHeader header;
|
/// Counter of how many bytes of sample data have been read from the file.
|
||||||
|
long dataRead;
|
||||||
/// Init the WAV file stream
|
|
||||||
void init();
|
/// WAV header information
|
||||||
|
WavHeader header;
|
||||||
/// Read WAV file headers.
|
|
||||||
/// \return zero if all ok, nonzero if file format is invalid.
|
/// Init the WAV file stream
|
||||||
int readWavHeaders();
|
void init();
|
||||||
|
|
||||||
/// Checks WAV file header tags.
|
/// Read WAV file headers.
|
||||||
/// \return zero if all ok, nonzero if file format is invalid.
|
/// \return zero if all ok, nonzero if file format is invalid.
|
||||||
int checkCharTags() const;
|
int readWavHeaders();
|
||||||
|
|
||||||
/// Reads a single WAV file header block.
|
/// Checks WAV file header tags.
|
||||||
/// \return zero if all ok, nonzero if file format is invalid.
|
/// \return zero if all ok, nonzero if file format is invalid.
|
||||||
int readHeaderBlock();
|
int checkCharTags() const;
|
||||||
|
|
||||||
/// Reads WAV file 'riff' block
|
/// Reads a single WAV file header block.
|
||||||
int readRIFFBlock();
|
/// \return zero if all ok, nonzero if file format is invalid.
|
||||||
|
int readHeaderBlock();
|
||||||
public:
|
|
||||||
/// Constructor: Opens the given WAV file. If the file can't be opened,
|
/// Reads WAV file 'riff' block
|
||||||
/// throws 'runtime_error' exception.
|
int readRIFFBlock();
|
||||||
WavInFile(const char *filename);
|
|
||||||
|
public:
|
||||||
WavInFile(FILE *file);
|
/// Constructor: Opens the given WAV file. If the file can't be opened,
|
||||||
|
/// throws 'runtime_error' exception.
|
||||||
/// Destructor: Closes the file.
|
WavInFile(const STRING& filename);
|
||||||
~WavInFile();
|
|
||||||
|
WavInFile(FILE *file);
|
||||||
/// Rewind to beginning of the file
|
|
||||||
void rewind();
|
/// Destructor: Closes the file.
|
||||||
|
~WavInFile();
|
||||||
/// Get sample rate.
|
|
||||||
uint getSampleRate() const;
|
/// Rewind to beginning of the file
|
||||||
|
void rewind();
|
||||||
/// Get number of bits per sample, i.e. 8 or 16.
|
|
||||||
uint getNumBits() const;
|
/// Get sample rate.
|
||||||
|
uint getSampleRate() const;
|
||||||
/// Get sample data size in bytes. Ahem, this should return same information as
|
|
||||||
/// 'getBytesPerSample'...
|
/// Get number of bits per sample, i.e. 8 or 16.
|
||||||
uint getDataSizeInBytes() const;
|
uint getNumBits() const;
|
||||||
|
|
||||||
/// Get total number of samples in file.
|
/// Get sample data size in bytes. Ahem, this should return same information as
|
||||||
uint getNumSamples() const;
|
/// 'getBytesPerSample'...
|
||||||
|
uint getDataSizeInBytes() const;
|
||||||
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
|
|
||||||
uint getBytesPerSample() const;
|
/// Get total number of samples in file.
|
||||||
|
uint getNumSamples() const;
|
||||||
/// Get number of audio channels in the file (1=mono, 2=stereo)
|
|
||||||
uint getNumChannels() const;
|
/// Get number of bytes per audio sample (e.g. 16bit stereo = 4 bytes/sample)
|
||||||
|
uint getBytesPerSample() const;
|
||||||
/// Get the audio file length in milliseconds
|
|
||||||
uint getLengthMS() const;
|
/// Get number of audio channels in the file (1=mono, 2=stereo)
|
||||||
|
uint getNumChannels() const;
|
||||||
/// Returns how many milliseconds of audio have so far been read from the file
|
|
||||||
///
|
/// Get the audio file length in milliseconds
|
||||||
/// \return elapsed duration in milliseconds
|
uint getLengthMS() const;
|
||||||
uint getElapsedMS() const;
|
|
||||||
|
/// Returns how many milliseconds of audio have so far been read from the file
|
||||||
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
|
///
|
||||||
/// Reads given number of elements from the file or if end-of-file reached, as many
|
/// \return elapsed duration in milliseconds
|
||||||
/// elements as are left in the file.
|
uint getElapsedMS() const;
|
||||||
///
|
|
||||||
/// \return Number of 8-bit integers read from the file.
|
/// Reads audio samples from the WAV file. This routine works only for 8 bit samples.
|
||||||
int read(unsigned char *buffer, int maxElems);
|
/// Reads given number of elements from the file or if end-of-file reached, as many
|
||||||
|
/// elements as are left in the file.
|
||||||
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
|
///
|
||||||
/// of elements from the file or if end-of-file reached, as many elements as are
|
/// \return Number of 8-bit integers read from the file.
|
||||||
/// left in the file.
|
int read(unsigned char *buffer, int maxElems);
|
||||||
///
|
|
||||||
/// \return Number of 16-bit integers read from the file.
|
/// Reads audio samples from the WAV file to 16 bit integer format. Reads given number
|
||||||
int read(short *buffer, ///< Pointer to buffer where to read data.
|
/// of elements from the file or if end-of-file reached, as many elements as are
|
||||||
int maxElems ///< Size of 'buffer' array (number of array elements).
|
/// left in the file.
|
||||||
);
|
///
|
||||||
|
/// \return Number of 16-bit integers read from the file.
|
||||||
/// Reads audio samples from the WAV file to floating point format, converting
|
int read(short *buffer, ///< Pointer to buffer where to read data.
|
||||||
/// sample values to range [-1,1[. Reads given number of elements from the file
|
int maxElems ///< Size of 'buffer' array (number of array elements).
|
||||||
/// or if end-of-file reached, as many elements as are left in the file.
|
);
|
||||||
/// Notice that reading in float format supports 8/16/24/32bit sample formats.
|
|
||||||
///
|
/// Reads audio samples from the WAV file to floating point format, converting
|
||||||
/// \return Number of elements read from the file.
|
/// sample values to range [-1,1[. Reads given number of elements from the file
|
||||||
int read(float *buffer, ///< Pointer to buffer where to read data.
|
/// or if end-of-file reached, as many elements as are left in the file.
|
||||||
int maxElems ///< Size of 'buffer' array (number of array elements).
|
/// Notice that reading in float format supports 8/16/24/32bit sample formats.
|
||||||
);
|
///
|
||||||
|
/// \return Number of elements read from the file.
|
||||||
/// Check end-of-file.
|
int read(float *buffer, ///< Pointer to buffer where to read data.
|
||||||
///
|
int maxElems ///< Size of 'buffer' array (number of array elements).
|
||||||
/// \return Nonzero if end-of-file reached.
|
);
|
||||||
int eof() const;
|
|
||||||
};
|
/// Check end-of-file.
|
||||||
|
///
|
||||||
|
/// \return Nonzero if end-of-file reached.
|
||||||
|
int eof() const;
|
||||||
/// Class for writing WAV audio files.
|
};
|
||||||
class WavOutFile : protected WavFileBase
|
|
||||||
{
|
|
||||||
private:
|
/// Class for writing WAV audio files.
|
||||||
/// Pointer to the WAV file
|
class WavOutFile : protected WavFileBase
|
||||||
FILE *fptr;
|
{
|
||||||
|
private:
|
||||||
/// WAV file header data.
|
/// Pointer to the WAV file
|
||||||
WavHeader header;
|
FILE *fptr;
|
||||||
|
|
||||||
/// Counter of how many bytes have been written to the file so far.
|
/// WAV file header data.
|
||||||
int bytesWritten;
|
WavHeader header;
|
||||||
|
|
||||||
/// Fills in WAV file header information.
|
/// Counter of how many bytes have been written to the file so far.
|
||||||
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
|
int bytesWritten;
|
||||||
|
|
||||||
/// Finishes the WAV file header by supplementing information of amount of
|
/// Fills in WAV file header information.
|
||||||
/// data written to file etc
|
void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
|
||||||
void finishHeader();
|
|
||||||
|
/// Finishes the WAV file header by supplementing information of amount of
|
||||||
/// Writes the WAV file header.
|
/// data written to file etc
|
||||||
void writeHeader();
|
void finishHeader();
|
||||||
|
|
||||||
public:
|
/// Writes the WAV file header.
|
||||||
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
|
void writeHeader();
|
||||||
/// if file creation fails.
|
|
||||||
WavOutFile(const char *fileName, ///< Filename
|
public:
|
||||||
int sampleRate, ///< Sample rate (e.g. 44100 etc)
|
/// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
|
||||||
int bits, ///< Bits per sample (8 or 16 bits)
|
/// if file creation fails.
|
||||||
int channels ///< Number of channels (1=mono, 2=stereo)
|
WavOutFile(const STRING& fileName, ///< Filename
|
||||||
);
|
int sampleRate, ///< Sample rate (e.g. 44100 etc)
|
||||||
|
int bits, ///< Bits per sample (8 or 16 bits)
|
||||||
WavOutFile(FILE *file, int sampleRate, int bits, int channels);
|
int channels ///< Number of channels (1=mono, 2=stereo)
|
||||||
|
);
|
||||||
/// Destructor: Finalizes & closes the WAV file.
|
|
||||||
~WavOutFile();
|
WavOutFile(FILE *file, int sampleRate, int bits, int channels);
|
||||||
|
|
||||||
/// Write data to WAV file. This function works only with 8bit samples.
|
/// Destructor: Finalizes & closes the WAV file.
|
||||||
/// Throws a 'runtime_error' exception if writing to file fails.
|
~WavOutFile();
|
||||||
void write(const unsigned char *buffer, ///< Pointer to sample data buffer.
|
|
||||||
int numElems ///< How many array items are to be written to file.
|
/// Write data to WAV file. This function works only with 8bit samples.
|
||||||
);
|
/// Throws a 'runtime_error' exception if writing to file fails.
|
||||||
|
void write(const unsigned char *buffer, ///< Pointer to sample data buffer.
|
||||||
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to
|
int numElems ///< How many array items are to be written to file.
|
||||||
/// file fails.
|
);
|
||||||
void write(const short *buffer, ///< Pointer to sample data buffer.
|
|
||||||
int numElems ///< How many array items are to be written to file.
|
/// Write data to WAV file. Throws a 'runtime_error' exception if writing to
|
||||||
);
|
/// file fails.
|
||||||
|
void write(const short *buffer, ///< Pointer to sample data buffer.
|
||||||
/// Write data to WAV file in floating point format, saturating sample values to range
|
int numElems ///< How many array items are to be written to file.
|
||||||
/// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails.
|
);
|
||||||
void write(const float *buffer, ///< Pointer to sample data buffer.
|
|
||||||
int numElems ///< How many array items are to be written to file.
|
/// Write data to WAV file in floating point format, saturating sample values to range
|
||||||
);
|
/// [-1..+1[. Throws a 'runtime_error' exception if writing to file fails.
|
||||||
};
|
void write(const float *buffer, ///< Pointer to sample data buffer.
|
||||||
|
int numElems ///< How many array items are to be written to file.
|
||||||
#endif
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,333 +1,321 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// SoundStretch main routine.
|
/// SoundStretch main routine.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include <iostream>
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include <memory>
|
||||||
// License along with this library; if not, write to the Free Software
|
#include <stdexcept>
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <string>
|
||||||
//
|
#include <cstdio>
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include <ctime>
|
||||||
|
#include "RunParameters.h"
|
||||||
#include <stdexcept>
|
#include "WavFile.h"
|
||||||
#include <stdio.h>
|
#include "SoundTouch.h"
|
||||||
#include <string.h>
|
#include "BPMDetect.h"
|
||||||
#include <time.h>
|
|
||||||
#include "RunParameters.h"
|
using namespace soundtouch;
|
||||||
#include "WavFile.h"
|
using namespace std;
|
||||||
#include "SoundTouch.h"
|
|
||||||
#include "BPMDetect.h"
|
namespace soundstretch
|
||||||
|
{
|
||||||
using namespace soundtouch;
|
|
||||||
using namespace std;
|
// Processing chunk size (size chosen to be divisible by 2, 4, 6, 8, 10, 12, 14, 16 channels ...)
|
||||||
|
#define BUFF_SIZE 6720
|
||||||
// Processing chunk size
|
|
||||||
#define BUFF_SIZE 2048
|
#if _WIN32
|
||||||
|
#include <io.h>
|
||||||
#if _WIN32
|
#include <fcntl.h>
|
||||||
#include <io.h>
|
|
||||||
#include <fcntl.h>
|
// Macro for Win32 standard input/output stream support: Sets a file stream into binary mode
|
||||||
|
#define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY))
|
||||||
// Macro for Win32 standard input/output stream support: Sets a file stream into binary mode
|
#else
|
||||||
#define SET_STREAM_TO_BIN_MODE(f) (_setmode(_fileno(f), _O_BINARY))
|
// Not needed for GNU environment...
|
||||||
#else
|
#define SET_STREAM_TO_BIN_MODE(f) {}
|
||||||
// Not needed for GNU environment...
|
#endif
|
||||||
#define SET_STREAM_TO_BIN_MODE(f) {}
|
|
||||||
#endif
|
|
||||||
|
static const char _helloText[] =
|
||||||
|
"\n"
|
||||||
static const char _helloText[] =
|
" SoundStretch v%s - Copyright (c) Olli Parviainen\n"
|
||||||
"\n"
|
"=========================================================\n"
|
||||||
" SoundStretch v%s - Written by Olli Parviainen 2001 - 2012\n"
|
"author e-mail: <oparviai"
|
||||||
"==================================================================\n"
|
"@"
|
||||||
"author e-mail: <oparviai"
|
"iki.fi> - WWW: http://www.surina.net/soundtouch\n"
|
||||||
"@"
|
"\n"
|
||||||
"iki.fi> - WWW: http://www.surina.net/soundtouch\n"
|
"This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"
|
||||||
"\n"
|
"more information.\n"
|
||||||
"This program is subject to (L)GPL license. Run \"soundstretch -license\" for\n"
|
"\n";
|
||||||
"more information.\n"
|
|
||||||
"\n";
|
static void openFiles(unique_ptr<WavInFile>& inFile, unique_ptr<WavOutFile>& outFile, const RunParameters& params)
|
||||||
|
{
|
||||||
static void openFiles(WavInFile **inFile, WavOutFile **outFile, const RunParameters *params)
|
if (params.inFileName == STRING_CONST("stdin"))
|
||||||
{
|
{
|
||||||
int bits, samplerate, channels;
|
// used 'stdin' as input file
|
||||||
|
SET_STREAM_TO_BIN_MODE(stdin);
|
||||||
if (strcmp(params->inFileName, "stdin") == 0)
|
inFile = make_unique<WavInFile>(stdin);
|
||||||
{
|
}
|
||||||
// used 'stdin' as input file
|
else
|
||||||
SET_STREAM_TO_BIN_MODE(stdin);
|
{
|
||||||
*inFile = new WavInFile(stdin);
|
// open input file...
|
||||||
}
|
inFile = make_unique<WavInFile>(params.inFileName.c_str());
|
||||||
else
|
}
|
||||||
{
|
|
||||||
// open input file...
|
// ... open output file with same sound parameters
|
||||||
*inFile = new WavInFile(params->inFileName);
|
const int bits = (int)inFile->getNumBits();
|
||||||
}
|
const int samplerate = (int)inFile->getSampleRate();
|
||||||
|
const int channels = (int)inFile->getNumChannels();
|
||||||
// ... open output file with same sound parameters
|
|
||||||
bits = (int)(*inFile)->getNumBits();
|
if (!params.outFileName.empty())
|
||||||
samplerate = (int)(*inFile)->getSampleRate();
|
{
|
||||||
channels = (int)(*inFile)->getNumChannels();
|
if (params.outFileName == STRING_CONST("stdout"))
|
||||||
|
{
|
||||||
if (params->outFileName)
|
SET_STREAM_TO_BIN_MODE(stdout);
|
||||||
{
|
outFile = make_unique<WavOutFile>(stdout, samplerate, bits, channels);
|
||||||
if (strcmp(params->outFileName, "stdout") == 0)
|
}
|
||||||
{
|
else
|
||||||
SET_STREAM_TO_BIN_MODE(stdout);
|
{
|
||||||
*outFile = new WavOutFile(stdout, samplerate, bits, channels);
|
outFile = make_unique<WavOutFile>(params.outFileName.c_str(), samplerate, bits, channels);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
*outFile = new WavOutFile(params->outFileName, samplerate, bits, channels);
|
|
||||||
}
|
|
||||||
}
|
// Sets the 'SoundTouch' object up according to input file sound format &
|
||||||
else
|
// command line parameters
|
||||||
{
|
static void setup(SoundTouch& soundTouch, const WavInFile& inFile, const RunParameters& params)
|
||||||
*outFile = NULL;
|
{
|
||||||
}
|
const int sampleRate = (int)inFile.getSampleRate();
|
||||||
}
|
const int channels = (int)inFile.getNumChannels();
|
||||||
|
soundTouch.setSampleRate(sampleRate);
|
||||||
|
soundTouch.setChannels(channels);
|
||||||
|
|
||||||
// Sets the 'SoundTouch' object up according to input file sound format &
|
soundTouch.setTempoChange(params.tempoDelta);
|
||||||
// command line parameters
|
soundTouch.setPitchSemiTones(params.pitchDelta);
|
||||||
static void setup(SoundTouch *pSoundTouch, const WavInFile *inFile, const RunParameters *params)
|
soundTouch.setRateChange(params.rateDelta);
|
||||||
{
|
|
||||||
int sampleRate;
|
soundTouch.setSetting(SETTING_USE_QUICKSEEK, params.quick);
|
||||||
int channels;
|
soundTouch.setSetting(SETTING_USE_AA_FILTER, !(params.noAntiAlias));
|
||||||
|
|
||||||
sampleRate = (int)inFile->getSampleRate();
|
if (params.speech)
|
||||||
channels = (int)inFile->getNumChannels();
|
{
|
||||||
pSoundTouch->setSampleRate(sampleRate);
|
// use settings for speech processing
|
||||||
pSoundTouch->setChannels(channels);
|
soundTouch.setSetting(SETTING_SEQUENCE_MS, 40);
|
||||||
|
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
|
||||||
pSoundTouch->setTempoChange(params->tempoDelta);
|
soundTouch.setSetting(SETTING_OVERLAP_MS, 8);
|
||||||
pSoundTouch->setPitchSemiTones(params->pitchDelta);
|
fprintf(stderr, "Tune processing parameters for speech processing.\n");
|
||||||
pSoundTouch->setRateChange(params->rateDelta);
|
}
|
||||||
|
|
||||||
pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, params->quick);
|
// print processing information
|
||||||
pSoundTouch->setSetting(SETTING_USE_AA_FILTER, !(params->noAntiAlias));
|
if (!params.outFileName.empty())
|
||||||
|
{
|
||||||
if (params->speech)
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
{
|
fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
|
||||||
// use settings for speech processing
|
#else
|
||||||
pSoundTouch->setSetting(SETTING_SEQUENCE_MS, 40);
|
#ifndef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
pSoundTouch->setSetting(SETTING_SEEKWINDOW_MS, 15);
|
#error "Sampletype not defined"
|
||||||
pSoundTouch->setSetting(SETTING_OVERLAP_MS, 8);
|
#endif
|
||||||
fprintf(stderr, "Tune processing parameters for speech processing.\n");
|
fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");
|
||||||
}
|
#endif
|
||||||
|
// print processing information only if outFileName given i.e. some processing will happen
|
||||||
// print processing information
|
fprintf(stderr, "Processing the file with the following changes:\n");
|
||||||
if (params->outFileName)
|
fprintf(stderr, " tempo change = %+lg %%\n", params.tempoDelta);
|
||||||
{
|
fprintf(stderr, " pitch change = %+lg semitones\n", params.pitchDelta);
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
fprintf(stderr, " rate change = %+lg %%\n\n", params.rateDelta);
|
||||||
fprintf(stderr, "Uses 16bit integer sample type in processing.\n\n");
|
fprintf(stderr, "Working...");
|
||||||
#else
|
}
|
||||||
#ifndef SOUNDTOUCH_FLOAT_SAMPLES
|
else
|
||||||
#error "Sampletype not defined"
|
{
|
||||||
#endif
|
// outFileName not given
|
||||||
fprintf(stderr, "Uses 32bit floating point sample type in processing.\n\n");
|
fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n");
|
||||||
#endif
|
}
|
||||||
// print processing information only if outFileName given i.e. some processing will happen
|
|
||||||
fprintf(stderr, "Processing the file with the following changes:\n");
|
fflush(stderr);
|
||||||
fprintf(stderr, " tempo change = %+g %%\n", params->tempoDelta);
|
}
|
||||||
fprintf(stderr, " pitch change = %+g semitones\n", params->pitchDelta);
|
|
||||||
fprintf(stderr, " rate change = %+g %%\n\n", params->rateDelta);
|
|
||||||
fprintf(stderr, "Working...");
|
// Processes the sound
|
||||||
}
|
static void process(SoundTouch& soundTouch, WavInFile& inFile, WavOutFile& outFile)
|
||||||
else
|
{
|
||||||
{
|
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
||||||
// outFileName not given
|
int nSamples;
|
||||||
fprintf(stderr, "Warning: output file name missing, won't output anything.\n\n");
|
|
||||||
}
|
const int nChannels = (int)inFile.getNumChannels();
|
||||||
|
assert(nChannels > 0);
|
||||||
fflush(stderr);
|
const int buffSizeSamples = BUFF_SIZE / nChannels;
|
||||||
}
|
|
||||||
|
// Process samples read from the input file
|
||||||
|
while (inFile.eof() == 0)
|
||||||
|
{
|
||||||
// Processes the sound
|
// Read a chunk of samples from the input file
|
||||||
static void process(SoundTouch *pSoundTouch, WavInFile *inFile, WavOutFile *outFile)
|
const int num = inFile.read(sampleBuffer, BUFF_SIZE);
|
||||||
{
|
int nSamples = num / (int)inFile.getNumChannels();
|
||||||
int nSamples;
|
|
||||||
int nChannels;
|
// Feed the samples into SoundTouch processor
|
||||||
int buffSizeSamples;
|
soundTouch.putSamples(sampleBuffer, nSamples);
|
||||||
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
|
||||||
|
// Read ready samples from SoundTouch processor & write them output file.
|
||||||
if ((inFile == NULL) || (outFile == NULL)) return; // nothing to do.
|
// NOTES:
|
||||||
|
// - 'receiveSamples' doesn't necessarily return any samples at all
|
||||||
nChannels = (int)inFile->getNumChannels();
|
// during some rounds!
|
||||||
assert(nChannels > 0);
|
// - On the other hand, during some round 'receiveSamples' may have more
|
||||||
buffSizeSamples = BUFF_SIZE / nChannels;
|
// ready samples than would fit into 'sampleBuffer', and for this reason
|
||||||
|
// the 'receiveSamples' call is iterated for as many times as it
|
||||||
// Process samples read from the input file
|
// outputs samples.
|
||||||
while (inFile->eof() == 0)
|
do
|
||||||
{
|
{
|
||||||
int num;
|
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
|
||||||
|
outFile.write(sampleBuffer, nSamples * nChannels);
|
||||||
// Read a chunk of samples from the input file
|
} while (nSamples != 0);
|
||||||
num = inFile->read(sampleBuffer, BUFF_SIZE);
|
}
|
||||||
nSamples = num / (int)inFile->getNumChannels();
|
|
||||||
|
// Now the input file is processed, yet 'flush' few last samples that are
|
||||||
// Feed the samples into SoundTouch processor
|
// hiding in the SoundTouch's internal processing pipeline.
|
||||||
pSoundTouch->putSamples(sampleBuffer, nSamples);
|
soundTouch.flush();
|
||||||
|
do
|
||||||
// Read ready samples from SoundTouch processor & write them output file.
|
{
|
||||||
// NOTES:
|
nSamples = soundTouch.receiveSamples(sampleBuffer, buffSizeSamples);
|
||||||
// - 'receiveSamples' doesn't necessarily return any samples at all
|
outFile.write(sampleBuffer, nSamples * nChannels);
|
||||||
// during some rounds!
|
} while (nSamples != 0);
|
||||||
// - On the other hand, during some round 'receiveSamples' may have more
|
}
|
||||||
// ready samples than would fit into 'sampleBuffer', and for this reason
|
|
||||||
// the 'receiveSamples' call is iterated for as many times as it
|
|
||||||
// outputs samples.
|
// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary
|
||||||
do
|
static void detectBPM(WavInFile& inFile, RunParameters& params)
|
||||||
{
|
{
|
||||||
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
BPMDetect bpm(inFile.getNumChannels(), inFile.getSampleRate());
|
||||||
outFile->write(sampleBuffer, nSamples * nChannels);
|
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
||||||
} while (nSamples != 0);
|
|
||||||
}
|
// detect bpm rate
|
||||||
|
fprintf(stderr, "Detecting BPM rate...");
|
||||||
// Now the input file is processed, yet 'flush' few last samples that are
|
fflush(stderr);
|
||||||
// hiding in the SoundTouch's internal processing pipeline.
|
|
||||||
pSoundTouch->flush();
|
const int nChannels = (int)inFile.getNumChannels();
|
||||||
do
|
int readSize = BUFF_SIZE - BUFF_SIZE % nChannels; // round read size down to multiple of num.channels
|
||||||
{
|
|
||||||
nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
|
// Process the 'inFile' in small blocks, repeat until whole file has
|
||||||
outFile->write(sampleBuffer, nSamples * nChannels);
|
// been processed
|
||||||
} while (nSamples != 0);
|
while (inFile.eof() == 0)
|
||||||
}
|
{
|
||||||
|
// Read sample data from input file
|
||||||
|
const int num = inFile.read(sampleBuffer, readSize);
|
||||||
|
|
||||||
// Detect BPM rate of inFile and adjust tempo setting accordingly if necessary
|
// Enter the new samples to the bpm analyzer class
|
||||||
static void detectBPM(WavInFile *inFile, RunParameters *params)
|
const int samples = num / nChannels;
|
||||||
{
|
bpm.inputSamples(sampleBuffer, samples);
|
||||||
float bpmValue;
|
}
|
||||||
int nChannels;
|
|
||||||
BPMDetect bpm(inFile->getNumChannels(), inFile->getSampleRate());
|
// Now the whole song data has been analyzed. Read the resulting bpm.
|
||||||
SAMPLETYPE sampleBuffer[BUFF_SIZE];
|
const float bpmValue = bpm.getBpm();
|
||||||
|
fprintf(stderr, "Done!\n");
|
||||||
// detect bpm rate
|
|
||||||
fprintf(stderr, "Detecting BPM rate...");
|
// rewind the file after bpm detection
|
||||||
fflush(stderr);
|
inFile.rewind();
|
||||||
|
|
||||||
nChannels = (int)inFile->getNumChannels();
|
if (bpmValue > 0)
|
||||||
assert(BUFF_SIZE % nChannels == 0);
|
{
|
||||||
|
fprintf(stderr, "Detected BPM rate %.1lf\n\n", bpmValue);
|
||||||
// Process the 'inFile' in small blocks, repeat until whole file has
|
}
|
||||||
// been processed
|
else
|
||||||
while (inFile->eof() == 0)
|
{
|
||||||
{
|
fprintf(stderr, "Couldn't detect BPM rate.\n\n");
|
||||||
int num, samples;
|
return;
|
||||||
|
}
|
||||||
// Read sample data from input file
|
|
||||||
num = inFile->read(sampleBuffer, BUFF_SIZE);
|
if (params.goalBPM > 0)
|
||||||
|
{
|
||||||
// Enter the new samples to the bpm analyzer class
|
// adjust tempo to given bpm
|
||||||
samples = num / nChannels;
|
params.tempoDelta = (params.goalBPM / bpmValue - 1.0f) * 100.0f;
|
||||||
bpm.inputSamples(sampleBuffer, samples);
|
fprintf(stderr, "The file will be converted to %.1lf BPM\n\n", params.goalBPM);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Now the whole song data has been analyzed. Read the resulting bpm.
|
|
||||||
bpmValue = bpm.getBpm();
|
void printHelloText()
|
||||||
fprintf(stderr, "Done!\n");
|
{
|
||||||
|
SoundTouch soundTouch;
|
||||||
// rewind the file after bpm detection
|
fprintf(stderr, _helloText, soundTouch.getVersionString());
|
||||||
inFile->rewind();
|
}
|
||||||
|
|
||||||
if (bpmValue > 0)
|
void ss_main(RunParameters& params)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Detected BPM rate %.1f\n\n", bpmValue);
|
unique_ptr<WavInFile> inFile;
|
||||||
}
|
unique_ptr<WavOutFile> outFile;
|
||||||
else
|
SoundTouch soundTouch;
|
||||||
{
|
|
||||||
fprintf(stderr, "Couldn't detect BPM rate.\n\n");
|
// Open input & output files
|
||||||
return;
|
openFiles(inFile, outFile, params);
|
||||||
}
|
|
||||||
|
if (params.detectBPM == true)
|
||||||
if (params->goalBPM > 0)
|
{
|
||||||
{
|
// detect sound BPM (and adjust processing parameters
|
||||||
// adjust tempo to given bpm
|
// accordingly if necessary)
|
||||||
params->tempoDelta = (params->goalBPM / bpmValue - 1.0f) * 100.0f;
|
detectBPM(*inFile, params);
|
||||||
fprintf(stderr, "The file will be converted to %.1f BPM\n\n", params->goalBPM);
|
}
|
||||||
}
|
|
||||||
}
|
// Setup the 'SoundTouch' object for processing the sound
|
||||||
|
setup(soundTouch, *inFile, params);
|
||||||
|
|
||||||
|
// clock_t cs = clock(); // for benchmarking processing duration
|
||||||
int main(const int nParams, const char * const paramStr[])
|
// Process the sound
|
||||||
{
|
if (inFile && outFile)
|
||||||
WavInFile *inFile;
|
{
|
||||||
WavOutFile *outFile;
|
process(soundTouch, *inFile, *outFile);
|
||||||
RunParameters *params;
|
}
|
||||||
SoundTouch soundTouch;
|
// clock_t ce = clock(); // for benchmarking processing duration
|
||||||
|
// printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC);
|
||||||
fprintf(stderr, _helloText, SoundTouch::getVersionString());
|
|
||||||
|
fprintf(stderr, "Done!\n");
|
||||||
try
|
}
|
||||||
{
|
|
||||||
// Parse command line parameters
|
}
|
||||||
params = new RunParameters(nParams, paramStr);
|
|
||||||
|
#if _WIN32
|
||||||
// Open input & output files
|
int wmain(int argc, const wchar_t* args[])
|
||||||
openFiles(&inFile, &outFile, params);
|
#else
|
||||||
|
int main(int argc, const char* args[])
|
||||||
if (params->detectBPM == TRUE)
|
#endif
|
||||||
{
|
{
|
||||||
// detect sound BPM (and adjust processing parameters
|
try
|
||||||
// accordingly if necessary)
|
{
|
||||||
detectBPM(inFile, params);
|
soundstretch::printHelloText();
|
||||||
}
|
soundstretch::RunParameters params(argc, args);
|
||||||
|
soundstretch::ss_main(params);
|
||||||
// Setup the 'SoundTouch' object for processing the sound
|
}
|
||||||
setup(&soundTouch, inFile, params);
|
catch (const runtime_error& e)
|
||||||
|
{
|
||||||
// clock_t cs = clock(); // for benchmarking processing duration
|
fprintf(stderr, "%s\n", e.what());
|
||||||
// Process the sound
|
return -1;
|
||||||
process(&soundTouch, inFile, outFile);
|
}
|
||||||
// clock_t ce = clock(); // for benchmarking processing duration
|
catch (const string& e)
|
||||||
// printf("duration: %lf\n", (double)(ce-cs)/CLOCKS_PER_SEC);
|
{
|
||||||
|
fprintf(stderr, "%s\n", e.c_str());
|
||||||
// Close WAV file handles & dispose of the objects
|
return -1;
|
||||||
delete inFile;
|
}
|
||||||
delete outFile;
|
return 0;
|
||||||
delete params;
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Done!\n");
|
|
||||||
}
|
|
||||||
catch (const runtime_error &e)
|
|
||||||
{
|
|
||||||
// An exception occurred during processing, display an error message
|
|
||||||
fprintf(stderr, "%s\n", e.what());
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,137 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="soundstretch" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
|
||||||
|
|
||||||
CFG=soundstretch - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "soundstretch.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "soundstretch.mak" CFG="soundstretch - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "soundstretch - Win32 Release" (based on "Win32 (x86) Console Application")
|
|
||||||
!MESSAGE "soundstretch - Win32 Debug" (based on "Win32 (x86) Console Application")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "soundstretch - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
|
|
||||||
# SUBTRACT CPP /YX
|
|
||||||
# ADD BASE RSC /l 0x40b /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x40b /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
|
||||||
# ADD LINK32 SoundTouch.lib /nologo /subsystem:console /profile /map /debug /machine:I386 /libpath:"..\..\lib"
|
|
||||||
# Begin Special Build Tool
|
|
||||||
SOURCE="$(InputPath)"
|
|
||||||
PostBuild_Cmds=copy Release\soundstretch.exe ..\..\bin\
|
|
||||||
# End Special Build Tool
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "soundstretch - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Ignore_Export_Lib 0
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /Zp16 /W3 /Gm /GX /ZI /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /GZ /c
|
|
||||||
# SUBTRACT CPP /YX
|
|
||||||
# ADD BASE RSC /l 0x40b /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x40b /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LINK32=link.exe
|
|
||||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
|
||||||
# ADD LINK32 SoundTouchD.lib /nologo /subsystem:console /map /debug /machine:I386 /nodefaultlib:"libc" /out:"Debug/soundstretchD.exe" /pdbtype:sept /libpath:"..\..\lib"
|
|
||||||
# SUBTRACT LINK32 /pdb:none
|
|
||||||
# Begin Special Build Tool
|
|
||||||
SOURCE="$(InputPath)"
|
|
||||||
PostBuild_Cmds=copy Debug\soundstretchD.exe ..\..\bin\
|
|
||||||
# End Special Build Tool
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "soundstretch - Win32 Release"
|
|
||||||
# Name "soundstretch - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\main.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\RunParameters.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\WavFile.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\RunParameters.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\include\SoundTouch.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\..\include\STTypes.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\WavFile.h
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Resource Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
|
||||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "SoundTouch"=..\SoundTouch\SoundTouch.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "soundstretch"=.\soundstretch.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
Begin Project Dependency
|
|
||||||
Project_Dep_Name SoundTouch
|
|
||||||
End Project Dependency
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Global:
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<3>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
@ -1,32 +1,37 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "soundstretch", "soundstretch.vcproj", "{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}"
|
# Visual Studio 14
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
VisualStudioVersion = 14.0.23107.0
|
||||||
{68A5DD20-7057-448B-8FE0-B6AC8D205509} = {68A5DD20-7057-448B-8FE0-B6AC8D205509}
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
EndProjectSection
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "soundstretch", "soundstretch.vcxproj", "{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "..\SoundTouch\SoundTouch.vcproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "..\SoundTouch\SoundTouch.vcxproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfiguration) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug = Debug
|
Debug|Win32 = Debug|Win32
|
||||||
Release = Release
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectDependencies) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release|x64.Build.0 = Release|x64
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfiguration) = postSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug.ActiveCfg = Debug|Win32
|
HideSolutionNode = FALSE
|
||||||
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Debug.Build.0 = Debug|Win32
|
|
||||||
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release.ActiveCfg = Release|Win32
|
|
||||||
{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}.Release.Build.0 = Release|Win32
|
|
||||||
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug.ActiveCfg = Debug|Win32
|
|
||||||
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug.Build.0 = Debug|Win32
|
|
||||||
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release.ActiveCfg = Release|Win32
|
|
||||||
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release.Build.0 = Release|Win32
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@ -1,235 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="7.10"
|
|
||||||
Name="soundstretch"
|
|
||||||
SccProjectName=""
|
|
||||||
SccLocalPath="">
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"/>
|
|
||||||
</Platforms>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory=".\Debug"
|
|
||||||
IntermediateDirectory=".\Debug"
|
|
||||||
ConfigurationType="1"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="..\..\include"
|
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="5"
|
|
||||||
StructMemberAlignment="5"
|
|
||||||
PrecompiledHeaderFile=".\Debug/soundstretch.pch"
|
|
||||||
AssemblerListingLocation=".\Debug/"
|
|
||||||
ObjectFile=".\Debug/"
|
|
||||||
ProgramDataBaseFileName=".\Debug/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="TRUE"
|
|
||||||
DebugInformationFormat="4"
|
|
||||||
CompileAs="0"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="SoundTouchD.lib"
|
|
||||||
OutputFile="Debug/soundstretchD.exe"
|
|
||||||
LinkIncremental="2"
|
|
||||||
SuppressStartupBanner="TRUE"
|
|
||||||
AdditionalLibraryDirectories="..\..\lib"
|
|
||||||
IgnoreDefaultLibraryNames="libc"
|
|
||||||
GenerateDebugInformation="TRUE"
|
|
||||||
ProgramDatabaseFile=".\Debug/soundstretchD.pdb"
|
|
||||||
GenerateMapFile="TRUE"
|
|
||||||
MapFileName=".\Debug/soundstretchD.map"
|
|
||||||
SubSystem="1"
|
|
||||||
TargetMachine="1"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TypeLibraryName=".\Debug/soundstretch.tlb"
|
|
||||||
HeaderFileName=""/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
CommandLine="copy Debug\soundstretchD.exe ..\..\bin\"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
Culture="1035"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory=".\Release"
|
|
||||||
IntermediateDirectory=".\Release"
|
|
||||||
ConfigurationType="1"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="3"
|
|
||||||
GlobalOptimizations="FALSE"
|
|
||||||
InlineFunctionExpansion="2"
|
|
||||||
EnableIntrinsicFunctions="TRUE"
|
|
||||||
AdditionalIncludeDirectories="..\..\include"
|
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS"
|
|
||||||
StringPooling="TRUE"
|
|
||||||
RuntimeLibrary="4"
|
|
||||||
EnableFunctionLevelLinking="TRUE"
|
|
||||||
PrecompiledHeaderFile=".\Release/soundstretch.pch"
|
|
||||||
AssemblerListingLocation=".\Release/"
|
|
||||||
ObjectFile=".\Release/"
|
|
||||||
ProgramDataBaseFileName=".\Release/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="TRUE"
|
|
||||||
DebugInformationFormat="0"
|
|
||||||
CompileAs="0"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLinkerTool"
|
|
||||||
AdditionalDependencies="SoundTouch.lib"
|
|
||||||
OutputFile=".\Release/soundstretch.exe"
|
|
||||||
LinkIncremental="1"
|
|
||||||
SuppressStartupBanner="TRUE"
|
|
||||||
AdditionalLibraryDirectories="..\..\lib"
|
|
||||||
GenerateDebugInformation="FALSE"
|
|
||||||
GenerateMapFile="TRUE"
|
|
||||||
MapFileName=".\Release/soundstretch.map"
|
|
||||||
SubSystem="1"
|
|
||||||
TargetMachine="1"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"
|
|
||||||
TypeLibraryName=".\Release/soundstretch.tlb"
|
|
||||||
HeaderFileName=""/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
CommandLine="copy Release\soundstretch.exe ..\..\bin\"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1035"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebDeploymentTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<Filter
|
|
||||||
Name="Source Files"
|
|
||||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
|
|
||||||
<File
|
|
||||||
RelativePath="main.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="RunParameters.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="WavFile.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Header Files"
|
|
||||||
Filter="h;hpp;hxx;hm;inl">
|
|
||||||
<File
|
|
||||||
RelativePath="RunParameters.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="WavFile.h">
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Resource Files"
|
|
||||||
Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
|
|
||||||
</Filter>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
333
source/SoundStretch/soundstretch.vcxproj
Normal file
333
source/SoundStretch/soundstretch.vcxproj
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{5AACDFFA-D491-44B8-A332-DA7ACCAAF2AF}</ProjectGuid>
|
||||||
|
<RootNamespace>soundstretch</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<TargetName>$(ProjectName)D</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<TargetName>$(ProjectName)D_x64</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<TargetName>$(ProjectName)_x64</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Midl>
|
||||||
|
<TypeLibraryName>.\Debug/soundstretch.tlb</TypeLibraryName>
|
||||||
|
<HeaderFileName />
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<StructMemberAlignment>16Bytes</StructMemberAlignment>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<BrowseInformation>true</BrowseInformation>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Midl>
|
||||||
|
<TypeLibraryName>.\Release/soundstretch.tlb</TypeLibraryName>
|
||||||
|
<HeaderFileName />
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Full</Optimization>
|
||||||
|
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat />
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Midl>
|
||||||
|
<TargetEnvironment>X64</TargetEnvironment>
|
||||||
|
<TypeLibraryName>.\Debug/soundstretch.tlb</TypeLibraryName>
|
||||||
|
<HeaderFileName />
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<StructMemberAlignment>16Bytes</StructMemberAlignment>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<BrowseInformation>true</BrowseInformation>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>
|
||||||
|
</EnableEnhancedInstructionSet>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<IgnoreSpecificDefaultLibraries>libc;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<ProgramDatabaseFile>$(OutDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Midl>
|
||||||
|
<TargetEnvironment>X64</TargetEnvironment>
|
||||||
|
<TypeLibraryName>.\Release/soundstretch.tlb</TypeLibraryName>
|
||||||
|
<HeaderFileName />
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Full</Optimization>
|
||||||
|
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat />
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>
|
||||||
|
</EnableEnhancedInstructionSet>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Link>
|
||||||
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<AdditionalLibraryDirectories>..\..\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||||
|
<GenerateMapFile>true</GenerateMapFile>
|
||||||
|
<MapFileName>$(OutDir)$(TargetName).map</MapFileName>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<DataExecutionPrevention />
|
||||||
|
</Link>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\bin mkdir ..\..\bin
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\bin\</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="main.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="RunParameters.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="WavFile.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="RunParameters.h" />
|
||||||
|
<ClInclude Include="SS_CharTypes.h" />
|
||||||
|
<ClInclude Include="WavFile.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\SoundTouch\SoundTouch.vcxproj">
|
||||||
|
<Project>{68a5dd20-7057-448b-8fe0-b6ac8d205509}</Project>
|
||||||
|
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
@ -1,184 +1,222 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
|
/// FIR low-pass (anti-alias) filter with filter coefficient design routine and
|
||||||
/// MMX optimization.
|
/// MMX optimization.
|
||||||
///
|
///
|
||||||
/// Anti-alias filter is used to prevent folding of high frequencies when
|
/// Anti-alias filter is used to prevent folding of high frequencies when
|
||||||
/// transposing the sample rate with interpolation.
|
/// transposing the sample rate with interpolation.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include <memory.h>
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include <assert.h>
|
||||||
// License along with this library; if not, write to the Free Software
|
#include <math.h>
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <stdlib.h>
|
||||||
//
|
#include "AAFilter.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "FIRFilter.h"
|
||||||
|
|
||||||
#include <memory.h>
|
using namespace soundtouch;
|
||||||
#include <assert.h>
|
|
||||||
#include <math.h>
|
#define PI 3.14159265358979323846
|
||||||
#include <stdlib.h>
|
#define TWOPI (2 * PI)
|
||||||
#include "AAFilter.h"
|
|
||||||
#include "FIRFilter.h"
|
// define this to save AA filter coefficients to a file
|
||||||
|
// #define _DEBUG_SAVE_AAFILTER_COEFFICIENTS 1
|
||||||
using namespace soundtouch;
|
|
||||||
|
#ifdef _DEBUG_SAVE_AAFILTER_COEFFICIENTS
|
||||||
#define PI 3.141592655357989
|
#include <stdio.h>
|
||||||
#define TWOPI (2 * PI)
|
|
||||||
|
static void _DEBUG_SAVE_AAFIR_COEFFS(SAMPLETYPE *coeffs, int len)
|
||||||
/*****************************************************************************
|
{
|
||||||
*
|
FILE *fptr = fopen("aa_filter_coeffs.txt", "wt");
|
||||||
* Implementation of the class 'AAFilter'
|
if (fptr == nullptr) return;
|
||||||
*
|
|
||||||
*****************************************************************************/
|
for (int i = 0; i < len; i ++)
|
||||||
|
{
|
||||||
AAFilter::AAFilter(uint len)
|
double temp = coeffs[i];
|
||||||
{
|
fprintf(fptr, "%lf\n", temp);
|
||||||
pFIR = FIRFilter::newInstance();
|
}
|
||||||
cutoffFreq = 0.5;
|
fclose(fptr);
|
||||||
setLength(len);
|
}
|
||||||
}
|
|
||||||
|
#else
|
||||||
|
#define _DEBUG_SAVE_AAFIR_COEFFS(x, y)
|
||||||
|
#endif
|
||||||
AAFilter::~AAFilter()
|
|
||||||
{
|
/*****************************************************************************
|
||||||
delete pFIR;
|
*
|
||||||
}
|
* Implementation of the class 'AAFilter'
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
// Sets new anti-alias filter cut-off edge frequency, scaled to
|
AAFilter::AAFilter(uint len)
|
||||||
// sampling frequency (nyquist frequency = 0.5).
|
{
|
||||||
// The filter will cut frequencies higher than the given frequency.
|
pFIR = FIRFilter::newInstance();
|
||||||
void AAFilter::setCutoffFreq(double newCutoffFreq)
|
cutoffFreq = 0.5;
|
||||||
{
|
setLength(len);
|
||||||
cutoffFreq = newCutoffFreq;
|
}
|
||||||
calculateCoeffs();
|
|
||||||
}
|
|
||||||
|
AAFilter::~AAFilter()
|
||||||
|
{
|
||||||
|
delete pFIR;
|
||||||
// Sets number of FIR filter taps
|
}
|
||||||
void AAFilter::setLength(uint newLength)
|
|
||||||
{
|
|
||||||
length = newLength;
|
// Sets new anti-alias filter cut-off edge frequency, scaled to
|
||||||
calculateCoeffs();
|
// sampling frequency (nyquist frequency = 0.5).
|
||||||
}
|
// The filter will cut frequencies higher than the given frequency.
|
||||||
|
void AAFilter::setCutoffFreq(double newCutoffFreq)
|
||||||
|
{
|
||||||
|
cutoffFreq = newCutoffFreq;
|
||||||
// Calculates coefficients for a low-pass FIR filter using Hamming window
|
calculateCoeffs();
|
||||||
void AAFilter::calculateCoeffs()
|
}
|
||||||
{
|
|
||||||
uint i;
|
|
||||||
double cntTemp, temp, tempCoeff,h, w;
|
// Sets number of FIR filter taps
|
||||||
double fc2, wc;
|
void AAFilter::setLength(uint newLength)
|
||||||
double scaleCoeff, sum;
|
{
|
||||||
double *work;
|
length = newLength;
|
||||||
SAMPLETYPE *coeffs;
|
calculateCoeffs();
|
||||||
|
}
|
||||||
assert(length >= 2);
|
|
||||||
assert(length % 4 == 0);
|
|
||||||
assert(cutoffFreq >= 0);
|
// Calculates coefficients for a low-pass FIR filter using Hamming window
|
||||||
assert(cutoffFreq <= 0.5);
|
void AAFilter::calculateCoeffs()
|
||||||
|
{
|
||||||
work = new double[length];
|
uint i;
|
||||||
coeffs = new SAMPLETYPE[length];
|
double cntTemp, temp, tempCoeff,h, w;
|
||||||
|
double wc;
|
||||||
fc2 = 2.0 * cutoffFreq;
|
double scaleCoeff, sum;
|
||||||
wc = PI * fc2;
|
double *work;
|
||||||
tempCoeff = TWOPI / (double)length;
|
SAMPLETYPE *coeffs;
|
||||||
|
|
||||||
sum = 0;
|
assert(length >= 2);
|
||||||
for (i = 0; i < length; i ++)
|
assert(length % 4 == 0);
|
||||||
{
|
assert(cutoffFreq >= 0);
|
||||||
cntTemp = (double)i - (double)(length / 2);
|
assert(cutoffFreq <= 0.5);
|
||||||
|
|
||||||
temp = cntTemp * wc;
|
work = new double[length];
|
||||||
if (temp != 0)
|
coeffs = new SAMPLETYPE[length];
|
||||||
{
|
|
||||||
h = fc2 * sin(temp) / temp; // sinc function
|
wc = 2.0 * PI * cutoffFreq;
|
||||||
}
|
tempCoeff = TWOPI / (double)length;
|
||||||
else
|
|
||||||
{
|
sum = 0;
|
||||||
h = 1.0;
|
for (i = 0; i < length; i ++)
|
||||||
}
|
{
|
||||||
w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
|
cntTemp = (double)i - (double)(length / 2);
|
||||||
|
|
||||||
temp = w * h;
|
temp = cntTemp * wc;
|
||||||
work[i] = temp;
|
if (temp != 0)
|
||||||
|
{
|
||||||
// calc net sum of coefficients
|
h = sin(temp) / temp; // sinc function
|
||||||
sum += temp;
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
// ensure the sum of coefficients is larger than zero
|
h = 1.0;
|
||||||
assert(sum > 0);
|
}
|
||||||
|
w = 0.54 + 0.46 * cos(tempCoeff * cntTemp); // hamming window
|
||||||
// ensure we've really designed a lowpass filter...
|
|
||||||
assert(work[length/2] > 0);
|
temp = w * h;
|
||||||
assert(work[length/2 + 1] > -1e-6);
|
work[i] = temp;
|
||||||
assert(work[length/2 - 1] > -1e-6);
|
|
||||||
|
// calc net sum of coefficients
|
||||||
// Calculate a scaling coefficient in such a way that the result can be
|
sum += temp;
|
||||||
// divided by 16384
|
}
|
||||||
scaleCoeff = 16384.0f / sum;
|
|
||||||
|
// ensure the sum of coefficients is larger than zero
|
||||||
for (i = 0; i < length; i ++)
|
assert(sum > 0);
|
||||||
{
|
|
||||||
// scale & round to nearest integer
|
// ensure we've really designed a lowpass filter...
|
||||||
temp = work[i] * scaleCoeff;
|
assert(work[length/2] > 0);
|
||||||
temp += (temp >= 0) ? 0.5 : -0.5;
|
assert(work[length/2 + 1] > -1e-6);
|
||||||
// ensure no overfloods
|
assert(work[length/2 - 1] > -1e-6);
|
||||||
assert(temp >= -32768 && temp <= 32767);
|
|
||||||
coeffs[i] = (SAMPLETYPE)temp;
|
// Calculate a scaling coefficient in such a way that the result can be
|
||||||
}
|
// divided by 16384
|
||||||
|
scaleCoeff = 16384.0f / sum;
|
||||||
// Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
|
|
||||||
pFIR->setCoefficients(coeffs, length, 14);
|
for (i = 0; i < length; i ++)
|
||||||
|
{
|
||||||
delete[] work;
|
temp = work[i] * scaleCoeff;
|
||||||
delete[] coeffs;
|
// scale & round to nearest integer
|
||||||
}
|
temp += (temp >= 0) ? 0.5 : -0.5;
|
||||||
|
// ensure no overfloods
|
||||||
|
assert(temp >= -32768 && temp <= 32767);
|
||||||
// Applies the filter to the given sequence of samples.
|
coeffs[i] = (SAMPLETYPE)temp;
|
||||||
// Note : The amount of outputted samples is by value of 'filter length'
|
}
|
||||||
// smaller than the amount of input samples.
|
|
||||||
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
|
// Set coefficients. Use divide factor 14 => divide result by 2^14 = 16384
|
||||||
{
|
pFIR->setCoefficients(coeffs, length, 14);
|
||||||
return pFIR->evaluate(dest, src, numSamples, numChannels);
|
|
||||||
}
|
_DEBUG_SAVE_AAFIR_COEFFS(coeffs, length);
|
||||||
|
|
||||||
|
delete[] work;
|
||||||
uint AAFilter::getLength() const
|
delete[] coeffs;
|
||||||
{
|
}
|
||||||
return pFIR->getLength();
|
|
||||||
}
|
|
||||||
|
// Applies the filter to the given sequence of samples.
|
||||||
|
// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
|
// smaller than the amount of input samples.
|
||||||
|
uint AAFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
|
||||||
|
{
|
||||||
|
return pFIR->evaluate(dest, src, numSamples, numChannels);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Applies the filter to the given src & dest pipes, so that processed amount of
|
||||||
|
/// samples get removed from src, and produced amount added to dest
|
||||||
|
/// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
|
/// smaller than the amount of input samples.
|
||||||
|
uint AAFilter::evaluate(FIFOSampleBuffer &dest, FIFOSampleBuffer &src) const
|
||||||
|
{
|
||||||
|
SAMPLETYPE *pdest;
|
||||||
|
const SAMPLETYPE *psrc;
|
||||||
|
uint numSrcSamples;
|
||||||
|
uint result;
|
||||||
|
int numChannels = src.getChannels();
|
||||||
|
|
||||||
|
assert(numChannels == dest.getChannels());
|
||||||
|
|
||||||
|
numSrcSamples = src.numSamples();
|
||||||
|
psrc = src.ptrBegin();
|
||||||
|
pdest = dest.ptrEnd(numSrcSamples);
|
||||||
|
result = pFIR->evaluate(pdest, psrc, numSrcSamples, numChannels);
|
||||||
|
src.receiveSamples(result);
|
||||||
|
dest.putSamples(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint AAFilter::getLength() const
|
||||||
|
{
|
||||||
|
return pFIR->getLength();
|
||||||
|
}
|
||||||
|
|||||||
@ -1,91 +1,93 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// 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 method
|
/// while maintaining the original pitch by using a time domain WSOLA-like method
|
||||||
/// with several performance-increasing tweaks.
|
/// with several performance-increasing tweaks.
|
||||||
///
|
///
|
||||||
/// Anti-alias filter is used to prevent folding of high frequencies when
|
/// Anti-alias filter is used to prevent folding of high frequencies when
|
||||||
/// transposing the sample rate with interpolation.
|
/// transposing the sample rate with interpolation.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef AAFilter_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define AAFilter_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include "STTypes.h"
|
||||||
//
|
#include "FIFOSampleBuffer.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
namespace soundtouch
|
||||||
#ifndef AAFilter_H
|
{
|
||||||
#define AAFilter_H
|
|
||||||
|
class AAFilter
|
||||||
#include "STTypes.h"
|
{
|
||||||
|
protected:
|
||||||
namespace soundtouch
|
class FIRFilter *pFIR;
|
||||||
{
|
|
||||||
|
/// Low-pass filter cut-off frequency, negative = invalid
|
||||||
class AAFilter
|
double cutoffFreq;
|
||||||
{
|
|
||||||
protected:
|
/// num of filter taps
|
||||||
class FIRFilter *pFIR;
|
uint length;
|
||||||
|
|
||||||
/// Low-pass filter cut-off frequency, negative = invalid
|
/// Calculate the FIR coefficients realizing the given cutoff-frequency
|
||||||
double cutoffFreq;
|
void calculateCoeffs();
|
||||||
|
public:
|
||||||
/// num of filter taps
|
AAFilter(uint length);
|
||||||
uint length;
|
|
||||||
|
~AAFilter();
|
||||||
/// Calculate the FIR coefficients realizing the given cutoff-frequency
|
|
||||||
void calculateCoeffs();
|
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
|
||||||
public:
|
/// frequency (nyquist frequency = 0.5). The filter will cut off the
|
||||||
AAFilter(uint length);
|
/// frequencies than that.
|
||||||
|
void setCutoffFreq(double newCutoffFreq);
|
||||||
~AAFilter();
|
|
||||||
|
/// Sets number of FIR filter taps, i.e. ~filter complexity
|
||||||
/// Sets new anti-alias filter cut-off edge frequency, scaled to sampling
|
void setLength(uint newLength);
|
||||||
/// frequency (nyquist frequency = 0.5). The filter will cut off the
|
|
||||||
/// frequencies than that.
|
uint getLength() const;
|
||||||
void setCutoffFreq(double newCutoffFreq);
|
|
||||||
|
/// Applies the filter to the given sequence of samples.
|
||||||
/// Sets number of FIR filter taps, i.e. ~filter complexity
|
/// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
void setLength(uint newLength);
|
/// smaller than the amount of input samples.
|
||||||
|
uint evaluate(SAMPLETYPE *dest,
|
||||||
uint getLength() const;
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples,
|
||||||
/// Applies the filter to the given sequence of samples.
|
uint numChannels) const;
|
||||||
/// Note : The amount of outputted samples is by value of 'filter length'
|
|
||||||
/// smaller than the amount of input samples.
|
/// Applies the filter to the given src & dest pipes, so that processed amount of
|
||||||
uint evaluate(SAMPLETYPE *dest,
|
/// samples get removed from src, and produced amount added to dest
|
||||||
const SAMPLETYPE *src,
|
/// Note : The amount of outputted samples is by value of 'filter length'
|
||||||
uint numSamples,
|
/// smaller than the amount of input samples.
|
||||||
uint numChannels) const;
|
uint evaluate(FIFOSampleBuffer &dest,
|
||||||
};
|
FIFOSampleBuffer &src) const;
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -1,370 +1,571 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Beats-per-minute (BPM) detection routine.
|
/// Beats-per-minute (BPM) detection routine.
|
||||||
///
|
///
|
||||||
/// The beat detection algorithm works as follows:
|
/// The beat detection algorithm works as follows:
|
||||||
/// - Use function 'inputSamples' to input a chunks of samples to the class for
|
/// - Use function 'inputSamples' to input a chunks of samples to the class for
|
||||||
/// analysis. It's a good idea to enter a large sound file or stream in smallish
|
/// analysis. It's a good idea to enter a large sound file or stream in smallish
|
||||||
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
|
/// chunks of around few kilosamples in order not to extinguish too much RAM memory.
|
||||||
/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden,
|
/// - Inputted sound data is decimated to approx 500 Hz to reduce calculation burden,
|
||||||
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
|
/// which is basically ok as low (bass) frequencies mostly determine the beat rate.
|
||||||
/// Simple averaging is used for anti-alias filtering because the resulting signal
|
/// Simple averaging is used for anti-alias filtering because the resulting signal
|
||||||
/// quality isn't of that high importance.
|
/// quality isn't of that high importance.
|
||||||
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
|
/// - Decimated sound data is enveloped, i.e. the amplitude shape is detected by
|
||||||
/// taking absolute value that's smoothed by sliding average. Signal levels that
|
/// taking absolute value that's smoothed by sliding average. Signal levels that
|
||||||
/// are below a couple of times the general RMS amplitude level are cut away to
|
/// are below a couple of times the general RMS amplitude level are cut away to
|
||||||
/// leave only notable peaks there.
|
/// leave only notable peaks there.
|
||||||
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
|
/// - Repeating sound patterns (e.g. beats) are detected by calculating short-term
|
||||||
/// autocorrelation function of the enveloped signal.
|
/// autocorrelation function of the enveloped signal.
|
||||||
/// - After whole sound data file has been analyzed as above, the bpm level is
|
/// - After whole sound data file has been analyzed as above, the bpm level is
|
||||||
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
|
/// detected by function 'getBpm' that finds the highest peak of the autocorrelation
|
||||||
/// function, calculates it's precise location and converts this reading to bpm's.
|
/// function, calculates it's precise location and converts this reading to bpm's.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#define _USE_MATH_DEFINES
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
#include <math.h>
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <assert.h>
|
||||||
//
|
#include <string.h>
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include <stdio.h>
|
||||||
|
#include <cfloat>
|
||||||
#include <math.h>
|
#include "FIFOSampleBuffer.h"
|
||||||
#include <assert.h>
|
#include "PeakFinder.h"
|
||||||
#include <string.h>
|
#include "BPMDetect.h"
|
||||||
#include <stdio.h>
|
|
||||||
#include "FIFOSampleBuffer.h"
|
using namespace soundtouch;
|
||||||
#include "PeakFinder.h"
|
|
||||||
#include "BPMDetect.h"
|
// algorithm input sample block size
|
||||||
|
static const int INPUT_BLOCK_SIZE = 2048;
|
||||||
using namespace soundtouch;
|
|
||||||
|
// decimated sample block size
|
||||||
#define INPUT_BLOCK_SAMPLES 2048
|
static const int DECIMATED_BLOCK_SIZE = 256;
|
||||||
#define DECIMATED_BLOCK_SAMPLES 256
|
|
||||||
|
/// Target sample rate after decimation
|
||||||
/// decay constant for calculating RMS volume sliding average approximation
|
static const int TARGET_SRATE = 1000;
|
||||||
/// (time constant is about 10 sec)
|
|
||||||
const float avgdecay = 0.99986f;
|
/// XCorr update sequence size, update in about 200msec chunks
|
||||||
|
static const int XCORR_UPDATE_SEQUENCE = (int)(TARGET_SRATE / 5);
|
||||||
/// Normalization coefficient for calculating RMS sliding average approximation.
|
|
||||||
const float avgnorm = (1 - avgdecay);
|
/// Moving average N size
|
||||||
|
static const int MOVING_AVERAGE_N = 15;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
/// XCorr decay time constant, decay to half in 30 seconds
|
||||||
|
/// If it's desired to have the system adapt quicker to beat rate
|
||||||
// Enable following define to create bpm analysis file:
|
/// changes within a continuing music stream, then the
|
||||||
|
/// 'xcorr_decay_time_constant' value can be reduced, yet that
|
||||||
// #define _CREATE_BPM_DEBUG_FILE
|
/// can increase possibility of glitches in bpm detection.
|
||||||
|
static const double XCORR_DECAY_TIME_CONSTANT = 30.0;
|
||||||
#ifdef _CREATE_BPM_DEBUG_FILE
|
|
||||||
|
/// Data overlap factor for beat detection algorithm
|
||||||
#define DEBUGFILE_NAME "c:\\temp\\soundtouch-bpm-debug.txt"
|
static const int OVERLAP_FACTOR = 4;
|
||||||
|
|
||||||
static void _SaveDebugData(const float *data, int minpos, int maxpos, double coeff)
|
static const double TWOPI = (2 * M_PI);
|
||||||
{
|
|
||||||
FILE *fptr = fopen(DEBUGFILE_NAME, "wt");
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int i;
|
|
||||||
|
// Enable following define to create bpm analysis file:
|
||||||
if (fptr)
|
|
||||||
{
|
//#define _CREATE_BPM_DEBUG_FILE
|
||||||
printf("\n\nWriting BPM debug data into file " DEBUGFILE_NAME "\n\n");
|
|
||||||
for (i = minpos; i < maxpos; i ++)
|
#ifdef _CREATE_BPM_DEBUG_FILE
|
||||||
{
|
|
||||||
fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]);
|
static void _SaveDebugData(const char *name, const float *data, int minpos, int maxpos, double coeff)
|
||||||
}
|
{
|
||||||
fclose(fptr);
|
FILE *fptr = fopen(name, "wt");
|
||||||
}
|
int i;
|
||||||
}
|
|
||||||
#else
|
if (fptr)
|
||||||
#define _SaveDebugData(a,b,c,d)
|
{
|
||||||
#endif
|
printf("\nWriting BPM debug data into file %s\n", name);
|
||||||
|
for (i = minpos; i < maxpos; i ++)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
{
|
||||||
|
fprintf(fptr, "%d\t%.1lf\t%f\n", i, coeff / (double)i, data[i]);
|
||||||
|
}
|
||||||
BPMDetect::BPMDetect(int numChannels, int aSampleRate)
|
fclose(fptr);
|
||||||
{
|
}
|
||||||
this->sampleRate = aSampleRate;
|
}
|
||||||
this->channels = numChannels;
|
|
||||||
|
void _SaveDebugBeatPos(const char *name, const std::vector<BEAT> &beats)
|
||||||
decimateSum = 0;
|
{
|
||||||
decimateCount = 0;
|
printf("\nWriting beat detections data into file %s\n", name);
|
||||||
|
|
||||||
envelopeAccu = 0;
|
FILE *fptr = fopen(name, "wt");
|
||||||
|
if (fptr)
|
||||||
// Initialize RMS volume accumulator to RMS level of 1500 (out of 32768) that's
|
{
|
||||||
// safe initial RMS signal level value for song data. This value is then adapted
|
for (uint i = 0; i < beats.size(); i++)
|
||||||
// to the actual level during processing.
|
{
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
BEAT b = beats[i];
|
||||||
// integer samples
|
fprintf(fptr, "%lf\t%lf\n", b.pos, b.strength);
|
||||||
RMSVolumeAccu = (1500 * 1500) / avgnorm;
|
}
|
||||||
#else
|
fclose(fptr);
|
||||||
// float samples, scaled to range [-1..+1[
|
}
|
||||||
RMSVolumeAccu = (0.045f * 0.045f) / avgnorm;
|
}
|
||||||
#endif
|
#else
|
||||||
|
#define _SaveDebugData(name, a,b,c,d)
|
||||||
// choose decimation factor so that result is approx. 1000 Hz
|
#define _SaveDebugBeatPos(name, b)
|
||||||
decimateBy = sampleRate / 1000;
|
#endif
|
||||||
assert(decimateBy > 0);
|
|
||||||
assert(INPUT_BLOCK_SAMPLES < decimateBy * DECIMATED_BLOCK_SAMPLES);
|
// Hamming window
|
||||||
|
void hamming(float *w, int N)
|
||||||
// Calculate window length & starting item according to desired min & max bpms
|
{
|
||||||
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
|
for (int i = 0; i < N; i++)
|
||||||
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM);
|
{
|
||||||
|
w[i] = (float)(0.54 - 0.46 * cos(TWOPI * i / (N - 1)));
|
||||||
assert(windowLen > windowStart);
|
}
|
||||||
|
|
||||||
// allocate new working objects
|
}
|
||||||
xcorr = new float[windowLen];
|
|
||||||
memset(xcorr, 0, windowLen * sizeof(float));
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
// allocate processing buffer
|
// IIR2_filter - 2nd order IIR filter
|
||||||
buffer = new FIFOSampleBuffer();
|
|
||||||
// we do processing in mono mode
|
IIR2_filter::IIR2_filter(const double *lpf_coeffs)
|
||||||
buffer->setChannels(1);
|
{
|
||||||
buffer->clear();
|
memcpy(coeffs, lpf_coeffs, 5 * sizeof(double));
|
||||||
}
|
memset(prev, 0, sizeof(prev));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BPMDetect::~BPMDetect()
|
float IIR2_filter::update(float x)
|
||||||
{
|
{
|
||||||
delete[] xcorr;
|
prev[0] = x;
|
||||||
delete buffer;
|
double y = x * coeffs[0];
|
||||||
}
|
|
||||||
|
for (int i = 4; i >= 1; i--)
|
||||||
|
{
|
||||||
|
y += coeffs[i] * prev[i];
|
||||||
/// convert to mono, low-pass filter & decimate to about 500 Hz.
|
prev[i] = prev[i - 1];
|
||||||
/// return number of outputted samples.
|
}
|
||||||
///
|
|
||||||
/// Decimation is used to remove the unnecessary frequencies and thus to reduce
|
prev[3] = y;
|
||||||
/// the amount of data needed to be processed as calculating autocorrelation
|
return (float)y;
|
||||||
/// function is a very-very heavy operation.
|
}
|
||||||
///
|
|
||||||
/// Anti-alias filtering is done simply by averaging the samples. This is really a
|
|
||||||
/// poor-man's anti-alias filtering, but it's not so critical in this kind of application
|
// IIR low-pass filter coefficients, calculated with matlab/octave cheby2(2,40,0.05)
|
||||||
/// (it'd also be difficult to design a high-quality filter with steep cut-off at very
|
const double _LPF_coeffs[5] = { 0.00996655391939, -0.01944529148401, 0.00996655391939, 1.96867605796247, -0.96916387431724 };
|
||||||
/// narrow band)
|
|
||||||
int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
{
|
|
||||||
int count, outcount;
|
BPMDetect::BPMDetect(int numChannels, int aSampleRate) :
|
||||||
LONG_SAMPLETYPE out;
|
beat_lpf(_LPF_coeffs)
|
||||||
|
{
|
||||||
assert(channels > 0);
|
beats.reserve(250); // initial reservation to prevent frequent reallocation
|
||||||
assert(decimateBy > 0);
|
|
||||||
outcount = 0;
|
this->sampleRate = aSampleRate;
|
||||||
for (count = 0; count < numsamples; count ++)
|
this->channels = numChannels;
|
||||||
{
|
|
||||||
int j;
|
decimateSum = 0;
|
||||||
|
decimateCount = 0;
|
||||||
// convert to mono and accumulate
|
|
||||||
for (j = 0; j < channels; j ++)
|
// choose decimation factor so that result is approx. 1000 Hz
|
||||||
{
|
decimateBy = sampleRate / TARGET_SRATE;
|
||||||
decimateSum += src[j];
|
if ((decimateBy <= 0) || (decimateBy * DECIMATED_BLOCK_SIZE < INPUT_BLOCK_SIZE))
|
||||||
}
|
{
|
||||||
src += j;
|
ST_THROW_RT_ERROR("Too small samplerate");
|
||||||
|
}
|
||||||
decimateCount ++;
|
|
||||||
if (decimateCount >= decimateBy)
|
// Calculate window length & starting item according to desired min & max bpms
|
||||||
{
|
windowLen = (60 * sampleRate) / (decimateBy * MIN_BPM);
|
||||||
// Store every Nth sample only
|
windowStart = (60 * sampleRate) / (decimateBy * MAX_BPM_RANGE);
|
||||||
out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels));
|
|
||||||
decimateSum = 0;
|
assert(windowLen > windowStart);
|
||||||
decimateCount = 0;
|
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
// allocate new working objects
|
||||||
// check ranges for sure (shouldn't actually be necessary)
|
xcorr = new float[windowLen];
|
||||||
if (out > 32767)
|
memset(xcorr, 0, windowLen * sizeof(float));
|
||||||
{
|
|
||||||
out = 32767;
|
pos = 0;
|
||||||
}
|
peakPos = 0;
|
||||||
else if (out < -32768)
|
peakVal = 0;
|
||||||
{
|
init_scaler = 1;
|
||||||
out = -32768;
|
beatcorr_ringbuffpos = 0;
|
||||||
}
|
beatcorr_ringbuff = new float[windowLen];
|
||||||
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
memset(beatcorr_ringbuff, 0, windowLen * sizeof(float));
|
||||||
dest[outcount] = (SAMPLETYPE)out;
|
|
||||||
outcount ++;
|
// allocate processing buffer
|
||||||
}
|
buffer = new FIFOSampleBuffer();
|
||||||
}
|
// we do processing in mono mode
|
||||||
return outcount;
|
buffer->setChannels(1);
|
||||||
}
|
buffer->clear();
|
||||||
|
|
||||||
|
// calculate hamming windows
|
||||||
|
hamw = new float[XCORR_UPDATE_SEQUENCE];
|
||||||
// Calculates autocorrelation function of the sample history buffer
|
hamming(hamw, XCORR_UPDATE_SEQUENCE);
|
||||||
void BPMDetect::updateXCorr(int process_samples)
|
hamw2 = new float[XCORR_UPDATE_SEQUENCE / 2];
|
||||||
{
|
hamming(hamw2, XCORR_UPDATE_SEQUENCE / 2);
|
||||||
int offs;
|
}
|
||||||
SAMPLETYPE *pBuffer;
|
|
||||||
|
|
||||||
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
|
BPMDetect::~BPMDetect()
|
||||||
|
{
|
||||||
pBuffer = buffer->ptrBegin();
|
delete[] xcorr;
|
||||||
for (offs = windowStart; offs < windowLen; offs ++)
|
delete[] beatcorr_ringbuff;
|
||||||
{
|
delete[] hamw;
|
||||||
LONG_SAMPLETYPE sum;
|
delete[] hamw2;
|
||||||
int i;
|
delete buffer;
|
||||||
|
}
|
||||||
sum = 0;
|
|
||||||
for (i = 0; i < process_samples; i ++)
|
|
||||||
{
|
/// convert to mono, low-pass filter & decimate to about 500 Hz.
|
||||||
sum += pBuffer[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
|
/// return number of outputted samples.
|
||||||
}
|
///
|
||||||
// xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable coefficients
|
/// Decimation is used to remove the unnecessary frequencies and thus to reduce
|
||||||
// if it's desired that the system adapts automatically to
|
/// the amount of data needed to be processed as calculating autocorrelation
|
||||||
// various bpms, e.g. in processing continouos music stream.
|
/// function is a very-very heavy operation.
|
||||||
// The 'xcorr_decay' should be a value that's smaller than but
|
///
|
||||||
// close to one, and should also depend on 'process_samples' value.
|
/// Anti-alias filtering is done simply by averaging the samples. This is really a
|
||||||
|
/// poor-man's anti-alias filtering, but it's not so critical in this kind of application
|
||||||
xcorr[offs] += (float)sum;
|
/// (it'd also be difficult to design a high-quality filter with steep cut-off at very
|
||||||
}
|
/// narrow band)
|
||||||
}
|
int BPMDetect::decimate(SAMPLETYPE *dest, const SAMPLETYPE *src, int numsamples)
|
||||||
|
{
|
||||||
|
int count, outcount;
|
||||||
// Calculates envelope of the sample data
|
LONG_SAMPLETYPE out;
|
||||||
void BPMDetect::calcEnvelope(SAMPLETYPE *samples, int numsamples)
|
|
||||||
{
|
assert(channels > 0);
|
||||||
const static double decay = 0.7f; // decay constant for smoothing the envelope
|
assert(decimateBy > 0);
|
||||||
const static double norm = (1 - decay);
|
outcount = 0;
|
||||||
|
for (count = 0; count < numsamples; count ++)
|
||||||
int i;
|
{
|
||||||
LONG_SAMPLETYPE out;
|
int j;
|
||||||
double val;
|
|
||||||
|
// convert to mono and accumulate
|
||||||
for (i = 0; i < numsamples; i ++)
|
for (j = 0; j < channels; j ++)
|
||||||
{
|
{
|
||||||
// calc average RMS volume
|
decimateSum += src[j];
|
||||||
RMSVolumeAccu *= avgdecay;
|
}
|
||||||
val = (float)fabs((float)samples[i]);
|
src += j;
|
||||||
RMSVolumeAccu += val * val;
|
|
||||||
|
decimateCount ++;
|
||||||
// cut amplitudes that are below cutoff ~2 times RMS volume
|
if (decimateCount >= decimateBy)
|
||||||
// (we're interested in peak values, not the silent moments)
|
{
|
||||||
if (val < 0.5 * sqrt(RMSVolumeAccu * avgnorm))
|
// Store every Nth sample only
|
||||||
{
|
out = (LONG_SAMPLETYPE)(decimateSum / (decimateBy * channels));
|
||||||
val = 0;
|
decimateSum = 0;
|
||||||
}
|
decimateCount = 0;
|
||||||
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
// smooth amplitude envelope
|
// check ranges for sure (shouldn't actually be necessary)
|
||||||
envelopeAccu *= decay;
|
if (out > 32767)
|
||||||
envelopeAccu += val;
|
{
|
||||||
out = (LONG_SAMPLETYPE)(envelopeAccu * norm);
|
out = 32767;
|
||||||
|
}
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
else if (out < -32768)
|
||||||
// cut peaks (shouldn't be necessary though)
|
{
|
||||||
if (out > 32767) out = 32767;
|
out = -32768;
|
||||||
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
}
|
||||||
samples[i] = (SAMPLETYPE)out;
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
}
|
dest[outcount] = (SAMPLETYPE)out;
|
||||||
}
|
outcount ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return outcount;
|
||||||
void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
|
}
|
||||||
{
|
|
||||||
SAMPLETYPE decimated[DECIMATED_BLOCK_SAMPLES];
|
|
||||||
|
// Calculates autocorrelation function of the sample history buffer
|
||||||
// iterate so that max INPUT_BLOCK_SAMPLES processed per iteration
|
void BPMDetect::updateXCorr(int process_samples)
|
||||||
while (numSamples > 0)
|
{
|
||||||
{
|
int offs;
|
||||||
int block;
|
SAMPLETYPE *pBuffer;
|
||||||
int decSamples;
|
|
||||||
|
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
|
||||||
block = (numSamples > INPUT_BLOCK_SAMPLES) ? INPUT_BLOCK_SAMPLES : numSamples;
|
assert(process_samples == XCORR_UPDATE_SEQUENCE);
|
||||||
|
|
||||||
// decimate. note that converts to mono at the same time
|
pBuffer = buffer->ptrBegin();
|
||||||
decSamples = decimate(decimated, samples, block);
|
|
||||||
samples += block * channels;
|
// calculate decay factor for xcorr filtering
|
||||||
numSamples -= block;
|
float xcorr_decay = (float)pow(0.5, process_samples / (XCORR_DECAY_TIME_CONSTANT * TARGET_SRATE));
|
||||||
|
|
||||||
// envelope new samples and add them to buffer
|
// prescale pbuffer
|
||||||
calcEnvelope(decimated, decSamples);
|
float tmp[XCORR_UPDATE_SEQUENCE];
|
||||||
buffer->putSamples(decimated, decSamples);
|
for (int i = 0; i < process_samples; i++)
|
||||||
}
|
{
|
||||||
|
tmp[i] = hamw[i] * hamw[i] * pBuffer[i];
|
||||||
// when the buffer has enought samples for processing...
|
}
|
||||||
if ((int)buffer->numSamples() > windowLen)
|
|
||||||
{
|
#pragma omp parallel for
|
||||||
int processLength;
|
for (offs = windowStart; offs < windowLen; offs ++)
|
||||||
|
{
|
||||||
// how many samples are processed
|
float sum;
|
||||||
processLength = (int)buffer->numSamples() - windowLen;
|
int i;
|
||||||
|
|
||||||
// ... calculate autocorrelations for oldest samples...
|
sum = 0;
|
||||||
updateXCorr(processLength);
|
for (i = 0; i < process_samples; i ++)
|
||||||
// ... and remove them from the buffer
|
{
|
||||||
buffer->receiveSamples(processLength);
|
sum += tmp[i] * pBuffer[i + offs]; // scaling the sub-result shouldn't be necessary
|
||||||
}
|
}
|
||||||
}
|
xcorr[offs] *= xcorr_decay; // decay 'xcorr' here with suitable time constant.
|
||||||
|
|
||||||
|
xcorr[offs] += (float)fabs(sum);
|
||||||
|
}
|
||||||
void BPMDetect::removeBias()
|
}
|
||||||
{
|
|
||||||
int i;
|
|
||||||
float minval = 1e12f; // arbitrary large number
|
// Detect individual beat positions
|
||||||
|
void BPMDetect::updateBeatPos(int process_samples)
|
||||||
for (i = windowStart; i < windowLen; i ++)
|
{
|
||||||
{
|
SAMPLETYPE *pBuffer;
|
||||||
if (xcorr[i] < minval)
|
|
||||||
{
|
assert(buffer->numSamples() >= (uint)(process_samples + windowLen));
|
||||||
minval = xcorr[i];
|
|
||||||
}
|
pBuffer = buffer->ptrBegin();
|
||||||
}
|
assert(process_samples == XCORR_UPDATE_SEQUENCE / 2);
|
||||||
|
|
||||||
for (i = windowStart; i < windowLen; i ++)
|
// static double thr = 0.0003;
|
||||||
{
|
double posScale = (double)this->decimateBy / (double)this->sampleRate;
|
||||||
xcorr[i] -= minval;
|
int resetDur = (int)(0.12 / posScale + 0.5);
|
||||||
}
|
|
||||||
}
|
// prescale pbuffer
|
||||||
|
float tmp[XCORR_UPDATE_SEQUENCE / 2];
|
||||||
|
for (int i = 0; i < process_samples; i++)
|
||||||
float BPMDetect::getBpm()
|
{
|
||||||
{
|
tmp[i] = hamw2[i] * hamw2[i] * pBuffer[i];
|
||||||
double peakPos;
|
}
|
||||||
double coeff;
|
|
||||||
PeakFinder peakFinder;
|
#pragma omp parallel for
|
||||||
|
for (int offs = windowStart; offs < windowLen; offs++)
|
||||||
coeff = 60.0 * ((double)sampleRate / (double)decimateBy);
|
{
|
||||||
|
float sum = 0;
|
||||||
// save bpm debug analysis data if debug data enabled
|
for (int i = 0; i < process_samples; i++)
|
||||||
_SaveDebugData(xcorr, windowStart, windowLen, coeff);
|
{
|
||||||
|
sum += tmp[i] * pBuffer[offs + i];
|
||||||
// remove bias from xcorr data
|
}
|
||||||
removeBias();
|
beatcorr_ringbuff[(beatcorr_ringbuffpos + offs) % windowLen] += (float)((sum > 0) ? sum : 0); // accumulate only positive correlations
|
||||||
|
}
|
||||||
// find peak position
|
|
||||||
peakPos = peakFinder.detectPeak(xcorr, windowStart, windowLen);
|
int skipstep = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;
|
||||||
|
|
||||||
assert(decimateBy != 0);
|
// compensate empty buffer at beginning by scaling coefficient
|
||||||
if (peakPos < 1e-9) return 0.0; // detection failed.
|
float scale = (float)windowLen / (float)(skipstep * init_scaler);
|
||||||
|
if (scale > 1.0f)
|
||||||
// calculate BPM
|
{
|
||||||
return (float) (coeff / peakPos);
|
init_scaler++;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect beats
|
||||||
|
for (int i = 0; i < skipstep; i++)
|
||||||
|
{
|
||||||
|
float sum = beatcorr_ringbuff[beatcorr_ringbuffpos];
|
||||||
|
sum -= beat_lpf.update(sum);
|
||||||
|
|
||||||
|
if (sum > peakVal)
|
||||||
|
{
|
||||||
|
// found new local largest value
|
||||||
|
peakVal = sum;
|
||||||
|
peakPos = pos;
|
||||||
|
}
|
||||||
|
if (pos > peakPos + resetDur)
|
||||||
|
{
|
||||||
|
// largest value not updated for 200msec => accept as beat
|
||||||
|
peakPos += skipstep;
|
||||||
|
if (peakVal > 0)
|
||||||
|
{
|
||||||
|
// add detected beat to end of "beats" vector
|
||||||
|
BEAT temp = { (float)(peakPos * posScale), (float)(peakVal * scale) };
|
||||||
|
beats.push_back(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
peakVal = 0;
|
||||||
|
peakPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
beatcorr_ringbuff[beatcorr_ringbuffpos] = 0;
|
||||||
|
pos++;
|
||||||
|
beatcorr_ringbuffpos = (beatcorr_ringbuffpos + 1) % windowLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define max(x,y) ((x) > (y) ? (x) : (y))
|
||||||
|
|
||||||
|
void BPMDetect::inputSamples(const SAMPLETYPE *samples, int numSamples)
|
||||||
|
{
|
||||||
|
SAMPLETYPE decimated[DECIMATED_BLOCK_SIZE];
|
||||||
|
|
||||||
|
// iterate so that max INPUT_BLOCK_SAMPLES processed per iteration
|
||||||
|
while (numSamples > 0)
|
||||||
|
{
|
||||||
|
int block;
|
||||||
|
int decSamples;
|
||||||
|
|
||||||
|
block = (numSamples > INPUT_BLOCK_SIZE) ? INPUT_BLOCK_SIZE : numSamples;
|
||||||
|
|
||||||
|
// decimate. note that converts to mono at the same time
|
||||||
|
decSamples = decimate(decimated, samples, block);
|
||||||
|
samples += block * channels;
|
||||||
|
numSamples -= block;
|
||||||
|
|
||||||
|
buffer->putSamples(decimated, decSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
// when the buffer has enough samples for processing...
|
||||||
|
int req = max(windowLen + XCORR_UPDATE_SEQUENCE, 2 * XCORR_UPDATE_SEQUENCE);
|
||||||
|
while ((int)buffer->numSamples() >= req)
|
||||||
|
{
|
||||||
|
// ... update autocorrelations...
|
||||||
|
updateXCorr(XCORR_UPDATE_SEQUENCE);
|
||||||
|
// ...update beat position calculation...
|
||||||
|
updateBeatPos(XCORR_UPDATE_SEQUENCE / 2);
|
||||||
|
// ... and remove proceessed samples from the buffer
|
||||||
|
int n = XCORR_UPDATE_SEQUENCE / OVERLAP_FACTOR;
|
||||||
|
buffer->receiveSamples(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BPMDetect::removeBias()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// Remove linear bias: calculate linear regression coefficient
|
||||||
|
// 1. calc mean of 'xcorr' and 'i'
|
||||||
|
double mean_i = 0;
|
||||||
|
double mean_x = 0;
|
||||||
|
for (i = windowStart; i < windowLen; i++)
|
||||||
|
{
|
||||||
|
mean_x += xcorr[i];
|
||||||
|
}
|
||||||
|
mean_x /= (windowLen - windowStart);
|
||||||
|
mean_i = 0.5 * (windowLen - 1 + windowStart);
|
||||||
|
|
||||||
|
// 2. calculate linear regression coefficient
|
||||||
|
double b = 0;
|
||||||
|
double div = 0;
|
||||||
|
for (i = windowStart; i < windowLen; i++)
|
||||||
|
{
|
||||||
|
double xt = xcorr[i] - mean_x;
|
||||||
|
double xi = i - mean_i;
|
||||||
|
b += xt * xi;
|
||||||
|
div += xi * xi;
|
||||||
|
}
|
||||||
|
b /= div;
|
||||||
|
|
||||||
|
// subtract linear regression and resolve min. value bias
|
||||||
|
float minval = FLT_MAX; // arbitrary large number
|
||||||
|
for (i = windowStart; i < windowLen; i ++)
|
||||||
|
{
|
||||||
|
xcorr[i] -= (float)(b * i);
|
||||||
|
if (xcorr[i] < minval)
|
||||||
|
{
|
||||||
|
minval = xcorr[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// subtract min.value
|
||||||
|
for (i = windowStart; i < windowLen; i ++)
|
||||||
|
{
|
||||||
|
xcorr[i] -= minval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Calculate N-point moving average for "source" values
|
||||||
|
void MAFilter(float *dest, const float *source, int start, int end, int N)
|
||||||
|
{
|
||||||
|
for (int i = start; i < end; i++)
|
||||||
|
{
|
||||||
|
int i1 = i - N / 2;
|
||||||
|
int i2 = i + N / 2 + 1;
|
||||||
|
if (i1 < start) i1 = start;
|
||||||
|
if (i2 > end) i2 = end;
|
||||||
|
|
||||||
|
double sum = 0;
|
||||||
|
for (int j = i1; j < i2; j ++)
|
||||||
|
{
|
||||||
|
sum += source[j];
|
||||||
|
}
|
||||||
|
dest[i] = (float)(sum / (i2 - i1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float BPMDetect::getBpm()
|
||||||
|
{
|
||||||
|
double peakPos;
|
||||||
|
double coeff;
|
||||||
|
PeakFinder peakFinder;
|
||||||
|
|
||||||
|
// remove bias from xcorr data
|
||||||
|
removeBias();
|
||||||
|
|
||||||
|
coeff = 60.0 * ((double)sampleRate / (double)decimateBy);
|
||||||
|
|
||||||
|
// save bpm debug data if debug data writing enabled
|
||||||
|
_SaveDebugData("soundtouch-bpm-xcorr.txt", xcorr, windowStart, windowLen, coeff);
|
||||||
|
|
||||||
|
// Smoothen by N-point moving-average
|
||||||
|
float *data = new float[windowLen];
|
||||||
|
memset(data, 0, sizeof(float) * windowLen);
|
||||||
|
MAFilter(data, xcorr, windowStart, windowLen, MOVING_AVERAGE_N);
|
||||||
|
|
||||||
|
// find peak position
|
||||||
|
peakPos = peakFinder.detectPeak(data, windowStart, windowLen);
|
||||||
|
|
||||||
|
// save bpm debug data if debug data writing enabled
|
||||||
|
_SaveDebugData("soundtouch-bpm-smoothed.txt", data, windowStart, windowLen, coeff);
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
|
||||||
|
assert(decimateBy != 0);
|
||||||
|
if (peakPos < 1e-9) return 0.0; // detection failed.
|
||||||
|
|
||||||
|
_SaveDebugBeatPos("soundtouch-detected-beats.txt", beats);
|
||||||
|
|
||||||
|
// calculate BPM
|
||||||
|
float bpm = (float)(coeff / peakPos);
|
||||||
|
return (bpm >= MIN_BPM && bpm <= MAX_BPM_VALID) ? bpm : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get beat position arrays. Note: The array includes also really low beat detection values
|
||||||
|
/// in absence of clear strong beats. Consumer may wish to filter low values away.
|
||||||
|
/// - "pos" receive array of beat positions
|
||||||
|
/// - "values" receive array of beat detection strengths
|
||||||
|
/// - max_num indicates max.size of "pos" and "values" array.
|
||||||
|
///
|
||||||
|
/// You can query a suitable array sized by calling this with nullptr in "pos" & "values".
|
||||||
|
///
|
||||||
|
/// \return number of beats in the arrays.
|
||||||
|
int BPMDetect::getBeats(float *pos, float *values, int max_num)
|
||||||
|
{
|
||||||
|
int num = (int)beats.size();
|
||||||
|
if ((!pos) || (!values)) return num; // pos or values nullptr, return just size
|
||||||
|
|
||||||
|
for (int i = 0; (i < num) && (i < max_num); i++)
|
||||||
|
{
|
||||||
|
pos[i] = beats[i].pos;
|
||||||
|
values[i] = beats[i].strength;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,274 +1,275 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// A buffer class for temporarily storaging sound samples, operates as a
|
/// A buffer class for temporarily storaging sound samples, operates as a
|
||||||
/// first-in-first-out pipe.
|
/// first-in-first-out pipe.
|
||||||
///
|
///
|
||||||
/// Samples are added to the end of the sample buffer with the 'putSamples'
|
/// Samples are added to the end of the sample buffer with the 'putSamples'
|
||||||
/// function, and are received from the beginning of the buffer by calling
|
/// function, and are received from the beginning of the buffer by calling
|
||||||
/// the 'receiveSamples' function. The class automatically removes the
|
/// the 'receiveSamples' function. The class automatically removes the
|
||||||
/// outputted samples from the buffer, as well as grows the buffer size
|
/// outputted samples from the buffer, as well as grows the buffer size
|
||||||
/// whenever necessary.
|
/// whenever necessary.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include <stdlib.h>
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include <memory.h>
|
||||||
// License along with this library; if not, write to the Free Software
|
#include <string.h>
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <assert.h>
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "FIFOSampleBuffer.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
using namespace soundtouch;
|
||||||
#include <memory.h>
|
|
||||||
#include <string.h>
|
// Constructor
|
||||||
#include <assert.h>
|
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
|
||||||
|
{
|
||||||
#include "FIFOSampleBuffer.h"
|
assert(numChannels > 0);
|
||||||
|
sizeInBytes = 0; // reasonable initial value
|
||||||
using namespace soundtouch;
|
buffer = nullptr;
|
||||||
|
bufferUnaligned = nullptr;
|
||||||
// Constructor
|
samplesInBuffer = 0;
|
||||||
FIFOSampleBuffer::FIFOSampleBuffer(int numChannels)
|
bufferPos = 0;
|
||||||
{
|
channels = (uint)numChannels;
|
||||||
assert(numChannels > 0);
|
ensureCapacity(32); // allocate initial capacity
|
||||||
sizeInBytes = 0; // reasonable initial value
|
}
|
||||||
buffer = NULL;
|
|
||||||
bufferUnaligned = NULL;
|
|
||||||
samplesInBuffer = 0;
|
// destructor
|
||||||
bufferPos = 0;
|
FIFOSampleBuffer::~FIFOSampleBuffer()
|
||||||
channels = (uint)numChannels;
|
{
|
||||||
ensureCapacity(32); // allocate initial capacity
|
delete[] bufferUnaligned;
|
||||||
}
|
bufferUnaligned = nullptr;
|
||||||
|
buffer = nullptr;
|
||||||
|
}
|
||||||
// destructor
|
|
||||||
FIFOSampleBuffer::~FIFOSampleBuffer()
|
|
||||||
{
|
// Sets number of channels, 1 = mono, 2 = stereo
|
||||||
delete[] bufferUnaligned;
|
void FIFOSampleBuffer::setChannels(int numChannels)
|
||||||
bufferUnaligned = NULL;
|
{
|
||||||
buffer = NULL;
|
uint usedBytes;
|
||||||
}
|
|
||||||
|
if (!verifyNumberOfChannels(numChannels)) return;
|
||||||
|
|
||||||
// Sets number of channels, 1 = mono, 2 = stereo
|
usedBytes = channels * samplesInBuffer;
|
||||||
void FIFOSampleBuffer::setChannels(int numChannels)
|
channels = (uint)numChannels;
|
||||||
{
|
samplesInBuffer = usedBytes / channels;
|
||||||
uint usedBytes;
|
}
|
||||||
|
|
||||||
assert(numChannels > 0);
|
|
||||||
usedBytes = channels * samplesInBuffer;
|
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
|
||||||
channels = (uint)numChannels;
|
// zeroes this pointer by copying samples from the 'bufferPos' pointer
|
||||||
samplesInBuffer = usedBytes / channels;
|
// location on to the beginning of the buffer.
|
||||||
}
|
void FIFOSampleBuffer::rewind()
|
||||||
|
{
|
||||||
|
if (buffer && bufferPos)
|
||||||
// if output location pointer 'bufferPos' isn't zero, 'rewinds' the buffer and
|
{
|
||||||
// zeroes this pointer by copying samples from the 'bufferPos' pointer
|
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
|
||||||
// location on to the beginning of the buffer.
|
bufferPos = 0;
|
||||||
void FIFOSampleBuffer::rewind()
|
}
|
||||||
{
|
}
|
||||||
if (buffer && bufferPos)
|
|
||||||
{
|
|
||||||
memmove(buffer, ptrBegin(), sizeof(SAMPLETYPE) * channels * samplesInBuffer);
|
// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
||||||
bufferPos = 0;
|
// the sample buffer.
|
||||||
}
|
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
||||||
}
|
{
|
||||||
|
memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
|
||||||
|
samplesInBuffer += nSamples;
|
||||||
// Adds 'numSamples' pcs of samples from the 'samples' memory position to
|
}
|
||||||
// the sample buffer.
|
|
||||||
void FIFOSampleBuffer::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
|
||||||
{
|
// Increases the number of samples in the buffer without copying any actual
|
||||||
memcpy(ptrEnd(nSamples), samples, sizeof(SAMPLETYPE) * nSamples * channels);
|
// samples.
|
||||||
samplesInBuffer += nSamples;
|
//
|
||||||
}
|
// This function is used to update the number of samples in the sample buffer
|
||||||
|
// when accessing the buffer directly with 'ptrEnd' function. Please be
|
||||||
|
// careful though!
|
||||||
// Increases the number of samples in the buffer without copying any actual
|
void FIFOSampleBuffer::putSamples(uint nSamples)
|
||||||
// samples.
|
{
|
||||||
//
|
uint req;
|
||||||
// This function is used to update the number of samples in the sample buffer
|
|
||||||
// when accessing the buffer directly with 'ptrEnd' function. Please be
|
req = samplesInBuffer + nSamples;
|
||||||
// careful though!
|
ensureCapacity(req);
|
||||||
void FIFOSampleBuffer::putSamples(uint nSamples)
|
samplesInBuffer += nSamples;
|
||||||
{
|
}
|
||||||
uint req;
|
|
||||||
|
|
||||||
req = samplesInBuffer + nSamples;
|
// Returns a pointer to the end of the used part of the sample buffer (i.e.
|
||||||
ensureCapacity(req);
|
// where the new samples are to be inserted). This function may be used for
|
||||||
samplesInBuffer += nSamples;
|
// inserting new samples into the sample buffer directly. Please be careful!
|
||||||
}
|
//
|
||||||
|
// Parameter 'slackCapacity' tells the function how much free capacity (in
|
||||||
|
// terms of samples) there _at least_ should be, in order to the caller to
|
||||||
// Returns a pointer to the end of the used part of the sample buffer (i.e.
|
// successfully insert all the required samples to the buffer. When necessary,
|
||||||
// where the new samples are to be inserted). This function may be used for
|
// the function grows the buffer size to comply with this requirement.
|
||||||
// inserting new samples into the sample buffer directly. Please be careful!
|
//
|
||||||
//
|
// When using this function as means for inserting new samples, also remember
|
||||||
// Parameter 'slackCapacity' tells the function how much free capacity (in
|
// to increase the sample count afterwards, by calling the
|
||||||
// terms of samples) there _at least_ should be, in order to the caller to
|
// 'putSamples(numSamples)' function.
|
||||||
// succesfully insert all the required samples to the buffer. When necessary,
|
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
|
||||||
// the function grows the buffer size to comply with this requirement.
|
{
|
||||||
//
|
ensureCapacity(samplesInBuffer + slackCapacity);
|
||||||
// When using this function as means for inserting new samples, also remember
|
return buffer + samplesInBuffer * channels;
|
||||||
// to increase the sample count afterwards, by calling the
|
}
|
||||||
// 'putSamples(numSamples)' function.
|
|
||||||
SAMPLETYPE *FIFOSampleBuffer::ptrEnd(uint slackCapacity)
|
|
||||||
{
|
// Returns a pointer to the beginning of the currently non-outputted samples.
|
||||||
ensureCapacity(samplesInBuffer + slackCapacity);
|
// This function is provided for accessing the output samples directly.
|
||||||
return buffer + samplesInBuffer * channels;
|
// Please be careful!
|
||||||
}
|
//
|
||||||
|
// When using this function to output samples, also remember to 'remove' the
|
||||||
|
// outputted samples from the buffer by calling the
|
||||||
// Returns a pointer to the beginning of the currently non-outputted samples.
|
// 'receiveSamples(numSamples)' function
|
||||||
// This function is provided for accessing the output samples directly.
|
SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
|
||||||
// Please be careful!
|
{
|
||||||
//
|
assert(buffer);
|
||||||
// When using this function to output samples, also remember to 'remove' the
|
return buffer + bufferPos * channels;
|
||||||
// outputted samples from the buffer by calling the
|
}
|
||||||
// 'receiveSamples(numSamples)' function
|
|
||||||
SAMPLETYPE *FIFOSampleBuffer::ptrBegin()
|
|
||||||
{
|
// Ensures that the buffer has enough capacity, i.e. space for _at least_
|
||||||
assert(buffer);
|
// 'capacityRequirement' number of samples. The buffer is grown in steps of
|
||||||
return buffer + bufferPos * channels;
|
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
|
||||||
}
|
// as well as to round the buffer size up to the virtual memory page size.
|
||||||
|
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
|
||||||
|
{
|
||||||
// Ensures that the buffer has enought capacity, i.e. space for _at least_
|
SAMPLETYPE *tempUnaligned, *temp;
|
||||||
// 'capacityRequirement' number of samples. The buffer is grown in steps of
|
|
||||||
// 4 kilobytes to eliminate the need for frequently growing up the buffer,
|
if (capacityRequirement > getCapacity())
|
||||||
// as well as to round the buffer size up to the virtual memory page size.
|
{
|
||||||
void FIFOSampleBuffer::ensureCapacity(uint capacityRequirement)
|
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
|
||||||
{
|
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
|
||||||
SAMPLETYPE *tempUnaligned, *temp;
|
assert(sizeInBytes % 2 == 0);
|
||||||
|
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
|
||||||
if (capacityRequirement > getCapacity())
|
if (tempUnaligned == nullptr)
|
||||||
{
|
{
|
||||||
// enlarge the buffer in 4kbyte steps (round up to next 4k boundary)
|
ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
|
||||||
sizeInBytes = (capacityRequirement * channels * sizeof(SAMPLETYPE) + 4095) & (uint)-4096;
|
}
|
||||||
assert(sizeInBytes % 2 == 0);
|
// Align the buffer to begin at 16byte cache line boundary for optimal performance
|
||||||
tempUnaligned = new SAMPLETYPE[sizeInBytes / sizeof(SAMPLETYPE) + 16 / sizeof(SAMPLETYPE)];
|
temp = (SAMPLETYPE *)SOUNDTOUCH_ALIGN_POINTER_16(tempUnaligned);
|
||||||
if (tempUnaligned == NULL)
|
if (samplesInBuffer)
|
||||||
{
|
{
|
||||||
ST_THROW_RT_ERROR("Couldn't allocate memory!\n");
|
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
|
||||||
}
|
}
|
||||||
// Align the buffer to begin at 16byte cache line boundary for optimal performance
|
delete[] bufferUnaligned;
|
||||||
temp = (SAMPLETYPE *)(((ulong)tempUnaligned + 15) & (ulong)-16);
|
buffer = temp;
|
||||||
if (samplesInBuffer)
|
bufferUnaligned = tempUnaligned;
|
||||||
{
|
bufferPos = 0;
|
||||||
memcpy(temp, ptrBegin(), samplesInBuffer * channels * sizeof(SAMPLETYPE));
|
}
|
||||||
}
|
else
|
||||||
delete[] bufferUnaligned;
|
{
|
||||||
buffer = temp;
|
// simply rewind the buffer (if necessary)
|
||||||
bufferUnaligned = tempUnaligned;
|
rewind();
|
||||||
bufferPos = 0;
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// simply rewind the buffer (if necessary)
|
// Returns the current buffer capacity in terms of samples
|
||||||
rewind();
|
uint FIFOSampleBuffer::getCapacity() const
|
||||||
}
|
{
|
||||||
}
|
return sizeInBytes / (channels * sizeof(SAMPLETYPE));
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the current buffer capacity in terms of samples
|
|
||||||
uint FIFOSampleBuffer::getCapacity() const
|
// Returns the number of samples currently in the buffer
|
||||||
{
|
uint FIFOSampleBuffer::numSamples() const
|
||||||
return sizeInBytes / (channels * sizeof(SAMPLETYPE));
|
{
|
||||||
}
|
return samplesInBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the number of samples currently in the buffer
|
|
||||||
uint FIFOSampleBuffer::numSamples() const
|
// Output samples from beginning of the sample buffer. Copies demanded number
|
||||||
{
|
// of samples to output and removes them from the sample buffer. If there
|
||||||
return samplesInBuffer;
|
// are less than 'numsample' samples in the buffer, returns all available.
|
||||||
}
|
//
|
||||||
|
// Returns number of samples copied.
|
||||||
|
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
|
||||||
// Output samples from beginning of the sample buffer. Copies demanded number
|
{
|
||||||
// of samples to output and removes them from the sample buffer. If there
|
uint num;
|
||||||
// are less than 'numsample' samples in the buffer, returns all available.
|
|
||||||
//
|
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
|
||||||
// Returns number of samples copied.
|
|
||||||
uint FIFOSampleBuffer::receiveSamples(SAMPLETYPE *output, uint maxSamples)
|
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
|
||||||
{
|
return receiveSamples(num);
|
||||||
uint num;
|
}
|
||||||
|
|
||||||
num = (maxSamples > samplesInBuffer) ? samplesInBuffer : maxSamples;
|
|
||||||
|
// Removes samples from the beginning of the sample buffer without copying them
|
||||||
memcpy(output, ptrBegin(), channels * sizeof(SAMPLETYPE) * num);
|
// anywhere. Used to reduce the number of samples in the buffer, when accessing
|
||||||
return receiveSamples(num);
|
// the sample buffer with the 'ptrBegin' function.
|
||||||
}
|
uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
|
||||||
|
{
|
||||||
|
if (maxSamples >= samplesInBuffer)
|
||||||
// Removes samples from the beginning of the sample buffer without copying them
|
{
|
||||||
// anywhere. Used to reduce the number of samples in the buffer, when accessing
|
uint temp;
|
||||||
// the sample buffer with the 'ptrBegin' function.
|
|
||||||
uint FIFOSampleBuffer::receiveSamples(uint maxSamples)
|
temp = samplesInBuffer;
|
||||||
{
|
samplesInBuffer = 0;
|
||||||
if (maxSamples >= samplesInBuffer)
|
return temp;
|
||||||
{
|
}
|
||||||
uint temp;
|
|
||||||
|
samplesInBuffer -= maxSamples;
|
||||||
temp = samplesInBuffer;
|
bufferPos += maxSamples;
|
||||||
samplesInBuffer = 0;
|
|
||||||
return temp;
|
return maxSamples;
|
||||||
}
|
}
|
||||||
|
|
||||||
samplesInBuffer -= maxSamples;
|
|
||||||
bufferPos += maxSamples;
|
// Returns nonzero if the sample buffer is empty
|
||||||
|
int FIFOSampleBuffer::isEmpty() const
|
||||||
return maxSamples;
|
{
|
||||||
}
|
return (samplesInBuffer == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns nonzero if the sample buffer is empty
|
|
||||||
int FIFOSampleBuffer::isEmpty() const
|
// Clears the sample buffer
|
||||||
{
|
void FIFOSampleBuffer::clear()
|
||||||
return (samplesInBuffer == 0) ? 1 : 0;
|
{
|
||||||
}
|
samplesInBuffer = 0;
|
||||||
|
bufferPos = 0;
|
||||||
|
}
|
||||||
// Clears the sample buffer
|
|
||||||
void FIFOSampleBuffer::clear()
|
|
||||||
{
|
/// allow trimming (downwards) amount of samples in pipeline.
|
||||||
samplesInBuffer = 0;
|
/// Returns adjusted amount of samples
|
||||||
bufferPos = 0;
|
uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
|
||||||
}
|
{
|
||||||
|
if (numSamples < samplesInBuffer)
|
||||||
|
{
|
||||||
/// allow trimming (downwards) amount of samples in pipeline.
|
samplesInBuffer = numSamples;
|
||||||
/// Returns adjusted amount of samples
|
}
|
||||||
uint FIFOSampleBuffer::adjustAmountOfSamples(uint numSamples)
|
return samplesInBuffer;
|
||||||
{
|
}
|
||||||
if (numSamples < samplesInBuffer)
|
|
||||||
{
|
|
||||||
samplesInBuffer = numSamples;
|
/// Add silence to end of buffer
|
||||||
}
|
void FIFOSampleBuffer::addSilent(uint nSamples)
|
||||||
return samplesInBuffer;
|
{
|
||||||
}
|
memset(ptrEnd(nSamples), 0, sizeof(SAMPLETYPE) * nSamples * channels);
|
||||||
|
samplesInBuffer += nSamples;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,259 +1,314 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// General FIR digital filter routines with MMX optimization.
|
/// General FIR digital filter routines with MMX optimization.
|
||||||
///
|
///
|
||||||
/// Note : MMX optimized functions reside in a separate, platform-specific file,
|
/// Notes : MMX optimized functions reside in a separate, platform-specific file,
|
||||||
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
|
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// This source file contains OpenMP optimizations that allow speeding up the
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// corss-correlation algorithm by executing it in several threads / CPU cores
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// in parallel. See the following article link for more detailed discussion
|
||||||
///
|
/// about SoundTouch OpenMP optimizations:
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
/// http://www.softwarecoven.com/parallel-computing-in-embedded-mobile-devices
|
||||||
//
|
///
|
||||||
// Last changed : $Date$
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
// File revision : $Revision: 4 $
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
//
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
// $Id$
|
///
|
||||||
//
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
//
|
||||||
//
|
// License :
|
||||||
// License :
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// SoundTouch audio processing library
|
// Copyright (c) Olli Parviainen
|
||||||
// Copyright (c) Olli Parviainen
|
//
|
||||||
//
|
// This library is free software; you can redistribute it and/or
|
||||||
// This library is free software; you can redistribute it and/or
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// License as published by the Free Software Foundation; either
|
||||||
// License as published by the Free Software Foundation; either
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// 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,
|
||||||
// This library is distributed in the hope that it will be useful,
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// Lesser General Public License for more details.
|
||||||
// Lesser General Public License for more details.
|
//
|
||||||
//
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
// License along with this library; if not, write to the Free Software
|
||||||
// License along with this library; if not, write to the Free Software
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
//
|
||||||
//
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
#include <memory.h>
|
||||||
#include <memory.h>
|
#include <assert.h>
|
||||||
#include <assert.h>
|
#include <math.h>
|
||||||
#include <math.h>
|
#include <stdlib.h>
|
||||||
#include <stdlib.h>
|
#include "FIRFilter.h"
|
||||||
#include "FIRFilter.h"
|
#include "cpu_detect.h"
|
||||||
#include "cpu_detect.h"
|
|
||||||
|
using namespace soundtouch;
|
||||||
using namespace soundtouch;
|
|
||||||
|
/*****************************************************************************
|
||||||
/*****************************************************************************
|
*
|
||||||
*
|
* Implementation of the class 'FIRFilter'
|
||||||
* Implementation of the class 'FIRFilter'
|
*
|
||||||
*
|
*****************************************************************************/
|
||||||
*****************************************************************************/
|
|
||||||
|
FIRFilter::FIRFilter()
|
||||||
FIRFilter::FIRFilter()
|
{
|
||||||
{
|
resultDivFactor = 0;
|
||||||
resultDivFactor = 0;
|
length = 0;
|
||||||
resultDivider = 0;
|
lengthDiv8 = 0;
|
||||||
length = 0;
|
filterCoeffs = nullptr;
|
||||||
lengthDiv8 = 0;
|
filterCoeffsStereo = nullptr;
|
||||||
filterCoeffs = NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
FIRFilter::~FIRFilter()
|
||||||
FIRFilter::~FIRFilter()
|
{
|
||||||
{
|
delete[] filterCoeffs;
|
||||||
delete[] filterCoeffs;
|
delete[] filterCoeffsStereo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usual C-version of the filter routine for stereo sound
|
|
||||||
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
// Usual C-version of the filter routine for stereo sound
|
||||||
{
|
uint FIRFilter::evaluateFilterStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
||||||
uint i, j, end;
|
{
|
||||||
LONG_SAMPLETYPE suml, sumr;
|
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;
|
assert((length != 0) && (length == ilength) && (src != nullptr) && (dest != nullptr) && (filterCoeffs != nullptr));
|
||||||
#endif
|
assert(numSamples > ilength);
|
||||||
|
|
||||||
assert(length != 0);
|
end = 2 * (numSamples - ilength);
|
||||||
assert(src != NULL);
|
|
||||||
assert(dest != NULL);
|
#pragma omp parallel for
|
||||||
assert(filterCoeffs != NULL);
|
for (j = 0; j < end; j += 2)
|
||||||
|
{
|
||||||
end = 2 * (numSamples - length);
|
const SAMPLETYPE *ptr;
|
||||||
|
LONG_SAMPLETYPE suml, sumr;
|
||||||
for (j = 0; j < end; j += 2)
|
|
||||||
{
|
suml = sumr = 0;
|
||||||
const SAMPLETYPE *ptr;
|
ptr = src + j;
|
||||||
|
|
||||||
suml = sumr = 0;
|
for (uint i = 0; i < ilength; i ++)
|
||||||
ptr = src + j;
|
{
|
||||||
|
suml += ptr[2 * i] * filterCoeffsStereo[2 * i];
|
||||||
for (i = 0; i < length; i += 4)
|
sumr += ptr[2 * i + 1] * filterCoeffsStereo[2 * i + 1];
|
||||||
{
|
}
|
||||||
// loop is unrolled by factor of 4 here for efficiency
|
|
||||||
suml += ptr[2 * i + 0] * filterCoeffs[i + 0] +
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
ptr[2 * i + 2] * filterCoeffs[i + 1] +
|
suml >>= resultDivFactor;
|
||||||
ptr[2 * i + 4] * filterCoeffs[i + 2] +
|
sumr >>= resultDivFactor;
|
||||||
ptr[2 * i + 6] * filterCoeffs[i + 3];
|
// saturate to 16 bit integer limits
|
||||||
sumr += ptr[2 * i + 1] * filterCoeffs[i + 0] +
|
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
|
||||||
ptr[2 * i + 3] * filterCoeffs[i + 1] +
|
// saturate to 16 bit integer limits
|
||||||
ptr[2 * i + 5] * filterCoeffs[i + 2] +
|
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
|
||||||
ptr[2 * i + 7] * filterCoeffs[i + 3];
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
}
|
dest[j] = (SAMPLETYPE)suml;
|
||||||
|
dest[j + 1] = (SAMPLETYPE)sumr;
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
}
|
||||||
suml >>= resultDivFactor;
|
return numSamples - ilength;
|
||||||
sumr >>= resultDivFactor;
|
}
|
||||||
// saturate to 16 bit integer limits
|
|
||||||
suml = (suml < -32768) ? -32768 : (suml > 32767) ? 32767 : suml;
|
|
||||||
// saturate to 16 bit integer limits
|
// Usual C-version of the filter routine for mono sound
|
||||||
sumr = (sumr < -32768) ? -32768 : (sumr > 32767) ? 32767 : sumr;
|
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
||||||
#else
|
{
|
||||||
suml *= dScaler;
|
int j, end;
|
||||||
sumr *= dScaler;
|
|
||||||
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
// hint compiler autovectorization that loop length is divisible by 8
|
||||||
dest[j] = (SAMPLETYPE)suml;
|
int ilength = length & -8;
|
||||||
dest[j + 1] = (SAMPLETYPE)sumr;
|
|
||||||
}
|
assert(ilength != 0);
|
||||||
return numSamples - length;
|
|
||||||
}
|
end = numSamples - ilength;
|
||||||
|
#pragma omp parallel for
|
||||||
|
for (j = 0; j < end; j ++)
|
||||||
|
{
|
||||||
|
const SAMPLETYPE *pSrc = src + j;
|
||||||
// Usual C-version of the filter routine for mono sound
|
LONG_SAMPLETYPE sum;
|
||||||
uint FIRFilter::evaluateFilterMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples) const
|
int i;
|
||||||
{
|
|
||||||
uint i, j, end;
|
sum = 0;
|
||||||
LONG_SAMPLETYPE sum;
|
for (i = 0; i < ilength; i ++)
|
||||||
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
{
|
||||||
// when using floating point samples, use a scaler instead of a divider
|
sum += pSrc[i] * filterCoeffs[i];
|
||||||
// because division is much slower operation than multiplying.
|
}
|
||||||
double dScaler = 1.0 / (double)resultDivider;
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
#endif
|
sum >>= resultDivFactor;
|
||||||
|
// saturate to 16 bit integer limits
|
||||||
|
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
|
||||||
assert(length != 0);
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
|
dest[j] = (SAMPLETYPE)sum;
|
||||||
end = numSamples - length;
|
}
|
||||||
for (j = 0; j < end; j ++)
|
return end;
|
||||||
{
|
}
|
||||||
sum = 0;
|
|
||||||
for (i = 0; i < length; i += 4)
|
|
||||||
{
|
uint FIRFilter::evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
|
||||||
// loop is unrolled by factor of 4 here for efficiency
|
{
|
||||||
sum += src[i + 0] * filterCoeffs[i + 0] +
|
int j, end;
|
||||||
src[i + 1] * filterCoeffs[i + 1] +
|
|
||||||
src[i + 2] * filterCoeffs[i + 2] +
|
assert(length != 0);
|
||||||
src[i + 3] * filterCoeffs[i + 3];
|
assert(src != nullptr);
|
||||||
}
|
assert(dest != nullptr);
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
assert(filterCoeffs != nullptr);
|
||||||
sum >>= resultDivFactor;
|
assert(numChannels <= SOUNDTOUCH_MAX_CHANNELS);
|
||||||
// saturate to 16 bit integer limits
|
|
||||||
sum = (sum < -32768) ? -32768 : (sum > 32767) ? 32767 : sum;
|
// hint compiler autovectorization that loop length is divisible by 8
|
||||||
#else
|
int ilength = length & -8;
|
||||||
sum *= dScaler;
|
|
||||||
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
end = numChannels * (numSamples - ilength);
|
||||||
dest[j] = (SAMPLETYPE)sum;
|
|
||||||
src ++;
|
#pragma omp parallel for
|
||||||
}
|
for (j = 0; j < end; j += numChannels)
|
||||||
return end;
|
{
|
||||||
}
|
const SAMPLETYPE *ptr;
|
||||||
|
LONG_SAMPLETYPE sums[16];
|
||||||
|
uint c;
|
||||||
// Set filter coeffiecients and length.
|
int i;
|
||||||
//
|
|
||||||
// Throws an exception if filter length isn't divisible by 8
|
for (c = 0; c < numChannels; c ++)
|
||||||
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
|
{
|
||||||
{
|
sums[c] = 0;
|
||||||
assert(newLength > 0);
|
}
|
||||||
if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8");
|
|
||||||
|
ptr = src + j;
|
||||||
lengthDiv8 = newLength / 8;
|
|
||||||
length = lengthDiv8 * 8;
|
for (i = 0; i < ilength; i ++)
|
||||||
assert(length == newLength);
|
{
|
||||||
|
SAMPLETYPE coef=filterCoeffs[i];
|
||||||
resultDivFactor = uResultDivFactor;
|
for (c = 0; c < numChannels; c ++)
|
||||||
resultDivider = (SAMPLETYPE)::pow(2.0, (int)resultDivFactor);
|
{
|
||||||
|
sums[c] += ptr[0] * coef;
|
||||||
delete[] filterCoeffs;
|
ptr ++;
|
||||||
filterCoeffs = new SAMPLETYPE[length];
|
}
|
||||||
memcpy(filterCoeffs, coeffs, length * sizeof(SAMPLETYPE));
|
}
|
||||||
}
|
|
||||||
|
for (c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
uint FIRFilter::getLength() const
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
{
|
sums[c] >>= resultDivFactor;
|
||||||
return length;
|
#endif // SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
}
|
dest[j+c] = (SAMPLETYPE)sums[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return numSamples - ilength;
|
||||||
// Applies the filter to the given sequence of samples.
|
}
|
||||||
//
|
|
||||||
// Note : The amount of outputted samples is by value of 'filter_length'
|
|
||||||
// smaller than the amount of input samples.
|
// Set filter coeffiecients and length.
|
||||||
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels) const
|
//
|
||||||
{
|
// Throws an exception if filter length isn't divisible by 8
|
||||||
assert(numChannels == 1 || numChannels == 2);
|
void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint uResultDivFactor)
|
||||||
|
{
|
||||||
assert(length > 0);
|
assert(newLength > 0);
|
||||||
assert(lengthDiv8 * 8 == length);
|
if (newLength % 8) ST_THROW_RT_ERROR("FIR filter length not divisible by 8");
|
||||||
if (numSamples < length) return 0;
|
|
||||||
if (numChannels == 2)
|
lengthDiv8 = newLength / 8;
|
||||||
{
|
length = lengthDiv8 * 8;
|
||||||
return evaluateFilterStereo(dest, src, numSamples);
|
assert(length == newLength);
|
||||||
} else {
|
|
||||||
return evaluateFilterMono(dest, src, numSamples);
|
resultDivFactor = uResultDivFactor;
|
||||||
}
|
|
||||||
}
|
delete[] filterCoeffs;
|
||||||
|
filterCoeffs = new SAMPLETYPE[length];
|
||||||
|
delete[] filterCoeffsStereo;
|
||||||
|
filterCoeffsStereo = new SAMPLETYPE[length*2];
|
||||||
// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
|
||||||
// depending on if we've a MMX-capable CPU available or not.
|
#ifdef SOUNDTOUCH_FLOAT_SAMPLES
|
||||||
void * FIRFilter::operator new(size_t s)
|
// scale coefficients already here if using floating samples
|
||||||
{
|
const double scale = ::pow(0.5, (int)resultDivFactor);;
|
||||||
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
|
#else
|
||||||
ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
|
const short scale = 1;
|
||||||
return newInstance();
|
#endif
|
||||||
}
|
|
||||||
|
for (uint i = 0; i < length; i ++)
|
||||||
|
{
|
||||||
FIRFilter * FIRFilter::newInstance()
|
filterCoeffs[i] = (SAMPLETYPE)(coeffs[i] * scale);
|
||||||
{
|
// create also stereo set of filter coefficients: this allows compiler
|
||||||
uint uExtensions;
|
// to autovectorize filter evaluation much more efficiently
|
||||||
|
filterCoeffsStereo[2 * i] = (SAMPLETYPE)(coeffs[i] * scale);
|
||||||
uExtensions = detectCPUextensions();
|
filterCoeffsStereo[2 * i + 1] = (SAMPLETYPE)(coeffs[i] * scale);
|
||||||
|
}
|
||||||
// Check if MMX/SSE instruction set extensions supported by CPU
|
}
|
||||||
|
|
||||||
#ifdef SOUNDTOUCH_ALLOW_MMX
|
|
||||||
// MMX routines available only with integer sample types
|
uint FIRFilter::getLength() const
|
||||||
if (uExtensions & SUPPORT_MMX)
|
{
|
||||||
{
|
return length;
|
||||||
return ::new FIRFilterMMX;
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif // SOUNDTOUCH_ALLOW_MMX
|
// Applies the filter to the given sequence of samples.
|
||||||
|
//
|
||||||
#ifdef SOUNDTOUCH_ALLOW_SSE
|
// Note : The amount of outputted samples is by value of 'filter_length'
|
||||||
if (uExtensions & SUPPORT_SSE)
|
// smaller than the amount of input samples.
|
||||||
{
|
uint FIRFilter::evaluate(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels)
|
||||||
// SSE support
|
{
|
||||||
return ::new FIRFilterSSE;
|
assert(length > 0);
|
||||||
}
|
assert(lengthDiv8 * 8 == length);
|
||||||
else
|
|
||||||
#endif // SOUNDTOUCH_ALLOW_SSE
|
if (numSamples < length) return 0;
|
||||||
|
|
||||||
{
|
#ifndef USE_MULTICH_ALWAYS
|
||||||
// ISA optimizations not supported, use plain C version
|
if (numChannels == 1)
|
||||||
return ::new FIRFilter;
|
{
|
||||||
}
|
return evaluateFilterMono(dest, src, numSamples);
|
||||||
}
|
}
|
||||||
|
else if (numChannels == 2)
|
||||||
|
{
|
||||||
|
return evaluateFilterStereo(dest, src, numSamples);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // USE_MULTICH_ALWAYS
|
||||||
|
{
|
||||||
|
assert(numChannels > 0);
|
||||||
|
return evaluateFilterMulti(dest, src, numSamples, numChannels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
||||||
|
// depending on if we've a MMX-capable CPU available or not.
|
||||||
|
void * FIRFilter::operator new(size_t)
|
||||||
|
{
|
||||||
|
// Notice! don't use "new FIRFilter" directly, use "newInstance" to create a new instance instead!
|
||||||
|
ST_THROW_RT_ERROR("Error in FIRFilter::new: Don't use 'new FIRFilter', use 'newInstance' member instead!");
|
||||||
|
return newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FIRFilter * FIRFilter::newInstance()
|
||||||
|
{
|
||||||
|
uint uExtensions;
|
||||||
|
|
||||||
|
uExtensions = detectCPUextensions();
|
||||||
|
(void)uExtensions;
|
||||||
|
|
||||||
|
// Check if MMX/SSE instruction set extensions supported by CPU
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
|
// MMX routines available only with integer sample types
|
||||||
|
if (uExtensions & SUPPORT_MMX)
|
||||||
|
{
|
||||||
|
return ::new FIRFilterMMX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|
||||||
|
#ifdef SOUNDTOUCH_ALLOW_SSE
|
||||||
|
if (uExtensions & SUPPORT_SSE)
|
||||||
|
{
|
||||||
|
// SSE support
|
||||||
|
return ::new FIRFilterSSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_SSE
|
||||||
|
|
||||||
|
{
|
||||||
|
// ISA optimizations not supported, use plain C version
|
||||||
|
return ::new FIRFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,145 +1,137 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// General FIR digital filter routines with MMX optimization.
|
/// General FIR digital filter routines with MMX optimization.
|
||||||
///
|
///
|
||||||
/// Note : MMX optimized functions reside in a separate, platform-specific file,
|
/// Note : MMX optimized functions reside in a separate, platform-specific file,
|
||||||
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
|
/// e.g. 'mmx_win.cpp' or 'mmx_gcc.cpp'
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef FIRFilter_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define FIRFilter_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <stddef.h>
|
||||||
//
|
#include "STTypes.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
namespace soundtouch
|
||||||
#ifndef FIRFilter_H
|
{
|
||||||
#define FIRFilter_H
|
|
||||||
|
class FIRFilter
|
||||||
#include <stddef.h>
|
{
|
||||||
#include "STTypes.h"
|
protected:
|
||||||
|
// Number of FIR filter taps
|
||||||
namespace soundtouch
|
uint length;
|
||||||
{
|
// Number of FIR filter taps divided by 8
|
||||||
|
uint lengthDiv8;
|
||||||
class FIRFilter
|
|
||||||
{
|
// Result divider factor in 2^k format
|
||||||
protected:
|
uint resultDivFactor;
|
||||||
// Number of FIR filter taps
|
|
||||||
uint length;
|
// Memory for filter coefficients
|
||||||
// Number of FIR filter taps divided by 8
|
SAMPLETYPE *filterCoeffs;
|
||||||
uint lengthDiv8;
|
SAMPLETYPE *filterCoeffsStereo;
|
||||||
|
|
||||||
// Result divider factor in 2^k format
|
virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
|
||||||
uint resultDivFactor;
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples) const;
|
||||||
// Result divider value.
|
virtual uint evaluateFilterMono(SAMPLETYPE *dest,
|
||||||
SAMPLETYPE resultDivider;
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples) const;
|
||||||
// Memory for filter coefficients
|
virtual uint evaluateFilterMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, uint numSamples, uint numChannels);
|
||||||
SAMPLETYPE *filterCoeffs;
|
|
||||||
|
public:
|
||||||
virtual uint evaluateFilterStereo(SAMPLETYPE *dest,
|
FIRFilter();
|
||||||
const SAMPLETYPE *src,
|
virtual ~FIRFilter();
|
||||||
uint numSamples) const;
|
|
||||||
virtual uint evaluateFilterMono(SAMPLETYPE *dest,
|
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
||||||
const SAMPLETYPE *src,
|
/// depending on if we've a MMX-capable CPU available or not.
|
||||||
uint numSamples) const;
|
static void * operator new(size_t s);
|
||||||
|
|
||||||
public:
|
static FIRFilter *newInstance();
|
||||||
FIRFilter();
|
|
||||||
virtual ~FIRFilter();
|
/// Applies the filter to the given sequence of samples.
|
||||||
|
/// Note : The amount of outputted samples is by value of 'filter_length'
|
||||||
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
/// smaller than the amount of input samples.
|
||||||
/// depending on if we've a MMX-capable CPU available or not.
|
///
|
||||||
static void * operator new(size_t s);
|
/// \return Number of samples copied to 'dest'.
|
||||||
|
uint evaluate(SAMPLETYPE *dest,
|
||||||
static FIRFilter *newInstance();
|
const SAMPLETYPE *src,
|
||||||
|
uint numSamples,
|
||||||
/// Applies the filter to the given sequence of samples.
|
uint numChannels);
|
||||||
/// Note : The amount of outputted samples is by value of 'filter_length'
|
|
||||||
/// smaller than the amount of input samples.
|
uint getLength() const;
|
||||||
///
|
|
||||||
/// \return Number of samples copied to 'dest'.
|
virtual void setCoefficients(const SAMPLETYPE *coeffs,
|
||||||
uint evaluate(SAMPLETYPE *dest,
|
uint newLength,
|
||||||
const SAMPLETYPE *src,
|
uint uResultDivFactor);
|
||||||
uint numSamples,
|
};
|
||||||
uint numChannels) const;
|
|
||||||
|
|
||||||
uint getLength() const;
|
// Optional subclasses that implement CPU-specific optimizations:
|
||||||
|
|
||||||
virtual void setCoefficients(const SAMPLETYPE *coeffs,
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
uint newLength,
|
|
||||||
uint uResultDivFactor);
|
/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
|
||||||
};
|
class FIRFilterMMX : public FIRFilter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
// Optional subclasses that implement CPU-specific optimizations:
|
short *filterCoeffsUnalign;
|
||||||
|
short *filterCoeffsAlign;
|
||||||
#ifdef SOUNDTOUCH_ALLOW_MMX
|
|
||||||
|
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const override;
|
||||||
/// Class that implements MMX optimized functions exclusive for 16bit integer samples type.
|
public:
|
||||||
class FIRFilterMMX : public FIRFilter
|
FIRFilterMMX();
|
||||||
{
|
~FIRFilterMMX();
|
||||||
protected:
|
|
||||||
short *filterCoeffsUnalign;
|
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor) override;
|
||||||
short *filterCoeffsAlign;
|
};
|
||||||
|
|
||||||
virtual uint evaluateFilterStereo(short *dest, const short *src, uint numSamples) const;
|
#endif // SOUNDTOUCH_ALLOW_MMX
|
||||||
public:
|
|
||||||
FIRFilterMMX();
|
|
||||||
~FIRFilterMMX();
|
#ifdef SOUNDTOUCH_ALLOW_SSE
|
||||||
|
/// Class that implements SSE optimized functions exclusive for floating point samples type.
|
||||||
virtual void setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor);
|
class FIRFilterSSE : public FIRFilter
|
||||||
};
|
{
|
||||||
|
protected:
|
||||||
#endif // SOUNDTOUCH_ALLOW_MMX
|
float *filterCoeffsUnalign;
|
||||||
|
float *filterCoeffsAlign;
|
||||||
|
|
||||||
#ifdef SOUNDTOUCH_ALLOW_SSE
|
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const override;
|
||||||
/// Class that implements SSE optimized functions exclusive for floating point samples type.
|
public:
|
||||||
class FIRFilterSSE : public FIRFilter
|
FIRFilterSSE();
|
||||||
{
|
~FIRFilterSSE();
|
||||||
protected:
|
|
||||||
float *filterCoeffsUnalign;
|
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor) override;
|
||||||
float *filterCoeffsAlign;
|
};
|
||||||
|
|
||||||
virtual uint evaluateFilterStereo(float *dest, const float *src, uint numSamples) const;
|
#endif // SOUNDTOUCH_ALLOW_SSE
|
||||||
public:
|
|
||||||
FIRFilterSSE();
|
}
|
||||||
~FIRFilterSSE();
|
|
||||||
|
#endif // FIRFilter_H
|
||||||
virtual void setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SOUNDTOUCH_ALLOW_SSE
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FIRFilter_H
|
|
||||||
|
|||||||
196
source/SoundTouch/InterpolateCubic.cpp
Normal file
196
source/SoundTouch/InterpolateCubic.cpp
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Cubic interpolation routine.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "InterpolateCubic.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
// cubic interpolation coefficients
|
||||||
|
static const float _coeffs[]=
|
||||||
|
{ -0.5f, 1.0f, -0.5f, 0.0f,
|
||||||
|
1.5f, -2.5f, 0.0f, 1.0f,
|
||||||
|
-1.5f, 2.0f, 0.5f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.0f, 0.0f};
|
||||||
|
|
||||||
|
|
||||||
|
InterpolateCubic::InterpolateCubic()
|
||||||
|
{
|
||||||
|
fract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpolateCubic::resetRegisters()
|
||||||
|
{
|
||||||
|
fract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Transpose mono audio. Returns number of produced output samples, and
|
||||||
|
/// updates "srcSamples" to amount of consumed source samples
|
||||||
|
int InterpolateCubic::transposeMono(SAMPLETYPE *pdest,
|
||||||
|
const SAMPLETYPE *psrc,
|
||||||
|
int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 4;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
float out;
|
||||||
|
const float x3 = 1.0f;
|
||||||
|
const float x2 = (float)fract; // x
|
||||||
|
const float x1 = x2*x2; // x^2
|
||||||
|
const float x0 = x1*x2; // x^3
|
||||||
|
float y0, y1, y2, y3;
|
||||||
|
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3;
|
||||||
|
y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3;
|
||||||
|
y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;
|
||||||
|
y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;
|
||||||
|
|
||||||
|
out = y0 * psrc[0] + y1 * psrc[1] + y2 * psrc[2] + y3 * psrc[3];
|
||||||
|
|
||||||
|
pdest[i] = (SAMPLETYPE)out;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
psrc += whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Transpose stereo audio. Returns number of produced output samples, and
|
||||||
|
/// updates "srcSamples" to amount of consumed source samples
|
||||||
|
int InterpolateCubic::transposeStereo(SAMPLETYPE *pdest,
|
||||||
|
const SAMPLETYPE *psrc,
|
||||||
|
int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 4;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
const float x3 = 1.0f;
|
||||||
|
const float x2 = (float)fract; // x
|
||||||
|
const float x1 = x2*x2; // x^2
|
||||||
|
const float x0 = x1*x2; // x^3
|
||||||
|
float y0, y1, y2, y3;
|
||||||
|
float out0, out1;
|
||||||
|
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3;
|
||||||
|
y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3;
|
||||||
|
y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;
|
||||||
|
y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;
|
||||||
|
|
||||||
|
out0 = y0 * psrc[0] + y1 * psrc[2] + y2 * psrc[4] + y3 * psrc[6];
|
||||||
|
out1 = y0 * psrc[1] + y1 * psrc[3] + y2 * psrc[5] + y3 * psrc[7];
|
||||||
|
|
||||||
|
pdest[2*i] = (SAMPLETYPE)out0;
|
||||||
|
pdest[2*i+1] = (SAMPLETYPE)out1;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
psrc += 2*whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Transpose multi-channel audio. Returns number of produced output samples, and
|
||||||
|
/// updates "srcSamples" to amount of consumed source samples
|
||||||
|
int InterpolateCubic::transposeMulti(SAMPLETYPE *pdest,
|
||||||
|
const SAMPLETYPE *psrc,
|
||||||
|
int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 4;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
const float x3 = 1.0f;
|
||||||
|
const float x2 = (float)fract; // x
|
||||||
|
const float x1 = x2*x2; // x^2
|
||||||
|
const float x0 = x1*x2; // x^3
|
||||||
|
float y0, y1, y2, y3;
|
||||||
|
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
y0 = _coeffs[0] * x0 + _coeffs[1] * x1 + _coeffs[2] * x2 + _coeffs[3] * x3;
|
||||||
|
y1 = _coeffs[4] * x0 + _coeffs[5] * x1 + _coeffs[6] * x2 + _coeffs[7] * x3;
|
||||||
|
y2 = _coeffs[8] * x0 + _coeffs[9] * x1 + _coeffs[10] * x2 + _coeffs[11] * x3;
|
||||||
|
y3 = _coeffs[12] * x0 + _coeffs[13] * x1 + _coeffs[14] * x2 + _coeffs[15] * x3;
|
||||||
|
|
||||||
|
for (int c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
float out;
|
||||||
|
out = y0 * psrc[c] + y1 * psrc[c + numChannels] + y2 * psrc[c + 2 * numChannels] + y3 * psrc[c + 3 * numChannels];
|
||||||
|
pdest[0] = (SAMPLETYPE)out;
|
||||||
|
pdest ++;
|
||||||
|
}
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
psrc += numChannels*whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
69
source/SoundTouch/InterpolateCubic.h
Normal file
69
source/SoundTouch/InterpolateCubic.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Cubic interpolation routine.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _InterpolateCubic_H_
|
||||||
|
#define _InterpolateCubic_H_
|
||||||
|
|
||||||
|
#include "RateTransposer.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
class InterpolateCubic : public TransposerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual int transposeMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
virtual int transposeMulti(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
|
||||||
|
double fract;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InterpolateCubic();
|
||||||
|
|
||||||
|
virtual void resetRegisters() override;
|
||||||
|
|
||||||
|
virtual int getLatency() const override
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
296
source/SoundTouch/InterpolateLinear.cpp
Normal file
296
source/SoundTouch/InterpolateLinear.cpp
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Linear interpolation algorithm.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "InterpolateLinear.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// InterpolateLinearInteger - integer arithmetic implementation
|
||||||
|
//
|
||||||
|
|
||||||
|
/// fixed-point interpolation routine precision
|
||||||
|
#define SCALE 65536
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
InterpolateLinearInteger::InterpolateLinearInteger() : TransposerBase()
|
||||||
|
{
|
||||||
|
// Notice: use local function calling syntax for sake of clarity,
|
||||||
|
// to indicate the fact that C++ constructor can't call virtual functions.
|
||||||
|
resetRegisters();
|
||||||
|
setRate(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpolateLinearInteger::resetRegisters()
|
||||||
|
{
|
||||||
|
iFract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Mono' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
LONG_SAMPLETYPE temp;
|
||||||
|
|
||||||
|
assert(iFract < SCALE);
|
||||||
|
|
||||||
|
temp = (SCALE - iFract) * src[0] + iFract * src[1];
|
||||||
|
dest[i] = (SAMPLETYPE)(temp / SCALE);
|
||||||
|
i++;
|
||||||
|
|
||||||
|
iFract += iRate;
|
||||||
|
|
||||||
|
int iWhole = iFract / SCALE;
|
||||||
|
iFract -= iWhole * SCALE;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += iWhole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Stereo' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
LONG_SAMPLETYPE temp0;
|
||||||
|
LONG_SAMPLETYPE temp1;
|
||||||
|
|
||||||
|
assert(iFract < SCALE);
|
||||||
|
|
||||||
|
temp0 = (SCALE - iFract) * src[0] + iFract * src[2];
|
||||||
|
temp1 = (SCALE - iFract) * src[1] + iFract * src[3];
|
||||||
|
dest[0] = (SAMPLETYPE)(temp0 / SCALE);
|
||||||
|
dest[1] = (SAMPLETYPE)(temp1 / SCALE);
|
||||||
|
dest += 2;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
iFract += iRate;
|
||||||
|
|
||||||
|
int iWhole = iFract / SCALE;
|
||||||
|
iFract -= iWhole * SCALE;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += 2*iWhole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int InterpolateLinearInteger::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
LONG_SAMPLETYPE temp, vol1;
|
||||||
|
|
||||||
|
assert(iFract < SCALE);
|
||||||
|
vol1 = (LONG_SAMPLETYPE)(SCALE - iFract);
|
||||||
|
for (int c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
temp = vol1 * src[c] + iFract * src[c + numChannels];
|
||||||
|
dest[0] = (SAMPLETYPE)(temp / SCALE);
|
||||||
|
dest ++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
iFract += iRate;
|
||||||
|
|
||||||
|
int iWhole = iFract / SCALE;
|
||||||
|
iFract -= iWhole * SCALE;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += iWhole * numChannels;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
||||||
|
// iRate, larger faster iRates.
|
||||||
|
void InterpolateLinearInteger::setRate(double newRate)
|
||||||
|
{
|
||||||
|
iRate = (int)(newRate * SCALE + 0.5);
|
||||||
|
TransposerBase::setRate(newRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// InterpolateLinearFloat - floating point arithmetic implementation
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
InterpolateLinearFloat::InterpolateLinearFloat() : TransposerBase()
|
||||||
|
{
|
||||||
|
// Notice: use local function calling syntax for sake of clarity,
|
||||||
|
// to indicate the fact that C++ constructor can't call virtual functions.
|
||||||
|
resetRegisters();
|
||||||
|
setRate(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpolateLinearFloat::resetRegisters()
|
||||||
|
{
|
||||||
|
fract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Mono' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
double out;
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
out = (1.0 - fract) * src[0] + fract * src[1];
|
||||||
|
dest[i] = (SAMPLETYPE)out;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
src += whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// 'Mono' version of the routine. Returns the number of samples returned in
|
||||||
|
// the "dest" buffer
|
||||||
|
int InterpolateLinearFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
double out0, out1;
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
out0 = (1.0 - fract) * src[0] + fract * src[2];
|
||||||
|
out1 = (1.0 - fract) * src[1] + fract * src[3];
|
||||||
|
dest[2*i] = (SAMPLETYPE)out0;
|
||||||
|
dest[2*i+1] = (SAMPLETYPE)out1;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
src += 2*whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int InterpolateLinearFloat::transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 1;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
float temp, vol1, fract_float;
|
||||||
|
|
||||||
|
vol1 = (float)(1.0 - fract);
|
||||||
|
fract_float = (float)fract;
|
||||||
|
for (int c = 0; c < numChannels; c ++)
|
||||||
|
{
|
||||||
|
temp = vol1 * src[c] + fract_float * src[c + numChannels];
|
||||||
|
*dest = (SAMPLETYPE)temp;
|
||||||
|
dest ++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
|
||||||
|
fract += rate;
|
||||||
|
|
||||||
|
int iWhole = (int)fract;
|
||||||
|
fract -= iWhole;
|
||||||
|
srcCount += iWhole;
|
||||||
|
src += iWhole * numChannels;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
98
source/SoundTouch/InterpolateLinear.h
Normal file
98
source/SoundTouch/InterpolateLinear.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Linear interpolation routine.
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _InterpolateLinear_H_
|
||||||
|
#define _InterpolateLinear_H_
|
||||||
|
|
||||||
|
#include "RateTransposer.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Linear transposer class that uses integer arithmetic
|
||||||
|
class InterpolateLinearInteger : public TransposerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int iFract;
|
||||||
|
int iRate;
|
||||||
|
|
||||||
|
virtual int transposeMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples) override;
|
||||||
|
public:
|
||||||
|
InterpolateLinearInteger();
|
||||||
|
|
||||||
|
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
|
||||||
|
/// rate, larger faster rates.
|
||||||
|
virtual void setRate(double newRate) override;
|
||||||
|
|
||||||
|
virtual void resetRegisters() override;
|
||||||
|
|
||||||
|
virtual int getLatency() const override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Linear transposer class that uses floating point arithmetic
|
||||||
|
class InterpolateLinearFloat : public TransposerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
double fract;
|
||||||
|
|
||||||
|
virtual int transposeMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples);
|
||||||
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples);
|
||||||
|
virtual int transposeMulti(SAMPLETYPE *dest, const SAMPLETYPE *src, int &srcSamples);
|
||||||
|
|
||||||
|
public:
|
||||||
|
InterpolateLinearFloat();
|
||||||
|
|
||||||
|
virtual void resetRegisters();
|
||||||
|
|
||||||
|
int getLatency() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
181
source/SoundTouch/InterpolateShannon.cpp
Normal file
181
source/SoundTouch/InterpolateShannon.cpp
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation
|
||||||
|
/// with kaiser window.
|
||||||
|
///
|
||||||
|
/// Notice. This algorithm is remarkably much heavier than linear or cubic
|
||||||
|
/// interpolation, and not remarkably better than cubic algorithm. Thus mostly
|
||||||
|
/// for experimental purposes
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include "InterpolateShannon.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
using namespace soundtouch;
|
||||||
|
|
||||||
|
|
||||||
|
/// Kaiser window with beta = 2.0
|
||||||
|
/// Values scaled down by 5% to avoid overflows
|
||||||
|
static const double _kaiser8[8] =
|
||||||
|
{
|
||||||
|
0.41778693317814,
|
||||||
|
0.64888025049173,
|
||||||
|
0.83508562409944,
|
||||||
|
0.93887857733412,
|
||||||
|
0.93887857733412,
|
||||||
|
0.83508562409944,
|
||||||
|
0.64888025049173,
|
||||||
|
0.41778693317814
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
InterpolateShannon::InterpolateShannon()
|
||||||
|
{
|
||||||
|
fract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpolateShannon::resetRegisters()
|
||||||
|
{
|
||||||
|
fract = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define PI 3.1415926536
|
||||||
|
#define sinc(x) (sin(PI * (x)) / (PI * (x)))
|
||||||
|
|
||||||
|
/// Transpose mono audio. Returns number of produced output samples, and
|
||||||
|
/// updates "srcSamples" to amount of consumed source samples
|
||||||
|
int InterpolateShannon::transposeMono(SAMPLETYPE *pdest,
|
||||||
|
const SAMPLETYPE *psrc,
|
||||||
|
int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 8;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
double out;
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
out = psrc[0] * sinc(-3.0 - fract) * _kaiser8[0];
|
||||||
|
out += psrc[1] * sinc(-2.0 - fract) * _kaiser8[1];
|
||||||
|
out += psrc[2] * sinc(-1.0 - fract) * _kaiser8[2];
|
||||||
|
if (fract < 1e-6)
|
||||||
|
{
|
||||||
|
out += psrc[3] * _kaiser8[3]; // sinc(0) = 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out += psrc[3] * sinc(- fract) * _kaiser8[3];
|
||||||
|
}
|
||||||
|
out += psrc[4] * sinc( 1.0 - fract) * _kaiser8[4];
|
||||||
|
out += psrc[5] * sinc( 2.0 - fract) * _kaiser8[5];
|
||||||
|
out += psrc[6] * sinc( 3.0 - fract) * _kaiser8[6];
|
||||||
|
out += psrc[7] * sinc( 4.0 - fract) * _kaiser8[7];
|
||||||
|
|
||||||
|
pdest[i] = (SAMPLETYPE)out;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
psrc += whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Transpose stereo audio. Returns number of produced output samples, and
|
||||||
|
/// updates "srcSamples" to amount of consumed source samples
|
||||||
|
int InterpolateShannon::transposeStereo(SAMPLETYPE *pdest,
|
||||||
|
const SAMPLETYPE *psrc,
|
||||||
|
int &srcSamples)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int srcSampleEnd = srcSamples - 8;
|
||||||
|
int srcCount = 0;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (srcCount < srcSampleEnd)
|
||||||
|
{
|
||||||
|
double out0, out1, w;
|
||||||
|
assert(fract < 1.0);
|
||||||
|
|
||||||
|
w = sinc(-3.0 - fract) * _kaiser8[0];
|
||||||
|
out0 = psrc[0] * w; out1 = psrc[1] * w;
|
||||||
|
w = sinc(-2.0 - fract) * _kaiser8[1];
|
||||||
|
out0 += psrc[2] * w; out1 += psrc[3] * w;
|
||||||
|
w = sinc(-1.0 - fract) * _kaiser8[2];
|
||||||
|
out0 += psrc[4] * w; out1 += psrc[5] * w;
|
||||||
|
w = _kaiser8[3] * ((fract < 1e-5) ? 1.0 : sinc(- fract)); // sinc(0) = 1
|
||||||
|
out0 += psrc[6] * w; out1 += psrc[7] * w;
|
||||||
|
w = sinc( 1.0 - fract) * _kaiser8[4];
|
||||||
|
out0 += psrc[8] * w; out1 += psrc[9] * w;
|
||||||
|
w = sinc( 2.0 - fract) * _kaiser8[5];
|
||||||
|
out0 += psrc[10] * w; out1 += psrc[11] * w;
|
||||||
|
w = sinc( 3.0 - fract) * _kaiser8[6];
|
||||||
|
out0 += psrc[12] * w; out1 += psrc[13] * w;
|
||||||
|
w = sinc( 4.0 - fract) * _kaiser8[7];
|
||||||
|
out0 += psrc[14] * w; out1 += psrc[15] * w;
|
||||||
|
|
||||||
|
pdest[2*i] = (SAMPLETYPE)out0;
|
||||||
|
pdest[2*i+1] = (SAMPLETYPE)out1;
|
||||||
|
i ++;
|
||||||
|
|
||||||
|
// update position fraction
|
||||||
|
fract += rate;
|
||||||
|
// update whole positions
|
||||||
|
int whole = (int)fract;
|
||||||
|
fract -= whole;
|
||||||
|
psrc += 2*whole;
|
||||||
|
srcCount += whole;
|
||||||
|
}
|
||||||
|
srcSamples = srcCount;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Transpose stereo audio. Returns number of produced output samples, and
|
||||||
|
/// updates "srcSamples" to amount of consumed source samples
|
||||||
|
int InterpolateShannon::transposeMulti(SAMPLETYPE *,
|
||||||
|
const SAMPLETYPE *,
|
||||||
|
int &)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
74
source/SoundTouch/InterpolateShannon.h
Normal file
74
source/SoundTouch/InterpolateShannon.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// Sample interpolation routine using 8-tap band-limited Shannon interpolation
|
||||||
|
/// with kaiser window.
|
||||||
|
///
|
||||||
|
/// Notice. This algorithm is remarkably much heavier than linear or cubic
|
||||||
|
/// interpolation, and not remarkably better than cubic algorithm. Thus mostly
|
||||||
|
/// for experimental purposes
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// License :
|
||||||
|
//
|
||||||
|
// SoundTouch audio processing library
|
||||||
|
// Copyright (c) Olli Parviainen
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU Lesser General Public
|
||||||
|
// License as published by the Free Software Foundation; either
|
||||||
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _InterpolateShannon_H_
|
||||||
|
#define _InterpolateShannon_H_
|
||||||
|
|
||||||
|
#include "RateTransposer.h"
|
||||||
|
#include "STTypes.h"
|
||||||
|
|
||||||
|
namespace soundtouch
|
||||||
|
{
|
||||||
|
|
||||||
|
class InterpolateShannon : public TransposerBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int transposeMono(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
int transposeStereo(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
int transposeMulti(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
|
int &srcSamples) override;
|
||||||
|
|
||||||
|
double fract;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InterpolateShannon();
|
||||||
|
|
||||||
|
void resetRegisters() override;
|
||||||
|
|
||||||
|
virtual int getLatency() const override
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,71 +1,74 @@
|
|||||||
## Process this file with automake to create Makefile.in
|
## Process this file with automake to create Makefile.in
|
||||||
##
|
##
|
||||||
## $Id$
|
## This file is part of SoundTouch, an audio processing library for pitch/time adjustments
|
||||||
##
|
##
|
||||||
## 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
|
||||||
## SoundTouch is free software; you can redistribute it and/or modify it under the
|
## Foundation; either version 2 of the License, or (at your option) any later
|
||||||
## terms of the GNU General Public License as published by the Free Software
|
## version.
|
||||||
## 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
|
||||||
## SoundTouch is distributed in the hope that it will be useful, but WITHOUT ANY
|
## A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
## 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
|
||||||
## You should have received a copy of the GNU General Public License along with
|
## Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
## 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
|
||||||
|
|
||||||
include $(top_srcdir)/config/am_include.mk
|
|
||||||
|
# set to something if you want other stuff to be included in the distribution tarball
|
||||||
|
EXTRA_DIST=SoundTouch.sln SoundTouch.vcxproj
|
||||||
# set to something if you want other stuff to be included in the distribution tarball
|
|
||||||
EXTRA_DIST=SoundTouch.dsp SoundTouch.dsw SoundTouch.sln SoundTouch.vcproj
|
noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h \
|
||||||
|
InterpolateCubic.h InterpolateLinear.h InterpolateShannon.h
|
||||||
noinst_HEADERS=AAFilter.h cpu_detect.h cpu_detect_x86.cpp FIRFilter.h RateTransposer.h TDStretch.h PeakFinder.h
|
|
||||||
|
lib_LTLIBRARIES=libSoundTouch.la
|
||||||
lib_LTLIBRARIES=libSoundTouch.la
|
#
|
||||||
#
|
libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp \
|
||||||
libSoundTouch_la_SOURCES=AAFilter.cpp FIRFilter.cpp FIFOSampleBuffer.cpp RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp BPMDetect.cpp PeakFinder.cpp
|
RateTransposer.cpp SoundTouch.cpp TDStretch.cpp cpu_detect_x86.cpp \
|
||||||
|
BPMDetect.cpp PeakFinder.cpp InterpolateLinear.cpp InterpolateCubic.cpp \
|
||||||
|
InterpolateShannon.cpp
|
||||||
# Compiler flags
|
|
||||||
AM_CXXFLAGS=-O3 -fcheck-new -I../../include
|
# Compiler flags
|
||||||
|
#AM_CXXFLAGS+=
|
||||||
# Compile the files that need MMX and SSE individually.
|
|
||||||
libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la
|
# Compile the files that need MMX and SSE individually.
|
||||||
noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la
|
libSoundTouch_la_LIBADD=libSoundTouchMMX.la libSoundTouchSSE.la
|
||||||
libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp
|
noinst_LTLIBRARIES=libSoundTouchMMX.la libSoundTouchSSE.la
|
||||||
libSoundTouchSSE_la_SOURCES=sse_optimized.cpp
|
libSoundTouchMMX_la_SOURCES=mmx_optimized.cpp
|
||||||
|
libSoundTouchSSE_la_SOURCES=sse_optimized.cpp
|
||||||
# We enable optimizations by default.
|
|
||||||
# If MMX is supported compile with -mmmx.
|
# We enable optimizations by default.
|
||||||
# Do not assume -msse is also supported.
|
# If MMX is supported compile with -mmmx.
|
||||||
if HAVE_MMX
|
# Do not assume -msse is also supported.
|
||||||
libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS)
|
if HAVE_MMX
|
||||||
else
|
libSoundTouchMMX_la_CXXFLAGS = -mmmx $(AM_CXXFLAGS)
|
||||||
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
|
else
|
||||||
endif
|
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||||
|
endif
|
||||||
# We enable optimizations by default.
|
|
||||||
# If SSE is supported compile with -msse.
|
# We enable optimizations by default.
|
||||||
if HAVE_SSE
|
# If SSE is supported compile with -msse.
|
||||||
libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS)
|
if HAVE_SSE
|
||||||
else
|
libSoundTouchSSE_la_CXXFLAGS = -msse $(AM_CXXFLAGS)
|
||||||
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
|
else
|
||||||
endif
|
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||||
|
endif
|
||||||
# Let the user disable optimizations if he wishes to.
|
|
||||||
if !X86_OPTIMIZATIONS
|
# Let the user disable optimizations if he wishes to.
|
||||||
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
|
if !X86_OPTIMIZATIONS
|
||||||
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
|
libSoundTouchMMX_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||||
endif
|
libSoundTouchSSE_la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
# other linking flags to add
|
# Modify the default 0.0.0 to LIB_SONAME.0.0
|
||||||
# noinst_LTLIBRARIES = libSoundTouchOpt.la
|
libSoundTouch_la_LDFLAGS=-version-info @LIB_SONAME@
|
||||||
# libSoundTouch_la_LIBADD = libSoundTouchOpt.la
|
|
||||||
# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp
|
# other linking flags to add
|
||||||
# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include
|
# noinst_LTLIBRARIES = libSoundTouchOpt.la
|
||||||
|
# libSoundTouch_la_LIBADD = libSoundTouchOpt.la
|
||||||
|
# libSoundTouchOpt_la_SOURCES = mmx_optimized.cpp sse_optimized.cpp
|
||||||
|
# libSoundTouchOpt_la_CXXFLAGS = -O3 -msse -fcheck-new -I../../include
|
||||||
|
|||||||
@ -1,278 +1,277 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Peak detection routine.
|
/// Peak detection routine.
|
||||||
///
|
///
|
||||||
/// The routine detects highest value on an array of values and calculates the
|
/// The routine detects highest value on an array of values and calculates the
|
||||||
/// precise peak location as a mass-center of the 'hump' around the peak value.
|
/// precise peak location as a mass-center of the 'hump' around the peak value.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include <math.h>
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include <assert.h>
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include "PeakFinder.h"
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
using namespace soundtouch;
|
||||||
|
|
||||||
#include <math.h>
|
#define max(x, y) (((x) > (y)) ? (x) : (y))
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#include "PeakFinder.h"
|
PeakFinder::PeakFinder()
|
||||||
|
{
|
||||||
using namespace soundtouch;
|
minPos = maxPos = 0;
|
||||||
|
}
|
||||||
#define max(x, y) (((x) > (y)) ? (x) : (y))
|
|
||||||
|
|
||||||
|
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
|
||||||
PeakFinder::PeakFinder()
|
int PeakFinder::findTop(const float *data, int peakpos) const
|
||||||
{
|
{
|
||||||
minPos = maxPos = 0;
|
int i;
|
||||||
}
|
int start, end;
|
||||||
|
float refvalue;
|
||||||
|
|
||||||
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
|
refvalue = data[peakpos];
|
||||||
int PeakFinder::findTop(const float *data, int peakpos) const
|
|
||||||
{
|
// seek within ±10 points
|
||||||
int i;
|
start = peakpos - 10;
|
||||||
int start, end;
|
if (start < minPos) start = minPos;
|
||||||
float refvalue;
|
end = peakpos + 10;
|
||||||
|
if (end > maxPos) end = maxPos;
|
||||||
refvalue = data[peakpos];
|
|
||||||
|
for (i = start; i <= end; i ++)
|
||||||
// seek within ±10 points
|
{
|
||||||
start = peakpos - 10;
|
if (data[i] > refvalue)
|
||||||
if (start < minPos) start = minPos;
|
{
|
||||||
end = peakpos + 10;
|
peakpos = i;
|
||||||
if (end > maxPos) end = maxPos;
|
refvalue = data[i];
|
||||||
|
}
|
||||||
for (i = start; i <= end; i ++)
|
}
|
||||||
{
|
|
||||||
if (data[i] > refvalue)
|
// failure if max value is at edges of seek range => it's not peak, it's at slope.
|
||||||
{
|
if ((peakpos == start) || (peakpos == end)) return 0;
|
||||||
peakpos = i;
|
|
||||||
refvalue = data[i];
|
return peakpos;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// failure if max value is at edges of seek range => it's not peak, it's at slope.
|
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding
|
||||||
if ((peakpos == start) || (peakpos == end)) return 0;
|
// to direction defined by 'direction' until next 'hump' after minimum value will
|
||||||
|
// begin
|
||||||
return peakpos;
|
int PeakFinder::findGround(const float *data, int peakpos, int direction) const
|
||||||
}
|
{
|
||||||
|
int lowpos;
|
||||||
|
int pos;
|
||||||
// Finds 'ground level' of a peak hump by starting from 'peakpos' and proceeding
|
int climb_count;
|
||||||
// to direction defined by 'direction' until next 'hump' after minimum value will
|
float refvalue;
|
||||||
// begin
|
float delta;
|
||||||
int PeakFinder::findGround(const float *data, int peakpos, int direction) const
|
|
||||||
{
|
climb_count = 0;
|
||||||
int lowpos;
|
refvalue = data[peakpos];
|
||||||
int pos;
|
lowpos = peakpos;
|
||||||
int climb_count;
|
|
||||||
float refvalue;
|
pos = peakpos;
|
||||||
float delta;
|
|
||||||
|
while ((pos > minPos+1) && (pos < maxPos-1))
|
||||||
climb_count = 0;
|
{
|
||||||
refvalue = data[peakpos];
|
int prevpos;
|
||||||
lowpos = peakpos;
|
|
||||||
|
prevpos = pos;
|
||||||
pos = peakpos;
|
pos += direction;
|
||||||
|
|
||||||
while ((pos > minPos+1) && (pos < maxPos-1))
|
// calculate derivate
|
||||||
{
|
delta = data[pos] - data[prevpos];
|
||||||
int prevpos;
|
if (delta <= 0)
|
||||||
|
{
|
||||||
prevpos = pos;
|
// going downhill, ok
|
||||||
pos += direction;
|
if (climb_count)
|
||||||
|
{
|
||||||
// calculate derivate
|
climb_count --; // decrease climb count
|
||||||
delta = data[pos] - data[prevpos];
|
}
|
||||||
if (delta <= 0)
|
|
||||||
{
|
// check if new minimum found
|
||||||
// going downhill, ok
|
if (data[pos] < refvalue)
|
||||||
if (climb_count)
|
{
|
||||||
{
|
// new minimum found
|
||||||
climb_count --; // decrease climb count
|
lowpos = pos;
|
||||||
}
|
refvalue = data[pos];
|
||||||
|
}
|
||||||
// check if new minimum found
|
}
|
||||||
if (data[pos] < refvalue)
|
else
|
||||||
{
|
{
|
||||||
// new minimum found
|
// going uphill, increase climbing counter
|
||||||
lowpos = pos;
|
climb_count ++;
|
||||||
refvalue = data[pos];
|
if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
return lowpos;
|
||||||
{
|
}
|
||||||
// going uphill, increase climbing counter
|
|
||||||
climb_count ++;
|
|
||||||
if (climb_count > 5) break; // we've been climbing too long => it's next uphill => quit
|
// Find offset where the value crosses the given level, when starting from 'peakpos' and
|
||||||
}
|
// proceeds to direction defined in 'direction'
|
||||||
}
|
int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const
|
||||||
return lowpos;
|
{
|
||||||
}
|
float peaklevel;
|
||||||
|
int pos;
|
||||||
|
|
||||||
// Find offset where the value crosses the given level, when starting from 'peakpos' and
|
peaklevel = data[peakpos];
|
||||||
// proceeds to direction defined in 'direction'
|
assert(peaklevel >= level);
|
||||||
int PeakFinder::findCrossingLevel(const float *data, float level, int peakpos, int direction) const
|
pos = peakpos;
|
||||||
{
|
while ((pos >= minPos) && (pos + direction < maxPos))
|
||||||
float peaklevel;
|
{
|
||||||
int pos;
|
if (data[pos + direction] < level) return pos; // crossing found
|
||||||
|
pos += direction;
|
||||||
peaklevel = data[peakpos];
|
}
|
||||||
assert(peaklevel >= level);
|
return -1; // not found
|
||||||
pos = peakpos;
|
}
|
||||||
while ((pos >= minPos) && (pos < maxPos))
|
|
||||||
{
|
|
||||||
if (data[pos + direction] < level) return pos; // crossing found
|
// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos'
|
||||||
pos += direction;
|
double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const
|
||||||
}
|
{
|
||||||
return -1; // not found
|
int i;
|
||||||
}
|
float sum;
|
||||||
|
float wsum;
|
||||||
|
|
||||||
// Calculates the center of mass location of 'data' array items between 'firstPos' and 'lastPos'
|
sum = 0;
|
||||||
double PeakFinder::calcMassCenter(const float *data, int firstPos, int lastPos) const
|
wsum = 0;
|
||||||
{
|
for (i = firstPos; i <= lastPos; i ++)
|
||||||
int i;
|
{
|
||||||
float sum;
|
sum += (float)i * data[i];
|
||||||
float wsum;
|
wsum += data[i];
|
||||||
|
}
|
||||||
sum = 0;
|
|
||||||
wsum = 0;
|
if (wsum < 1e-6) return 0;
|
||||||
for (i = firstPos; i <= lastPos; i ++)
|
return sum / wsum;
|
||||||
{
|
}
|
||||||
sum += (float)i * data[i];
|
|
||||||
wsum += data[i];
|
|
||||||
}
|
/// get exact center of peak near given position by calculating local mass of center
|
||||||
|
double PeakFinder::getPeakCenter(const float *data, int peakpos) const
|
||||||
if (wsum < 1e-6) return 0;
|
{
|
||||||
return sum / wsum;
|
float peakLevel; // peak level
|
||||||
}
|
int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level
|
||||||
|
float cutLevel; // cutting value
|
||||||
|
float groundLevel; // ground level of the peak
|
||||||
|
int gp1, gp2; // bottom positions of the peak 'hump'
|
||||||
/// get exact center of peak near given position by calculating local mass of center
|
|
||||||
double PeakFinder::getPeakCenter(const float *data, int peakpos) const
|
// find ground positions.
|
||||||
{
|
gp1 = findGround(data, peakpos, -1);
|
||||||
float peakLevel; // peak level
|
gp2 = findGround(data, peakpos, 1);
|
||||||
int crosspos1, crosspos2; // position where the peak 'hump' crosses cutting level
|
|
||||||
float cutLevel; // cutting value
|
peakLevel = data[peakpos];
|
||||||
float groundLevel; // ground level of the peak
|
|
||||||
int gp1, gp2; // bottom positions of the peak 'hump'
|
if (gp1 == gp2)
|
||||||
|
{
|
||||||
// find ground positions.
|
// avoid rounding errors when all are equal
|
||||||
gp1 = findGround(data, peakpos, -1);
|
assert(gp1 == peakpos);
|
||||||
gp2 = findGround(data, peakpos, 1);
|
cutLevel = groundLevel = peakLevel;
|
||||||
|
} else {
|
||||||
groundLevel = 0.5f * (data[gp1] + data[gp2]);
|
// get average of the ground levels
|
||||||
peakLevel = data[peakpos];
|
groundLevel = 0.5f * (data[gp1] + data[gp2]);
|
||||||
|
|
||||||
// calculate 70%-level of the peak
|
// calculate 70%-level of the peak
|
||||||
cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
|
cutLevel = 0.70f * peakLevel + 0.30f * groundLevel;
|
||||||
// find mid-level crossings
|
}
|
||||||
crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);
|
|
||||||
crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);
|
// find mid-level crossings
|
||||||
|
crosspos1 = findCrossingLevel(data, cutLevel, peakpos, -1);
|
||||||
if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak..
|
crosspos2 = findCrossingLevel(data, cutLevel, peakpos, 1);
|
||||||
|
|
||||||
// calculate mass center of the peak surroundings
|
if ((crosspos1 < 0) || (crosspos2 < 0)) return 0; // no crossing, no peak..
|
||||||
return calcMassCenter(data, crosspos1, crosspos2);
|
|
||||||
}
|
// calculate mass center of the peak surroundings
|
||||||
|
return calcMassCenter(data, crosspos1, crosspos2);
|
||||||
|
}
|
||||||
|
|
||||||
double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
|
|
||||||
{
|
double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
|
||||||
|
{
|
||||||
int i;
|
|
||||||
int peakpos; // position of peak level
|
int i;
|
||||||
double highPeak, peak;
|
int peakpos; // position of peak level
|
||||||
|
double highPeak, peak;
|
||||||
this->minPos = aminPos;
|
|
||||||
this->maxPos = amaxPos;
|
this->minPos = aminPos;
|
||||||
|
this->maxPos = amaxPos;
|
||||||
// find absolute peak
|
|
||||||
peakpos = minPos;
|
// find absolute peak
|
||||||
peak = data[minPos];
|
peakpos = minPos;
|
||||||
for (i = minPos + 1; i < maxPos; i ++)
|
peak = data[minPos];
|
||||||
{
|
for (i = minPos + 1; i < maxPos; i ++)
|
||||||
if (data[i] > peak)
|
{
|
||||||
{
|
if (data[i] > peak)
|
||||||
peak = data[i];
|
{
|
||||||
peakpos = i;
|
peak = data[i];
|
||||||
}
|
peakpos = i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Calculate exact location of the highest peak mass center
|
|
||||||
highPeak = getPeakCenter(data, peakpos);
|
// Calculate exact location of the highest peak mass center
|
||||||
peak = highPeak;
|
highPeak = getPeakCenter(data, peakpos);
|
||||||
|
peak = highPeak;
|
||||||
// Now check if the highest peak were in fact harmonic of the true base beat peak
|
|
||||||
// - sometimes the highest peak can be Nth harmonic of the true base peak yet
|
// Now check if the highest peak were in fact harmonic of the true base beat peak
|
||||||
// just a slightly higher than the true base
|
// - sometimes the highest peak can be Nth harmonic of the true base peak yet
|
||||||
|
// just a slightly higher than the true base
|
||||||
int hp = (int)(highPeak + 0.5);
|
|
||||||
|
for (i = 1; i < 3; i ++)
|
||||||
for (i = 3; i < 10; i ++)
|
{
|
||||||
{
|
double peaktmp, harmonic;
|
||||||
double peaktmp, harmonic;
|
int i1,i2;
|
||||||
int i1,i2;
|
|
||||||
|
harmonic = (double)pow(2.0, i);
|
||||||
harmonic = (double)i * 0.5;
|
peakpos = (int)(highPeak / harmonic + 0.5f);
|
||||||
peakpos = (int)(highPeak / harmonic + 0.5f);
|
if (peakpos < minPos) break;
|
||||||
if (peakpos < minPos) break;
|
peakpos = findTop(data, peakpos); // seek true local maximum index
|
||||||
peakpos = findTop(data, peakpos); // seek true local maximum index
|
if (peakpos == 0) continue; // no local max here
|
||||||
if (peakpos == 0) continue; // no local max here
|
|
||||||
|
// calculate mass-center of possible harmonic peak
|
||||||
// calculate mass-center of possible harmonic peak
|
peaktmp = getPeakCenter(data, peakpos);
|
||||||
peaktmp = getPeakCenter(data, peakpos);
|
|
||||||
|
// accept harmonic peak if
|
||||||
// accept harmonic peak if
|
// (a) it is found
|
||||||
// (a) it is found
|
// (b) is within ±4% of the expected harmonic interval
|
||||||
// (b) is within ±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;
|
if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected
|
||||||
if ((diff < 0.96) || (diff > 1.04)) continue; // peak too afar from expected
|
|
||||||
|
// now compare to highest detected peak
|
||||||
// now compare to highest detected peak
|
i1 = (int)(highPeak + 0.5);
|
||||||
i1 = (int)(highPeak + 0.5);
|
i2 = (int)(peaktmp + 0.5);
|
||||||
i2 = (int)(peaktmp + 0.5);
|
if (data[i2] >= 0.4*data[i1])
|
||||||
if (data[i2] >= 0.4*data[i1])
|
{
|
||||||
{
|
// The harmonic is at least half as high primary peak,
|
||||||
// The harmonic is at least half as high primary peak,
|
// thus use the harmonic peak instead
|
||||||
// thus use the harmonic peak instead
|
peak = peaktmp;
|
||||||
peak = peaktmp;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
return peak;
|
||||||
return peak;
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -1,97 +1,90 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// The routine detects highest value on an array of values and calculates the
|
/// The routine detects highest value on an array of values and calculates the
|
||||||
/// precise peak location as a mass-center of the 'hump' around the peak value.
|
/// precise peak location as a mass-center of the 'hump' around the peak value.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef _PeakFinder_H_
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define _PeakFinder_H_
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
namespace soundtouch
|
||||||
//
|
{
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
class PeakFinder
|
||||||
#ifndef _PeakFinder_H_
|
{
|
||||||
#define _PeakFinder_H_
|
protected:
|
||||||
|
/// Min, max allowed peak positions within the data vector
|
||||||
namespace soundtouch
|
int minPos, maxPos;
|
||||||
{
|
|
||||||
|
/// Calculates the mass center between given vector items.
|
||||||
class PeakFinder
|
double calcMassCenter(const float *data, ///< Data vector.
|
||||||
{
|
int firstPos, ///< Index of first vector item belonging to the peak.
|
||||||
protected:
|
int lastPos ///< Index of last vector item belonging to the peak.
|
||||||
/// Min, max allowed peak positions within the data vector
|
) const;
|
||||||
int minPos, maxPos;
|
|
||||||
|
/// Finds the data vector index where the monotoniously decreasing signal crosses the
|
||||||
/// Calculates the mass center between given vector items.
|
/// given level.
|
||||||
double calcMassCenter(const float *data, ///< Data vector.
|
int findCrossingLevel(const float *data, ///< Data vector.
|
||||||
int firstPos, ///< Index of first vector item beloging to the peak.
|
float level, ///< Goal crossing level.
|
||||||
int lastPos ///< Index of last vector item beloging to the peak.
|
int peakpos, ///< Peak position index within the data vector.
|
||||||
) const;
|
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
|
||||||
|
) const;
|
||||||
/// Finds the data vector index where the monotoniously decreasing signal crosses the
|
|
||||||
/// given level.
|
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
|
||||||
int findCrossingLevel(const float *data, ///< Data vector.
|
int findTop(const float *data, int peakpos) const;
|
||||||
float level, ///< Goal crossing level.
|
|
||||||
int peakpos, ///< Peak position index within the data vector.
|
|
||||||
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
|
/// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
|
||||||
) const;
|
/// or left-hand side of the given peak position.
|
||||||
|
int findGround(const float *data, /// Data vector.
|
||||||
// Finds real 'top' of a peak hump from neighnourhood of the given 'peakpos'.
|
int peakpos, /// Peak position index within the data vector.
|
||||||
int findTop(const float *data, int peakpos) const;
|
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
|
||||||
|
) const;
|
||||||
|
|
||||||
/// Finds the 'ground' level, i.e. smallest level between two neighbouring peaks, to right-
|
/// get exact center of peak near given position by calculating local mass of center
|
||||||
/// or left-hand side of the given peak position.
|
double getPeakCenter(const float *data, int peakpos) const;
|
||||||
int findGround(const float *data, /// Data vector.
|
|
||||||
int peakpos, /// Peak position index within the data vector.
|
public:
|
||||||
int direction /// Direction where to proceed from the peak: 1 = right, -1 = left.
|
/// Constructor.
|
||||||
) const;
|
PeakFinder();
|
||||||
|
|
||||||
/// get exact center of peak near given position by calculating local mass of center
|
/// Detect exact peak position of the data vector by finding the largest peak 'hump'
|
||||||
double getPeakCenter(const float *data, int peakpos) const;
|
/// and calculating the mass-center location of the peak hump.
|
||||||
|
///
|
||||||
public:
|
/// \return The location of the largest base harmonic peak hump.
|
||||||
/// Constructor.
|
double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has
|
||||||
PeakFinder();
|
/// to be at least 'maxPos' items long.
|
||||||
|
int minPos, ///< Min allowed peak location within the vector data.
|
||||||
/// Detect exact peak position of the data vector by finding the largest peak 'hump'
|
int maxPos ///< Max allowed peak location within the vector data.
|
||||||
/// and calculating the mass-center location of the peak hump.
|
);
|
||||||
///
|
};
|
||||||
/// \return The location of the largest base harmonic peak hump.
|
|
||||||
double detectPeak(const float *data, /// Data vector to be analyzed. The data vector has
|
}
|
||||||
/// to be at least 'maxPos' items long.
|
|
||||||
int minPos, ///< Min allowed peak location within the vector data.
|
#endif // _PeakFinder_H_
|
||||||
int maxPos ///< Max allowed peak location within the vector data.
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _PeakFinder_H_
|
|
||||||
|
|||||||
@ -1,626 +1,313 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Sample rate transposer. Changes sample rate by using linear interpolation
|
/// Sample rate transposer. Changes sample rate by using linear interpolation
|
||||||
/// together with anti-alias filtering (first order interpolation with anti-
|
/// together with anti-alias filtering (first order interpolation with anti-
|
||||||
/// alias filtering should be quite adequate for this application)
|
/// alias filtering should be quite adequate for this application)
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include <memory.h>
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include <assert.h>
|
||||||
// License along with this library; if not, write to the Free Software
|
#include <stdlib.h>
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <stdio.h>
|
||||||
//
|
#include "RateTransposer.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "InterpolateLinear.h"
|
||||||
|
#include "InterpolateCubic.h"
|
||||||
#include <memory.h>
|
#include "InterpolateShannon.h"
|
||||||
#include <assert.h>
|
#include "AAFilter.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
using namespace soundtouch;
|
||||||
#include "RateTransposer.h"
|
|
||||||
#include "AAFilter.h"
|
// Define default interpolation algorithm here
|
||||||
|
TransposerBase::ALGORITHM TransposerBase::algorithm = TransposerBase::CUBIC;
|
||||||
using namespace soundtouch;
|
|
||||||
|
|
||||||
|
// Constructor
|
||||||
/// A linear samplerate transposer class that uses integer arithmetics.
|
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
|
||||||
/// for the transposing.
|
{
|
||||||
class RateTransposerInteger : public RateTransposer
|
bUseAAFilter =
|
||||||
{
|
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
|
||||||
protected:
|
true;
|
||||||
int iSlopeCount;
|
#else
|
||||||
int iRate;
|
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
|
||||||
SAMPLETYPE sPrevSampleL, sPrevSampleR;
|
false;
|
||||||
|
#endif
|
||||||
virtual void resetRegisters();
|
|
||||||
|
// Instantiates the anti-alias filter
|
||||||
virtual uint transposeStereo(SAMPLETYPE *dest,
|
pAAFilter = new AAFilter(64);
|
||||||
const SAMPLETYPE *src,
|
pTransposer = TransposerBase::newInstance();
|
||||||
uint numSamples);
|
clear();
|
||||||
virtual uint transposeMono(SAMPLETYPE *dest,
|
}
|
||||||
const SAMPLETYPE *src,
|
|
||||||
uint numSamples);
|
|
||||||
|
RateTransposer::~RateTransposer()
|
||||||
public:
|
{
|
||||||
RateTransposerInteger();
|
delete pAAFilter;
|
||||||
virtual ~RateTransposerInteger();
|
delete pTransposer;
|
||||||
|
}
|
||||||
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
|
|
||||||
/// rate, larger faster rates.
|
|
||||||
virtual void setRate(float newRate);
|
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
||||||
|
void RateTransposer::enableAAFilter(bool newMode)
|
||||||
};
|
{
|
||||||
|
#ifndef SOUNDTOUCH_PREVENT_CLICK_AT_RATE_CROSSOVER
|
||||||
|
// Disable Anti-alias filter if desirable to avoid click at rate change zero value crossover
|
||||||
/// A linear samplerate transposer class that uses floating point arithmetics
|
bUseAAFilter = newMode;
|
||||||
/// for the transposing.
|
clear();
|
||||||
class RateTransposerFloat : public RateTransposer
|
#endif
|
||||||
{
|
}
|
||||||
protected:
|
|
||||||
float fSlopeCount;
|
|
||||||
SAMPLETYPE sPrevSampleL, sPrevSampleR;
|
/// Returns nonzero if anti-alias filter is enabled.
|
||||||
|
bool RateTransposer::isAAFilterEnabled() const
|
||||||
virtual void resetRegisters();
|
{
|
||||||
|
return bUseAAFilter;
|
||||||
virtual uint transposeStereo(SAMPLETYPE *dest,
|
}
|
||||||
const SAMPLETYPE *src,
|
|
||||||
uint numSamples);
|
|
||||||
virtual uint transposeMono(SAMPLETYPE *dest,
|
AAFilter *RateTransposer::getAAFilter()
|
||||||
const SAMPLETYPE *src,
|
{
|
||||||
uint numSamples);
|
return pAAFilter;
|
||||||
|
}
|
||||||
public:
|
|
||||||
RateTransposerFloat();
|
|
||||||
virtual ~RateTransposerFloat();
|
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
||||||
};
|
// iRate, larger faster iRates.
|
||||||
|
void RateTransposer::setRate(double newRate)
|
||||||
|
{
|
||||||
|
double fCutoff;
|
||||||
|
|
||||||
// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
pTransposer->setRate(newRate);
|
||||||
// depending on if we've a MMX/SSE/etc-capable CPU available or not.
|
|
||||||
void * RateTransposer::operator new(size_t s)
|
// design a new anti-alias filter
|
||||||
{
|
if (newRate > 1.0)
|
||||||
ST_THROW_RT_ERROR("Error in RateTransoser::new: don't use \"new TDStretch\" directly, use \"newInstance\" to create a new instance instead!");
|
{
|
||||||
return newInstance();
|
fCutoff = 0.5 / newRate;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
RateTransposer *RateTransposer::newInstance()
|
fCutoff = 0.5 * newRate;
|
||||||
{
|
}
|
||||||
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
pAAFilter->setCutoffFreq(fCutoff);
|
||||||
return ::new RateTransposerInteger;
|
}
|
||||||
#else
|
|
||||||
return ::new RateTransposerFloat;
|
|
||||||
#endif
|
// Adds 'nSamples' pcs of samples from the 'samples' memory position into
|
||||||
}
|
// the input of the object.
|
||||||
|
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
||||||
|
{
|
||||||
// Constructor
|
processSamples(samples, nSamples);
|
||||||
RateTransposer::RateTransposer() : FIFOProcessor(&outputBuffer)
|
}
|
||||||
{
|
|
||||||
numChannels = 2;
|
|
||||||
bUseAAFilter = TRUE;
|
// Transposes sample rate by applying anti-alias filter to prevent folding.
|
||||||
fRate = 0;
|
// Returns amount of samples returned in the "dest" buffer.
|
||||||
|
// The maximum amount of samples that can be returned at a time is set by
|
||||||
// Instantiates the anti-alias filter with default tap length
|
// the 'set_returnBuffer_size' function.
|
||||||
// of 32
|
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
|
||||||
pAAFilter = new AAFilter(32);
|
{
|
||||||
}
|
if (nSamples == 0) return;
|
||||||
|
|
||||||
|
// Store samples to input buffer
|
||||||
|
inputBuffer.putSamples(src, nSamples);
|
||||||
RateTransposer::~RateTransposer()
|
|
||||||
{
|
// If anti-alias filter is turned off, simply transpose without applying
|
||||||
delete pAAFilter;
|
// the filter
|
||||||
}
|
if (bUseAAFilter == false)
|
||||||
|
{
|
||||||
|
(void)pTransposer->transpose(outputBuffer, inputBuffer);
|
||||||
|
return;
|
||||||
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
}
|
||||||
void RateTransposer::enableAAFilter(BOOL newMode)
|
|
||||||
{
|
assert(pAAFilter);
|
||||||
bUseAAFilter = newMode;
|
|
||||||
}
|
// Transpose with anti-alias filter
|
||||||
|
if (pTransposer->rate < 1.0f)
|
||||||
|
{
|
||||||
/// Returns nonzero if anti-alias filter is enabled.
|
// If the parameter 'Rate' value is smaller than 1, first transpose
|
||||||
BOOL RateTransposer::isAAFilterEnabled() const
|
// the samples and then apply the anti-alias filter to remove aliasing.
|
||||||
{
|
|
||||||
return bUseAAFilter;
|
// Transpose the samples, store the result to end of "midBuffer"
|
||||||
}
|
pTransposer->transpose(midBuffer, inputBuffer);
|
||||||
|
|
||||||
|
// Apply the anti-alias filter for transposed samples in midBuffer
|
||||||
AAFilter *RateTransposer::getAAFilter()
|
pAAFilter->evaluate(outputBuffer, midBuffer);
|
||||||
{
|
}
|
||||||
return pAAFilter;
|
else
|
||||||
}
|
{
|
||||||
|
// If the parameter 'Rate' value is larger than 1, first apply the
|
||||||
|
// anti-alias filter to remove high frequencies (prevent them from folding
|
||||||
|
// over the lover frequencies), then transpose.
|
||||||
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
|
||||||
// iRate, larger faster iRates.
|
// Apply the anti-alias filter for samples in inputBuffer
|
||||||
void RateTransposer::setRate(float newRate)
|
pAAFilter->evaluate(midBuffer, inputBuffer);
|
||||||
{
|
|
||||||
double fCutoff;
|
// Transpose the AA-filtered samples in "midBuffer"
|
||||||
|
pTransposer->transpose(outputBuffer, midBuffer);
|
||||||
fRate = newRate;
|
}
|
||||||
|
}
|
||||||
// design a new anti-alias filter
|
|
||||||
if (newRate > 1.0f)
|
|
||||||
{
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
fCutoff = 0.5f / newRate;
|
void RateTransposer::setChannels(int nChannels)
|
||||||
}
|
{
|
||||||
else
|
if (!verifyNumberOfChannels(nChannels) ||
|
||||||
{
|
(pTransposer->numChannels == nChannels)) return;
|
||||||
fCutoff = 0.5f * newRate;
|
|
||||||
}
|
pTransposer->setChannels(nChannels);
|
||||||
pAAFilter->setCutoffFreq(fCutoff);
|
inputBuffer.setChannels(nChannels);
|
||||||
}
|
midBuffer.setChannels(nChannels);
|
||||||
|
outputBuffer.setChannels(nChannels);
|
||||||
|
}
|
||||||
// Outputs as many samples of the 'outputBuffer' as possible, and if there's
|
|
||||||
// any room left, outputs also as many of the incoming samples as possible.
|
|
||||||
// The goal is to drive the outputBuffer empty.
|
// Clears all the samples in the object
|
||||||
//
|
void RateTransposer::clear()
|
||||||
// It's allowed for 'output' and 'input' parameters to point to the same
|
{
|
||||||
// memory position.
|
outputBuffer.clear();
|
||||||
/*
|
midBuffer.clear();
|
||||||
void RateTransposer::flushStoreBuffer()
|
inputBuffer.clear();
|
||||||
{
|
pTransposer->resetRegisters();
|
||||||
if (storeBuffer.isEmpty()) return;
|
|
||||||
|
// prefill buffer to avoid losing first samples at beginning of stream
|
||||||
outputBuffer.moveSamples(storeBuffer);
|
int prefill = getLatency();
|
||||||
}
|
inputBuffer.addSilent(prefill);
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
|
||||||
// Adds 'nSamples' pcs of samples from the 'samples' memory position into
|
// Returns nonzero if there aren't any samples available for outputting.
|
||||||
// the input of the object.
|
int RateTransposer::isEmpty() const
|
||||||
void RateTransposer::putSamples(const SAMPLETYPE *samples, uint nSamples)
|
{
|
||||||
{
|
int res;
|
||||||
processSamples(samples, nSamples);
|
|
||||||
}
|
res = FIFOProcessor::isEmpty();
|
||||||
|
if (res == 0) return 0;
|
||||||
|
return inputBuffer.isEmpty();
|
||||||
|
}
|
||||||
// Transposes up the sample rate, causing the observed playback 'rate' of the
|
|
||||||
// sound to decrease
|
|
||||||
void RateTransposer::upsample(const SAMPLETYPE *src, uint nSamples)
|
/// Return approximate initial input-output latency
|
||||||
{
|
int RateTransposer::getLatency() const
|
||||||
uint count, sizeTemp, num;
|
{
|
||||||
|
return pTransposer->getLatency() +
|
||||||
// If the parameter 'uRate' value is smaller than 'SCALE', first transpose
|
((bUseAAFilter) ? (pAAFilter->getLength() / 2) : 0);
|
||||||
// the samples and then apply the anti-alias filter to remove aliasing.
|
}
|
||||||
|
|
||||||
// First check that there's enough room in 'storeBuffer'
|
|
||||||
// (+16 is to reserve some slack in the destination buffer)
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
|
//
|
||||||
|
// TransposerBase - Base class for interpolation
|
||||||
// Transpose the samples, store the result into the end of "storeBuffer"
|
//
|
||||||
count = transpose(storeBuffer.ptrEnd(sizeTemp), src, nSamples);
|
|
||||||
storeBuffer.putSamples(count);
|
// static function to set interpolation algorithm
|
||||||
|
void TransposerBase::setAlgorithm(TransposerBase::ALGORITHM a)
|
||||||
// Apply the anti-alias filter to samples in "store output", output the
|
{
|
||||||
// result to "dest"
|
TransposerBase::algorithm = a;
|
||||||
num = storeBuffer.numSamples();
|
}
|
||||||
count = pAAFilter->evaluate(outputBuffer.ptrEnd(num),
|
|
||||||
storeBuffer.ptrBegin(), num, (uint)numChannels);
|
|
||||||
outputBuffer.putSamples(count);
|
// Transposes the sample rate of the given samples using linear interpolation.
|
||||||
|
// Returns the number of samples returned in the "dest" buffer
|
||||||
// Remove the processed samples from "storeBuffer"
|
int TransposerBase::transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src)
|
||||||
storeBuffer.receiveSamples(count);
|
{
|
||||||
}
|
int numSrcSamples = src.numSamples();
|
||||||
|
int sizeDemand = (int)((double)numSrcSamples / rate) + 8;
|
||||||
|
int numOutput;
|
||||||
// Transposes down the sample rate, causing the observed playback 'rate' of the
|
SAMPLETYPE *psrc = src.ptrBegin();
|
||||||
// sound to increase
|
SAMPLETYPE *pdest = dest.ptrEnd(sizeDemand);
|
||||||
void RateTransposer::downsample(const SAMPLETYPE *src, uint nSamples)
|
|
||||||
{
|
#ifndef USE_MULTICH_ALWAYS
|
||||||
uint count, sizeTemp;
|
if (numChannels == 1)
|
||||||
|
{
|
||||||
// If the parameter 'uRate' value is larger than 'SCALE', first apply the
|
numOutput = transposeMono(pdest, psrc, numSrcSamples);
|
||||||
// anti-alias filter to remove high frequencies (prevent them from folding
|
}
|
||||||
// over the lover frequencies), then transpose.
|
else if (numChannels == 2)
|
||||||
|
{
|
||||||
// Add the new samples to the end of the storeBuffer
|
numOutput = transposeStereo(pdest, psrc, numSrcSamples);
|
||||||
storeBuffer.putSamples(src, nSamples);
|
}
|
||||||
|
else
|
||||||
// Anti-alias filter the samples to prevent folding and output the filtered
|
#endif // USE_MULTICH_ALWAYS
|
||||||
// data to tempBuffer. Note : because of the FIR filter length, the
|
{
|
||||||
// filtering routine takes in 'filter_length' more samples than it outputs.
|
assert(numChannels > 0);
|
||||||
assert(tempBuffer.isEmpty());
|
numOutput = transposeMulti(pdest, psrc, numSrcSamples);
|
||||||
sizeTemp = storeBuffer.numSamples();
|
}
|
||||||
|
dest.putSamples(numOutput);
|
||||||
count = pAAFilter->evaluate(tempBuffer.ptrEnd(sizeTemp),
|
src.receiveSamples(numSrcSamples);
|
||||||
storeBuffer.ptrBegin(), sizeTemp, (uint)numChannels);
|
return numOutput;
|
||||||
|
}
|
||||||
if (count == 0) return;
|
|
||||||
|
|
||||||
// Remove the filtered samples from 'storeBuffer'
|
TransposerBase::TransposerBase()
|
||||||
storeBuffer.receiveSamples(count);
|
{
|
||||||
|
numChannels = 0;
|
||||||
// Transpose the samples (+16 is to reserve some slack in the destination buffer)
|
rate = 1.0f;
|
||||||
sizeTemp = (uint)((float)nSamples / fRate + 16.0f);
|
}
|
||||||
count = transpose(outputBuffer.ptrEnd(sizeTemp), tempBuffer.ptrBegin(), count);
|
|
||||||
outputBuffer.putSamples(count);
|
|
||||||
}
|
TransposerBase::~TransposerBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
// Transposes sample rate by applying anti-alias filter to prevent folding.
|
|
||||||
// Returns amount of samples returned in the "dest" buffer.
|
|
||||||
// The maximum amount of samples that can be returned at a time is set by
|
void TransposerBase::setChannels(int channels)
|
||||||
// the 'set_returnBuffer_size' function.
|
{
|
||||||
void RateTransposer::processSamples(const SAMPLETYPE *src, uint nSamples)
|
numChannels = channels;
|
||||||
{
|
resetRegisters();
|
||||||
uint count;
|
}
|
||||||
uint sizeReq;
|
|
||||||
|
|
||||||
if (nSamples == 0) return;
|
void TransposerBase::setRate(double newRate)
|
||||||
assert(pAAFilter);
|
{
|
||||||
|
rate = newRate;
|
||||||
// If anti-alias filter is turned off, simply transpose without applying
|
}
|
||||||
// the filter
|
|
||||||
if (bUseAAFilter == FALSE)
|
|
||||||
{
|
// static factory function
|
||||||
sizeReq = (uint)((float)nSamples / fRate + 1.0f);
|
TransposerBase *TransposerBase::newInstance()
|
||||||
count = transpose(outputBuffer.ptrEnd(sizeReq), src, nSamples);
|
{
|
||||||
outputBuffer.putSamples(count);
|
#ifdef SOUNDTOUCH_INTEGER_SAMPLES
|
||||||
return;
|
// Notice: For integer arithmetic support only linear algorithm (due to simplest calculus)
|
||||||
}
|
return ::new InterpolateLinearInteger;
|
||||||
|
#else
|
||||||
// Transpose with anti-alias filter
|
switch (algorithm)
|
||||||
if (fRate < 1.0f)
|
{
|
||||||
{
|
case LINEAR:
|
||||||
upsample(src, nSamples);
|
return new InterpolateLinearFloat;
|
||||||
}
|
|
||||||
else
|
case CUBIC:
|
||||||
{
|
return new InterpolateCubic;
|
||||||
downsample(src, nSamples);
|
|
||||||
}
|
case SHANNON:
|
||||||
}
|
return new InterpolateShannon;
|
||||||
|
|
||||||
|
default:
|
||||||
// Transposes the sample rate of the given samples using linear interpolation.
|
assert(false);
|
||||||
// Returns the number of samples returned in the "dest" buffer
|
return nullptr;
|
||||||
inline uint RateTransposer::transpose(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
}
|
||||||
{
|
#endif
|
||||||
if (numChannels == 2)
|
}
|
||||||
{
|
|
||||||
return transposeStereo(dest, src, nSamples);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return transposeMono(dest, src, nSamples);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Sets the number of channels, 1 = mono, 2 = stereo
|
|
||||||
void RateTransposer::setChannels(int nChannels)
|
|
||||||
{
|
|
||||||
assert(nChannels > 0);
|
|
||||||
if (numChannels == nChannels) return;
|
|
||||||
|
|
||||||
assert(nChannels == 1 || nChannels == 2);
|
|
||||||
numChannels = nChannels;
|
|
||||||
|
|
||||||
storeBuffer.setChannels(numChannels);
|
|
||||||
tempBuffer.setChannels(numChannels);
|
|
||||||
outputBuffer.setChannels(numChannels);
|
|
||||||
|
|
||||||
// Inits the linear interpolation registers
|
|
||||||
resetRegisters();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Clears all the samples in the object
|
|
||||||
void RateTransposer::clear()
|
|
||||||
{
|
|
||||||
outputBuffer.clear();
|
|
||||||
storeBuffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns nonzero if there aren't any samples available for outputting.
|
|
||||||
int RateTransposer::isEmpty() const
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
|
|
||||||
res = FIFOProcessor::isEmpty();
|
|
||||||
if (res == 0) return 0;
|
|
||||||
return storeBuffer.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// RateTransposerInteger - integer arithmetic implementation
|
|
||||||
//
|
|
||||||
|
|
||||||
/// fixed-point interpolation routine precision
|
|
||||||
#define SCALE 65536
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
RateTransposerInteger::RateTransposerInteger() : RateTransposer()
|
|
||||||
{
|
|
||||||
// Notice: use local function calling syntax for sake of clarity,
|
|
||||||
// to indicate the fact that C++ constructor can't call virtual functions.
|
|
||||||
RateTransposerInteger::resetRegisters();
|
|
||||||
RateTransposerInteger::setRate(1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RateTransposerInteger::~RateTransposerInteger()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RateTransposerInteger::resetRegisters()
|
|
||||||
{
|
|
||||||
iSlopeCount = 0;
|
|
||||||
sPrevSampleL =
|
|
||||||
sPrevSampleR = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Transposes the sample rate of the given samples using linear interpolation.
|
|
||||||
// 'Mono' version of the routine. Returns the number of samples returned in
|
|
||||||
// the "dest" buffer
|
|
||||||
uint RateTransposerInteger::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
|
||||||
{
|
|
||||||
unsigned int i, used;
|
|
||||||
LONG_SAMPLETYPE temp, vol1;
|
|
||||||
|
|
||||||
if (nSamples == 0) return 0; // no samples, no work
|
|
||||||
|
|
||||||
used = 0;
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
// Process the last sample saved from the previous call first...
|
|
||||||
while (iSlopeCount <= SCALE)
|
|
||||||
{
|
|
||||||
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
|
||||||
temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
|
|
||||||
dest[i] = (SAMPLETYPE)(temp / SCALE);
|
|
||||||
i++;
|
|
||||||
iSlopeCount += iRate;
|
|
||||||
}
|
|
||||||
// now always (iSlopeCount > SCALE)
|
|
||||||
iSlopeCount -= SCALE;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
while (iSlopeCount > SCALE)
|
|
||||||
{
|
|
||||||
iSlopeCount -= SCALE;
|
|
||||||
used ++;
|
|
||||||
if (used >= nSamples - 1) goto end;
|
|
||||||
}
|
|
||||||
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
|
||||||
temp = src[used] * vol1 + iSlopeCount * src[used + 1];
|
|
||||||
dest[i] = (SAMPLETYPE)(temp / SCALE);
|
|
||||||
|
|
||||||
i++;
|
|
||||||
iSlopeCount += iRate;
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
// Store the last sample for the next round
|
|
||||||
sPrevSampleL = src[nSamples - 1];
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Transposes the sample rate of the given samples using linear interpolation.
|
|
||||||
// 'Stereo' version of the routine. Returns the number of samples returned in
|
|
||||||
// the "dest" buffer
|
|
||||||
uint RateTransposerInteger::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
|
||||||
{
|
|
||||||
unsigned int srcPos, i, used;
|
|
||||||
LONG_SAMPLETYPE temp, vol1;
|
|
||||||
|
|
||||||
if (nSamples == 0) return 0; // no samples, no work
|
|
||||||
|
|
||||||
used = 0;
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
// Process the last sample saved from the sPrevSampleLious call first...
|
|
||||||
while (iSlopeCount <= SCALE)
|
|
||||||
{
|
|
||||||
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
|
||||||
temp = vol1 * sPrevSampleL + iSlopeCount * src[0];
|
|
||||||
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
|
|
||||||
temp = vol1 * sPrevSampleR + iSlopeCount * src[1];
|
|
||||||
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
|
|
||||||
i++;
|
|
||||||
iSlopeCount += iRate;
|
|
||||||
}
|
|
||||||
// now always (iSlopeCount > SCALE)
|
|
||||||
iSlopeCount -= SCALE;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
while (iSlopeCount > SCALE)
|
|
||||||
{
|
|
||||||
iSlopeCount -= SCALE;
|
|
||||||
used ++;
|
|
||||||
if (used >= nSamples - 1) goto end;
|
|
||||||
}
|
|
||||||
srcPos = 2 * used;
|
|
||||||
vol1 = (LONG_SAMPLETYPE)(SCALE - iSlopeCount);
|
|
||||||
temp = src[srcPos] * vol1 + iSlopeCount * src[srcPos + 2];
|
|
||||||
dest[2 * i] = (SAMPLETYPE)(temp / SCALE);
|
|
||||||
temp = src[srcPos + 1] * vol1 + iSlopeCount * src[srcPos + 3];
|
|
||||||
dest[2 * i + 1] = (SAMPLETYPE)(temp / SCALE);
|
|
||||||
|
|
||||||
i++;
|
|
||||||
iSlopeCount += iRate;
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
// Store the last sample for the next round
|
|
||||||
sPrevSampleL = src[2 * nSamples - 2];
|
|
||||||
sPrevSampleR = src[2 * nSamples - 1];
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Sets new target iRate. Normal iRate = 1.0, smaller values represent slower
|
|
||||||
// iRate, larger faster iRates.
|
|
||||||
void RateTransposerInteger::setRate(float newRate)
|
|
||||||
{
|
|
||||||
iRate = (int)(newRate * SCALE + 0.5f);
|
|
||||||
RateTransposer::setRate(newRate);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// RateTransposerFloat - floating point arithmetic implementation
|
|
||||||
//
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Constructor
|
|
||||||
RateTransposerFloat::RateTransposerFloat() : RateTransposer()
|
|
||||||
{
|
|
||||||
// Notice: use local function calling syntax for sake of clarity,
|
|
||||||
// to indicate the fact that C++ constructor can't call virtual functions.
|
|
||||||
RateTransposerFloat::resetRegisters();
|
|
||||||
RateTransposerFloat::setRate(1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RateTransposerFloat::~RateTransposerFloat()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RateTransposerFloat::resetRegisters()
|
|
||||||
{
|
|
||||||
fSlopeCount = 0;
|
|
||||||
sPrevSampleL =
|
|
||||||
sPrevSampleR = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Transposes the sample rate of the given samples using linear interpolation.
|
|
||||||
// 'Mono' version of the routine. Returns the number of samples returned in
|
|
||||||
// the "dest" buffer
|
|
||||||
uint RateTransposerFloat::transposeMono(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
|
||||||
{
|
|
||||||
unsigned int i, used;
|
|
||||||
|
|
||||||
used = 0;
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
// Process the last sample saved from the previous call first...
|
|
||||||
while (fSlopeCount <= 1.0f)
|
|
||||||
{
|
|
||||||
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
|
|
||||||
i++;
|
|
||||||
fSlopeCount += fRate;
|
|
||||||
}
|
|
||||||
fSlopeCount -= 1.0f;
|
|
||||||
|
|
||||||
if (nSamples > 1)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
while (fSlopeCount > 1.0f)
|
|
||||||
{
|
|
||||||
fSlopeCount -= 1.0f;
|
|
||||||
used ++;
|
|
||||||
if (used >= nSamples - 1) goto end;
|
|
||||||
}
|
|
||||||
dest[i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[used] + fSlopeCount * src[used + 1]);
|
|
||||||
i++;
|
|
||||||
fSlopeCount += fRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
// Store the last sample for the next round
|
|
||||||
sPrevSampleL = src[nSamples - 1];
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Transposes the sample rate of the given samples using linear interpolation.
|
|
||||||
// 'Mono' version of the routine. Returns the number of samples returned in
|
|
||||||
// the "dest" buffer
|
|
||||||
uint RateTransposerFloat::transposeStereo(SAMPLETYPE *dest, const SAMPLETYPE *src, uint nSamples)
|
|
||||||
{
|
|
||||||
unsigned int srcPos, i, used;
|
|
||||||
|
|
||||||
if (nSamples == 0) return 0; // no samples, no work
|
|
||||||
|
|
||||||
used = 0;
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
// Process the last sample saved from the sPrevSampleLious call first...
|
|
||||||
while (fSlopeCount <= 1.0f)
|
|
||||||
{
|
|
||||||
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleL + fSlopeCount * src[0]);
|
|
||||||
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * sPrevSampleR + fSlopeCount * src[1]);
|
|
||||||
i++;
|
|
||||||
fSlopeCount += fRate;
|
|
||||||
}
|
|
||||||
// now always (iSlopeCount > 1.0f)
|
|
||||||
fSlopeCount -= 1.0f;
|
|
||||||
|
|
||||||
if (nSamples > 1)
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
while (fSlopeCount > 1.0f)
|
|
||||||
{
|
|
||||||
fSlopeCount -= 1.0f;
|
|
||||||
used ++;
|
|
||||||
if (used >= nSamples - 1) goto end;
|
|
||||||
}
|
|
||||||
srcPos = 2 * used;
|
|
||||||
|
|
||||||
dest[2 * i] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos]
|
|
||||||
+ fSlopeCount * src[srcPos + 2]);
|
|
||||||
dest[2 * i + 1] = (SAMPLETYPE)((1.0f - fSlopeCount) * src[srcPos + 1]
|
|
||||||
+ fSlopeCount * src[srcPos + 3]);
|
|
||||||
|
|
||||||
i++;
|
|
||||||
fSlopeCount += fRate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end:
|
|
||||||
// Store the last sample for the next round
|
|
||||||
sPrevSampleL = src[2 * nSamples - 2];
|
|
||||||
sPrevSampleR = src[2 * nSamples - 1];
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,159 +1,164 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Sample rate transposer. Changes sample rate by using linear interpolation
|
/// Sample rate transposer. Changes sample rate by using linear interpolation
|
||||||
/// together with anti-alias filtering (first order interpolation with anti-
|
/// together with anti-alias filtering (first order interpolation with anti-
|
||||||
/// alias filtering should be quite adequate for this application).
|
/// alias filtering should be quite adequate for this application).
|
||||||
///
|
///
|
||||||
/// Use either of the derived classes of 'RateTransposerInteger' or
|
/// Use either of the derived classes of 'RateTransposerInteger' or
|
||||||
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
|
/// 'RateTransposerFloat' for corresponding integer/floating point tranposing
|
||||||
/// algorithm implementation.
|
/// algorithm implementation.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef RateTransposer_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define RateTransposer_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <stddef.h>
|
||||||
//
|
#include "AAFilter.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "FIFOSamplePipe.h"
|
||||||
|
#include "FIFOSampleBuffer.h"
|
||||||
#ifndef RateTransposer_H
|
|
||||||
#define RateTransposer_H
|
#include "STTypes.h"
|
||||||
|
|
||||||
#include <stddef.h>
|
namespace soundtouch
|
||||||
#include "AAFilter.h"
|
{
|
||||||
#include "FIFOSamplePipe.h"
|
|
||||||
#include "FIFOSampleBuffer.h"
|
/// Abstract base class for transposer implementations (linear, advanced vs integer, float etc)
|
||||||
|
class TransposerBase
|
||||||
#include "STTypes.h"
|
{
|
||||||
|
public:
|
||||||
namespace soundtouch
|
enum ALGORITHM {
|
||||||
{
|
LINEAR = 0,
|
||||||
|
CUBIC,
|
||||||
/// A common linear samplerate transposer class.
|
SHANNON
|
||||||
///
|
};
|
||||||
/// Note: Use function "RateTransposer::newInstance()" to create a new class
|
|
||||||
/// instance instead of the "new" operator; that function automatically
|
protected:
|
||||||
/// chooses a correct implementation depending on if integer or floating
|
virtual int transposeMono(SAMPLETYPE *dest,
|
||||||
/// arithmetics are to be used.
|
const SAMPLETYPE *src,
|
||||||
class RateTransposer : public FIFOProcessor
|
int &srcSamples) = 0;
|
||||||
{
|
virtual int transposeStereo(SAMPLETYPE *dest,
|
||||||
protected:
|
const SAMPLETYPE *src,
|
||||||
/// Anti-alias filter object
|
int &srcSamples) = 0;
|
||||||
AAFilter *pAAFilter;
|
virtual int transposeMulti(SAMPLETYPE *dest,
|
||||||
|
const SAMPLETYPE *src,
|
||||||
float fRate;
|
int &srcSamples) = 0;
|
||||||
|
|
||||||
int numChannels;
|
static ALGORITHM algorithm;
|
||||||
|
|
||||||
/// Buffer for collecting samples to feed the anti-alias filter between
|
public:
|
||||||
/// two batches
|
double rate;
|
||||||
FIFOSampleBuffer storeBuffer;
|
int numChannels;
|
||||||
|
|
||||||
/// Buffer for keeping samples between transposing & anti-alias filter
|
TransposerBase();
|
||||||
FIFOSampleBuffer tempBuffer;
|
virtual ~TransposerBase();
|
||||||
|
|
||||||
/// Output sample buffer
|
virtual int transpose(FIFOSampleBuffer &dest, FIFOSampleBuffer &src);
|
||||||
FIFOSampleBuffer outputBuffer;
|
virtual void setRate(double newRate);
|
||||||
|
virtual void setChannels(int channels);
|
||||||
BOOL bUseAAFilter;
|
virtual int getLatency() const = 0;
|
||||||
|
|
||||||
virtual void resetRegisters() = 0;
|
virtual void resetRegisters() = 0;
|
||||||
|
|
||||||
virtual uint transposeStereo(SAMPLETYPE *dest,
|
// static factory function
|
||||||
const SAMPLETYPE *src,
|
static TransposerBase *newInstance();
|
||||||
uint numSamples) = 0;
|
|
||||||
virtual uint transposeMono(SAMPLETYPE *dest,
|
// static function to set interpolation algorithm
|
||||||
const SAMPLETYPE *src,
|
static void setAlgorithm(ALGORITHM a);
|
||||||
uint numSamples) = 0;
|
};
|
||||||
inline uint transpose(SAMPLETYPE *dest,
|
|
||||||
const SAMPLETYPE *src,
|
|
||||||
uint numSamples);
|
/// A common linear samplerate transposer class.
|
||||||
|
///
|
||||||
void downsample(const SAMPLETYPE *src,
|
class RateTransposer : public FIFOProcessor
|
||||||
uint numSamples);
|
{
|
||||||
void upsample(const SAMPLETYPE *src,
|
protected:
|
||||||
uint numSamples);
|
/// Anti-alias filter object
|
||||||
|
AAFilter *pAAFilter;
|
||||||
/// Transposes sample rate by applying anti-alias filter to prevent folding.
|
TransposerBase *pTransposer;
|
||||||
/// Returns amount of samples returned in the "dest" buffer.
|
|
||||||
/// The maximum amount of samples that can be returned at a time is set by
|
/// Buffer for collecting samples to feed the anti-alias filter between
|
||||||
/// the 'set_returnBuffer_size' function.
|
/// two batches
|
||||||
void processSamples(const SAMPLETYPE *src,
|
FIFOSampleBuffer inputBuffer;
|
||||||
uint numSamples);
|
|
||||||
|
/// Buffer for keeping samples between transposing & anti-alias filter
|
||||||
|
FIFOSampleBuffer midBuffer;
|
||||||
public:
|
|
||||||
RateTransposer();
|
/// Output sample buffer
|
||||||
virtual ~RateTransposer();
|
FIFOSampleBuffer outputBuffer;
|
||||||
|
|
||||||
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
bool bUseAAFilter;
|
||||||
/// depending on if we're to use integer or floating point arithmetics.
|
|
||||||
static void *operator new(size_t s);
|
|
||||||
|
/// Transposes sample rate by applying anti-alias filter to prevent folding.
|
||||||
/// Use this function instead of "new" operator to create a new instance of this class.
|
/// Returns amount of samples returned in the "dest" buffer.
|
||||||
/// This function automatically chooses a correct implementation, depending on if
|
/// The maximum amount of samples that can be returned at a time is set by
|
||||||
/// integer ot floating point arithmetics are to be used.
|
/// the 'set_returnBuffer_size' function.
|
||||||
static RateTransposer *newInstance();
|
void processSamples(const SAMPLETYPE *src,
|
||||||
|
uint numSamples);
|
||||||
/// Returns the output buffer object
|
|
||||||
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
public:
|
||||||
|
RateTransposer();
|
||||||
/// Returns the store buffer object
|
virtual ~RateTransposer() override;
|
||||||
FIFOSamplePipe *getStore() { return &storeBuffer; };
|
|
||||||
|
/// Returns the output buffer object
|
||||||
/// Return anti-alias filter object
|
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
||||||
AAFilter *getAAFilter();
|
|
||||||
|
/// Return anti-alias filter object
|
||||||
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
AAFilter *getAAFilter();
|
||||||
void enableAAFilter(BOOL newMode);
|
|
||||||
|
/// Enables/disables the anti-alias filter. Zero to disable, nonzero to enable
|
||||||
/// Returns nonzero if anti-alias filter is enabled.
|
void enableAAFilter(bool newMode);
|
||||||
BOOL isAAFilterEnabled() const;
|
|
||||||
|
/// Returns nonzero if anti-alias filter is enabled.
|
||||||
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
|
bool isAAFilterEnabled() const;
|
||||||
/// rate, larger faster rates.
|
|
||||||
virtual void setRate(float newRate);
|
/// Sets new target rate. Normal rate = 1.0, smaller values represent slower
|
||||||
|
/// rate, larger faster rates.
|
||||||
/// Sets the number of channels, 1 = mono, 2 = stereo
|
virtual void setRate(double newRate);
|
||||||
void setChannels(int channels);
|
|
||||||
|
/// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
void setChannels(int channels);
|
||||||
/// the input of the object.
|
|
||||||
void putSamples(const SAMPLETYPE *samples, uint numSamples);
|
/// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
||||||
|
/// the input of the object.
|
||||||
/// Clears all the samples in the object
|
void putSamples(const SAMPLETYPE *samples, uint numSamples) override;
|
||||||
void clear();
|
|
||||||
|
/// Clears all the samples in the object
|
||||||
/// Returns nonzero if there aren't any samples available for outputting.
|
void clear() override;
|
||||||
int isEmpty() const;
|
|
||||||
};
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
int isEmpty() const override;
|
||||||
}
|
|
||||||
|
/// Return approximate initial input-output latency
|
||||||
#endif
|
int getLatency() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,188 +0,0 @@
|
|||||||
# Microsoft Developer Studio Project File - Name="SoundTouch" - Package Owner=<4>
|
|
||||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
|
||||||
# ** DO NOT EDIT **
|
|
||||||
|
|
||||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
|
||||||
|
|
||||||
CFG=SoundTouch - Win32 Debug
|
|
||||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
|
||||||
!MESSAGE use the Export Makefile command and run
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "SoundTouch.mak".
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE You can specify a configuration when running NMAKE
|
|
||||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE NMAKE /f "SoundTouch.mak" CFG="SoundTouch - Win32 Debug"
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE Possible choices for configuration are:
|
|
||||||
!MESSAGE
|
|
||||||
!MESSAGE "SoundTouch - Win32 Release" (based on "Win32 (x86) Static Library")
|
|
||||||
!MESSAGE "SoundTouch - Win32 Debug" (based on "Win32 (x86) Static Library")
|
|
||||||
!MESSAGE
|
|
||||||
|
|
||||||
# Begin Project
|
|
||||||
# PROP AllowPerConfigDependencies 0
|
|
||||||
# PROP Scc_ProjName ""
|
|
||||||
# PROP Scc_LocalPath ""
|
|
||||||
CPP=cl.exe
|
|
||||||
RSC=rc.exe
|
|
||||||
|
|
||||||
!IF "$(CFG)" == "SoundTouch - Win32 Release"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 0
|
|
||||||
# PROP BASE Output_Dir "Release"
|
|
||||||
# PROP BASE Intermediate_Dir "Release"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 0
|
|
||||||
# PROP Output_Dir "Release"
|
|
||||||
# PROP Intermediate_Dir "Release"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
|
||||||
# ADD CPP /nologo /W3 /GX /Zi /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
|
||||||
# ADD BASE RSC /l 0x40b /d "NDEBUG"
|
|
||||||
# ADD RSC /l 0x40b /d "NDEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LIB32=link.exe -lib
|
|
||||||
# ADD BASE LIB32 /nologo
|
|
||||||
# ADD LIB32 /nologo
|
|
||||||
# Begin Special Build Tool
|
|
||||||
SOURCE="$(InputPath)"
|
|
||||||
PostBuild_Cmds=copy .\Release\SoundTouch.lib ..\..\lib\
|
|
||||||
# End Special Build Tool
|
|
||||||
|
|
||||||
!ELSEIF "$(CFG)" == "SoundTouch - Win32 Debug"
|
|
||||||
|
|
||||||
# PROP BASE Use_MFC 0
|
|
||||||
# PROP BASE Use_Debug_Libraries 1
|
|
||||||
# PROP BASE Output_Dir "Debug"
|
|
||||||
# PROP BASE Intermediate_Dir "Debug"
|
|
||||||
# PROP BASE Target_Dir ""
|
|
||||||
# PROP Use_MFC 0
|
|
||||||
# PROP Use_Debug_Libraries 1
|
|
||||||
# PROP Output_Dir "Debug"
|
|
||||||
# PROP Intermediate_Dir "Debug"
|
|
||||||
# PROP Target_Dir ""
|
|
||||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
|
||||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c
|
|
||||||
# ADD BASE RSC /l 0x40b /d "_DEBUG"
|
|
||||||
# ADD RSC /l 0x40b /d "_DEBUG"
|
|
||||||
BSC32=bscmake.exe
|
|
||||||
# ADD BASE BSC32 /nologo
|
|
||||||
# ADD BSC32 /nologo
|
|
||||||
LIB32=link.exe -lib
|
|
||||||
# ADD BASE LIB32 /nologo
|
|
||||||
# ADD LIB32 /nologo /out:"Debug\SoundTouchD.lib"
|
|
||||||
# Begin Special Build Tool
|
|
||||||
SOURCE="$(InputPath)"
|
|
||||||
PostBuild_Cmds=copy .\Debug\SoundTouchD.lib ..\..\lib\
|
|
||||||
# End Special Build Tool
|
|
||||||
|
|
||||||
!ENDIF
|
|
||||||
|
|
||||||
# Begin Target
|
|
||||||
|
|
||||||
# Name "SoundTouch - Win32 Release"
|
|
||||||
# Name "SoundTouch - Win32 Debug"
|
|
||||||
# Begin Group "Source Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
|
||||||
# Begin Group "bpm"
|
|
||||||
|
|
||||||
# PROP Default_Filter ""
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\BPMDetect.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\PeakFinder.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\3dnow_win.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\AAFilter.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cpu_detect_x86_win.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\FIFOSampleBuffer.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\FIRFilter.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\mmx_optimized.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\RateTransposer.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\SoundTouch.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\sse_optimized.cpp
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\TDStretch.cpp
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# Begin Group "Header Files"
|
|
||||||
|
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\AAFilter.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\cpu_detect.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\include\FIFOSampleBuffer.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\include\FIFOSamplePipe.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\FIRFilter.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\RateTransposer.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\include\SoundTouch.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=..\..\include\STTypes.h
|
|
||||||
# End Source File
|
|
||||||
# Begin Source File
|
|
||||||
|
|
||||||
SOURCE=.\TDStretch.h
|
|
||||||
# End Source File
|
|
||||||
# End Group
|
|
||||||
# End Target
|
|
||||||
# End Project
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
|
||||||
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
|
|
||||||
#
|
|
||||||
# $Id$
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Project: "SoundTouch"=.\SoundTouch.dsp - Package Owner=<4>
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<4>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
Global:
|
|
||||||
|
|
||||||
Package=<5>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
Package=<3>
|
|
||||||
{{{
|
|
||||||
}}}
|
|
||||||
|
|
||||||
###############################################################################
|
|
||||||
|
|
||||||
@ -1,21 +1,29 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 8.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "SoundTouch.vcproj", "{0A626C77-0515-4131-AA80-E0BFFC479FEB}"
|
# Visual Studio 14
|
||||||
ProjectSection(ProjectDependencies) = postProject
|
VisualStudioVersion = 14.0.23107.0
|
||||||
EndProjectSection
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SoundTouch", "SoundTouch.vcxproj", "{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfiguration) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug = Debug
|
Debug|Win32 = Debug|Win32
|
||||||
Release = Release
|
Debug|x64 = Debug|x64
|
||||||
|
Release|Win32 = Release|Win32
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
ReleaseX64|Win32 = ReleaseX64|Win32
|
||||||
|
ReleaseX64|x64 = ReleaseX64|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfiguration) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Debug.ActiveCfg = Debug|Win32
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Debug.Build.0 = Debug|Win32
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Release.ActiveCfg = Release|Win32
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{0A626C77-0515-4131-AA80-E0BFFC479FEB}.Release.Build.0 = Release|Win32
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|Win32.ActiveCfg = ReleaseX64|Win32
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|Win32.Build.0 = ReleaseX64|Win32
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|x64.ActiveCfg = ReleaseX64|x64
|
||||||
|
{68A5DD20-7057-448B-8FE0-B6AC8D205509}.ReleaseX64|x64.Build.0 = ReleaseX64|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
EndGlobalSection
|
HideSolutionNode = FALSE
|
||||||
GlobalSection(ExtensibilityAddIns) = postSolution
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@ -1,315 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="Windows-1252"?>
|
|
||||||
<VisualStudioProject
|
|
||||||
ProjectType="Visual C++"
|
|
||||||
Version="7.10"
|
|
||||||
Name="SoundTouch"
|
|
||||||
ProjectGUID="{68A5DD20-7057-448B-8FE0-B6AC8D205509}"
|
|
||||||
SccProjectName=""
|
|
||||||
SccLocalPath="">
|
|
||||||
<Platforms>
|
|
||||||
<Platform
|
|
||||||
Name="Win32"/>
|
|
||||||
</Platforms>
|
|
||||||
<Configurations>
|
|
||||||
<Configuration
|
|
||||||
Name="Release|Win32"
|
|
||||||
OutputDirectory=".\Release"
|
|
||||||
IntermediateDirectory=".\Release"
|
|
||||||
ConfigurationType="4"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="3"
|
|
||||||
InlineFunctionExpansion="2"
|
|
||||||
EnableIntrinsicFunctions="TRUE"
|
|
||||||
AdditionalIncludeDirectories="..\..\include"
|
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
|
||||||
StringPooling="TRUE"
|
|
||||||
RuntimeLibrary="4"
|
|
||||||
EnableFunctionLevelLinking="TRUE"
|
|
||||||
UsePrecompiledHeader="2"
|
|
||||||
PrecompiledHeaderFile=".\Release/SoundTouch.pch"
|
|
||||||
AssemblerListingLocation=".\Release/"
|
|
||||||
ObjectFile=".\Release/"
|
|
||||||
ProgramDataBaseFileName=".\Release/"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="TRUE"
|
|
||||||
DebugInformationFormat="0"
|
|
||||||
CompileAs="0"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLibrarianTool"
|
|
||||||
OutputFile=".\Release\SoundTouch.lib"
|
|
||||||
SuppressStartupBanner="TRUE"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
CommandLine="copy .\Release\SoundTouch.lib ..\..\lib\"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="NDEBUG"
|
|
||||||
Culture="1035"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
<Configuration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
OutputDirectory=".\Debug"
|
|
||||||
IntermediateDirectory=".\Debug"
|
|
||||||
ConfigurationType="4"
|
|
||||||
UseOfMFC="0"
|
|
||||||
ATLMinimizesCRunTimeLibraryUsage="FALSE"
|
|
||||||
CharacterSet="2">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories="..\..\include"
|
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
RuntimeLibrary="5"
|
|
||||||
UsePrecompiledHeader="2"
|
|
||||||
PrecompiledHeaderFile=".\Debug/SoundTouch.pch"
|
|
||||||
AssemblerListingLocation=".\Debug/"
|
|
||||||
ObjectFile=".\Debug/"
|
|
||||||
ProgramDataBaseFileName=".\Debug/"
|
|
||||||
BrowseInformation="1"
|
|
||||||
WarningLevel="3"
|
|
||||||
SuppressStartupBanner="TRUE"
|
|
||||||
DebugInformationFormat="4"
|
|
||||||
CompileAs="0"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCLibrarianTool"
|
|
||||||
OutputFile="Debug\SoundTouchD.lib"
|
|
||||||
SuppressStartupBanner="TRUE"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCMIDLTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPostBuildEventTool"
|
|
||||||
CommandLine="copy .\Debug\SoundTouchD.lib ..\..\lib\"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreBuildEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCPreLinkEventTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCResourceCompilerTool"
|
|
||||||
PreprocessorDefinitions="_DEBUG"
|
|
||||||
Culture="1035"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCWebServiceProxyGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCXMLDataGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCManagedWrapperGeneratorTool"/>
|
|
||||||
<Tool
|
|
||||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
|
||||||
</Configuration>
|
|
||||||
</Configurations>
|
|
||||||
<References>
|
|
||||||
</References>
|
|
||||||
<Files>
|
|
||||||
<Filter
|
|
||||||
Name="Source Files"
|
|
||||||
Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
|
|
||||||
<File
|
|
||||||
RelativePath="AAFilter.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\cpu_detect_x86.cpp">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="FIFOSampleBuffer.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="FIRFilter.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\mmx_optimized.cpp">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="RateTransposer.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="SoundTouch.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\sse_optimized.cpp">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="TDStretch.cpp">
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="2"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32">
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
Optimization="0"
|
|
||||||
AdditionalIncludeDirectories=""
|
|
||||||
PreprocessorDefinitions=""
|
|
||||||
BasicRuntimeChecks="3"
|
|
||||||
BrowseInformation="1"/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
<Filter
|
|
||||||
Name="bpm"
|
|
||||||
Filter="">
|
|
||||||
<File
|
|
||||||
RelativePath=".\BPMDetect.cpp">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\PeakFinder.cpp">
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Header Files"
|
|
||||||
Filter="h;hpp;hxx;hm;inl">
|
|
||||||
<File
|
|
||||||
RelativePath="AAFilter.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\include\BPMDetect.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="cpu_detect.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\include\FIFOSampleBuffer.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\include\FIFOSamplePipe.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="FIRFilter.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath=".\PeakFinder.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="RateTransposer.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\include\SoundTouch.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\include\STTypes.h">
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="TDStretch.h">
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
342
source/SoundTouch/SoundTouch.vcxproj
Normal file
342
source/SoundTouch/SoundTouch.vcxproj
Normal file
@ -0,0 +1,342 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{68A5DD20-7057-448B-8FE0-B6AC8D205509}</ProjectGuid>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<UseOfMfc>false</UseOfMfc>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
<Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<_ProjectFileVersion>14.0.23107.0</_ProjectFileVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)_x64</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)D</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)D_x64</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Full</Optimization>
|
||||||
|
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat />
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
|
||||||
|
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Lib>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
</Lib>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\lib mkdir ..\..\lib
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Midl>
|
||||||
|
<TargetEnvironment>X64</TargetEnvironment>
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Full</Optimization>
|
||||||
|
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<StringPooling>true</StringPooling>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat />
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>
|
||||||
|
</EnableEnhancedInstructionSet>
|
||||||
|
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
|
||||||
|
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Lib>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
</Lib>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\lib mkdir ..\..\lib
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<BrowseInformation>true</BrowseInformation>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
|
||||||
|
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Lib>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
</Lib>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\lib mkdir ..\..\lib
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Midl>
|
||||||
|
<TargetEnvironment>X64</TargetEnvironment>
|
||||||
|
</Midl>
|
||||||
|
<ClCompile>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
|
<PrecompiledHeader />
|
||||||
|
<PrecompiledHeaderOutputFile>$(OutDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||||
|
<AssemblerListingLocation>$(OutDir)</AssemblerListingLocation>
|
||||||
|
<ObjectFileName>$(OutDir)</ObjectFileName>
|
||||||
|
<ProgramDataBaseFileName>$(OutDir)</ProgramDataBaseFileName>
|
||||||
|
<BrowseInformation>true</BrowseInformation>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||||
|
<CompileAs>Default</CompileAs>
|
||||||
|
<EnableEnhancedInstructionSet>
|
||||||
|
</EnableEnhancedInstructionSet>
|
||||||
|
<XMLDocumentationFileName>$(IntDir)</XMLDocumentationFileName>
|
||||||
|
<BrowseInformationFile>$(IntDir)</BrowseInformationFile>
|
||||||
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
|
</ClCompile>
|
||||||
|
<ResourceCompile>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<Culture>0x040b</Culture>
|
||||||
|
</ResourceCompile>
|
||||||
|
<Lib>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||||
|
</Lib>
|
||||||
|
<PostBuildEvent>
|
||||||
|
<Command>if not exist ..\..\lib mkdir ..\..\lib
|
||||||
|
copy $(OutDir)$(TargetName)$(TargetExt) ..\..\lib</Command>
|
||||||
|
</PostBuildEvent>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="AAFilter.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="BPMDetect.cpp">
|
||||||
|
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4996</DisableSpecificWarnings>
|
||||||
|
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4996</DisableSpecificWarnings>
|
||||||
|
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4996</DisableSpecificWarnings>
|
||||||
|
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4996</DisableSpecificWarnings>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="cpu_detect_x86.cpp" />
|
||||||
|
<ClCompile Include="FIFOSampleBuffer.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="FIRFilter.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="InterpolateCubic.cpp" />
|
||||||
|
<ClCompile Include="InterpolateLinear.cpp" />
|
||||||
|
<ClCompile Include="InterpolateShannon.cpp" />
|
||||||
|
<ClCompile Include="mmx_optimized.cpp" />
|
||||||
|
<ClCompile Include="PeakFinder.cpp" />
|
||||||
|
<ClCompile Include="RateTransposer.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="SoundTouch.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="sse_optimized.cpp" />
|
||||||
|
<ClCompile Include="TDStretch.cpp">
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>
|
||||||
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EnableFastChecks</BasicRuntimeChecks>
|
||||||
|
<BrowseInformation Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</BrowseInformation>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>
|
||||||
|
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\include\BPMDetect.h" />
|
||||||
|
<ClInclude Include="..\..\include\FIFOSampleBuffer.h" />
|
||||||
|
<ClInclude Include="..\..\include\FIFOSamplePipe.h" />
|
||||||
|
<ClInclude Include="..\..\include\SoundTouch.h" />
|
||||||
|
<ClInclude Include="..\..\include\STTypes.h" />
|
||||||
|
<ClInclude Include="AAFilter.h" />
|
||||||
|
<ClInclude Include="cpu_detect.h" />
|
||||||
|
<ClInclude Include="FIRFilter.h" />
|
||||||
|
<ClInclude Include="InterpolateCubic.h" />
|
||||||
|
<ClInclude Include="InterpolateLinear.h" />
|
||||||
|
<ClInclude Include="InterpolateShannon.h" />
|
||||||
|
<ClInclude Include="PeakFinder.h" />
|
||||||
|
<ClInclude Include="RateTransposer.h" />
|
||||||
|
<ClInclude Include="TDStretch.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,268 +1,279 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// 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 method
|
/// while maintaining the original pitch by using a time domain WSOLA-like method
|
||||||
/// with several performance-increasing tweaks.
|
/// with several performance-increasing tweaks.
|
||||||
///
|
///
|
||||||
/// Note : MMX/SSE optimized functions reside in separate, platform-specific files
|
/// Note : MMX/SSE optimized functions reside in separate, platform-specific files
|
||||||
/// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
|
/// 'mmx_optimized.cpp' and 'sse_optimized.cpp'
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef TDStretch_H
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define TDStretch_H
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include <stddef.h>
|
||||||
//
|
#include "STTypes.h"
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#include "RateTransposer.h"
|
||||||
|
#include "FIFOSamplePipe.h"
|
||||||
#ifndef TDStretch_H
|
|
||||||
#define TDStretch_H
|
namespace soundtouch
|
||||||
|
{
|
||||||
#include <stddef.h>
|
|
||||||
#include "STTypes.h"
|
/// Default values for sound processing parameters:
|
||||||
#include "RateTransposer.h"
|
/// Notice that the default parameters are tuned for contemporary popular music
|
||||||
#include "FIFOSamplePipe.h"
|
/// processing. For speech processing applications these parameters suit better:
|
||||||
|
/// #define DEFAULT_SEQUENCE_MS 40
|
||||||
namespace soundtouch
|
/// #define DEFAULT_SEEKWINDOW_MS 15
|
||||||
{
|
/// #define DEFAULT_OVERLAP_MS 8
|
||||||
|
///
|
||||||
/// Default values for sound processing parameters:
|
|
||||||
/// Notice that the default parameters are tuned for contemporary popular music
|
/// Default length of a single processing sequence, in milliseconds. This determines to how
|
||||||
/// processing. For speech processing applications these parameters suit better:
|
/// long sequences the original sound is chopped in the time-stretch algorithm.
|
||||||
/// #define DEFAULT_SEQUENCE_MS 40
|
///
|
||||||
/// #define DEFAULT_SEEKWINDOW_MS 15
|
/// The larger this value is, the lesser sequences are used in processing. In principle
|
||||||
/// #define DEFAULT_OVERLAP_MS 8
|
/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
|
||||||
///
|
/// and vice versa.
|
||||||
|
///
|
||||||
/// Default length of a single processing sequence, in milliseconds. This determines to how
|
/// Increasing this value reduces computational burden & vice versa.
|
||||||
/// long sequences the original sound is chopped in the time-stretch algorithm.
|
//#define DEFAULT_SEQUENCE_MS 40
|
||||||
///
|
#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN
|
||||||
/// The larger this value is, the lesser sequences are used in processing. In principle
|
|
||||||
/// a bigger value sounds better when slowing down tempo, but worse when increasing tempo
|
/// Giving this value for the sequence length sets automatic parameter value
|
||||||
/// and vice versa.
|
/// according to tempo setting (recommended)
|
||||||
///
|
#define USE_AUTO_SEQUENCE_LEN 0
|
||||||
/// Increasing this value reduces computational burden & vice versa.
|
|
||||||
//#define DEFAULT_SEQUENCE_MS 40
|
/// Seeking window default length in milliseconds for algorithm that finds the best possible
|
||||||
#define DEFAULT_SEQUENCE_MS USE_AUTO_SEQUENCE_LEN
|
/// overlapping location. This determines from how wide window the algorithm may look for an
|
||||||
|
/// optimal joining location when mixing the sound sequences back together.
|
||||||
/// Giving this value for the sequence length sets automatic parameter value
|
///
|
||||||
/// according to tempo setting (recommended)
|
/// The bigger this window setting is, the higher the possibility to find a better mixing
|
||||||
#define USE_AUTO_SEQUENCE_LEN 0
|
/// position will become, but at the same time large values may cause a "drifting" artifact
|
||||||
|
/// because consequent sequences will be taken at more uneven intervals.
|
||||||
/// Seeking window default length in milliseconds for algorithm that finds the best possible
|
///
|
||||||
/// overlapping location. This determines from how wide window the algorithm may look for an
|
/// If there's a disturbing artifact that sounds as if a constant frequency was drifting
|
||||||
/// optimal joining location when mixing the sound sequences back together.
|
/// around, try reducing this setting.
|
||||||
///
|
///
|
||||||
/// The bigger this window setting is, the higher the possibility to find a better mixing
|
/// Increasing this value increases computational burden & vice versa.
|
||||||
/// position will become, but at the same time large values may cause a "drifting" artifact
|
//#define DEFAULT_SEEKWINDOW_MS 15
|
||||||
/// because consequent sequences will be taken at more uneven intervals.
|
#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN
|
||||||
///
|
|
||||||
/// If there's a disturbing artifact that sounds as if a constant frequency was drifting
|
/// Giving this value for the seek window length sets automatic parameter value
|
||||||
/// around, try reducing this setting.
|
/// according to tempo setting (recommended)
|
||||||
///
|
#define USE_AUTO_SEEKWINDOW_LEN 0
|
||||||
/// Increasing this value increases computational burden & vice versa.
|
|
||||||
//#define DEFAULT_SEEKWINDOW_MS 15
|
/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together,
|
||||||
#define DEFAULT_SEEKWINDOW_MS USE_AUTO_SEEKWINDOW_LEN
|
/// to form a continuous sound stream, this parameter defines over how long period the two
|
||||||
|
/// consecutive sequences are let to overlap each other.
|
||||||
/// Giving this value for the seek window length sets automatic parameter value
|
///
|
||||||
/// according to tempo setting (recommended)
|
/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting
|
||||||
#define USE_AUTO_SEEKWINDOW_LEN 0
|
/// by a large amount, you might wish to try a smaller value on this.
|
||||||
|
///
|
||||||
/// Overlap length in milliseconds. When the chopped sound sequences are mixed back together,
|
/// Increasing this value increases computational burden & vice versa.
|
||||||
/// to form a continuous sound stream, this parameter defines over how long period the two
|
#define DEFAULT_OVERLAP_MS 8
|
||||||
/// consecutive sequences are let to overlap each other.
|
|
||||||
///
|
|
||||||
/// This shouldn't be that critical parameter. If you reduce the DEFAULT_SEQUENCE_MS setting
|
/// Class that does the time-stretch (tempo change) effect for the processed
|
||||||
/// by a large amount, you might wish to try a smaller value on this.
|
/// sound.
|
||||||
///
|
class TDStretch : public FIFOProcessor
|
||||||
/// Increasing this value increases computational burden & vice versa.
|
{
|
||||||
#define DEFAULT_OVERLAP_MS 8
|
protected:
|
||||||
|
int channels;
|
||||||
|
int sampleReq;
|
||||||
/// Class that does the time-stretch (tempo change) effect for the processed
|
|
||||||
/// sound.
|
int overlapLength;
|
||||||
class TDStretch : public FIFOProcessor
|
int seekLength;
|
||||||
{
|
int seekWindowLength;
|
||||||
protected:
|
int overlapDividerBitsNorm;
|
||||||
int channels;
|
int overlapDividerBitsPure;
|
||||||
int sampleReq;
|
int slopingDivider;
|
||||||
float tempo;
|
int sampleRate;
|
||||||
|
int sequenceMs;
|
||||||
SAMPLETYPE *pMidBuffer;
|
int seekWindowMs;
|
||||||
SAMPLETYPE *pMidBufferUnaligned;
|
int overlapMs;
|
||||||
int overlapLength;
|
|
||||||
int seekLength;
|
unsigned long maxnorm;
|
||||||
int seekWindowLength;
|
float maxnormf;
|
||||||
int overlapDividerBits;
|
|
||||||
int slopingDivider;
|
double tempo;
|
||||||
float nominalSkip;
|
double nominalSkip;
|
||||||
float skipFract;
|
double skipFract;
|
||||||
FIFOSampleBuffer outputBuffer;
|
|
||||||
FIFOSampleBuffer inputBuffer;
|
bool bQuickSeek;
|
||||||
BOOL bQuickSeek;
|
bool bAutoSeqSetting;
|
||||||
|
bool bAutoSeekSetting;
|
||||||
int sampleRate;
|
bool isBeginning;
|
||||||
int sequenceMs;
|
|
||||||
int seekWindowMs;
|
SAMPLETYPE *pMidBuffer;
|
||||||
int overlapMs;
|
SAMPLETYPE *pMidBufferUnaligned;
|
||||||
BOOL bAutoSeqSetting;
|
|
||||||
BOOL bAutoSeekSetting;
|
FIFOSampleBuffer outputBuffer;
|
||||||
|
FIFOSampleBuffer inputBuffer;
|
||||||
void acceptNewOverlapLength(int newOverlapLength);
|
|
||||||
|
void acceptNewOverlapLength(int newOverlapLength);
|
||||||
virtual void clearCrossCorrState();
|
|
||||||
void calculateOverlapLength(int overlapMs);
|
virtual void clearCrossCorrState();
|
||||||
|
void calculateOverlapLength(int overlapMs);
|
||||||
virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare) const;
|
|
||||||
|
virtual double calcCrossCorr(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);
|
||||||
virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos);
|
virtual double calcCrossCorrAccumulate(const SAMPLETYPE *mixingPos, const SAMPLETYPE *compare, double &norm);
|
||||||
virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos);
|
|
||||||
int seekBestOverlapPosition(const SAMPLETYPE *refPos);
|
virtual int seekBestOverlapPositionFull(const SAMPLETYPE *refPos);
|
||||||
|
virtual int seekBestOverlapPositionQuick(const SAMPLETYPE *refPos);
|
||||||
virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
virtual int seekBestOverlapPosition(const SAMPLETYPE *refPos);
|
||||||
virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
|
||||||
|
virtual void overlapStereo(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
||||||
void clearMidBuffer();
|
virtual void overlapMono(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
||||||
void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
|
virtual void overlapMulti(SAMPLETYPE *output, const SAMPLETYPE *input) const;
|
||||||
|
|
||||||
void calcSeqParameters();
|
void clearMidBuffer();
|
||||||
|
void overlap(SAMPLETYPE *output, const SAMPLETYPE *input, uint ovlPos) const;
|
||||||
/// Changes the tempo of the given sound samples.
|
|
||||||
/// Returns amount of samples returned in the "output" buffer.
|
void calcSeqParameters();
|
||||||
/// The maximum amount of samples that can be returned at a time is set by
|
void adaptNormalizer();
|
||||||
/// the 'set_returnBuffer_size' function.
|
|
||||||
void processSamples();
|
/// Changes the tempo of the given sound samples.
|
||||||
|
/// Returns amount of samples returned in the "output" buffer.
|
||||||
public:
|
/// The maximum amount of samples that can be returned at a time is set by
|
||||||
TDStretch();
|
/// the 'set_returnBuffer_size' function.
|
||||||
virtual ~TDStretch();
|
void processSamples();
|
||||||
|
|
||||||
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
public:
|
||||||
/// depending on if we've a MMX/SSE/etc-capable CPU available or not.
|
TDStretch();
|
||||||
static void *operator new(size_t s);
|
virtual ~TDStretch() override;
|
||||||
|
|
||||||
/// Use this function instead of "new" operator to create a new instance of this class.
|
/// Operator 'new' is overloaded so that it automatically creates a suitable instance
|
||||||
/// This function automatically chooses a correct feature set depending on if the CPU
|
/// depending on if we've a MMX/SSE/etc-capable CPU available or not.
|
||||||
/// supports MMX/SSE/etc extensions.
|
static void *operator new(size_t s);
|
||||||
static TDStretch *newInstance();
|
|
||||||
|
/// Use this function instead of "new" operator to create a new instance of this class.
|
||||||
/// Returns the output buffer object
|
/// This function automatically chooses a correct feature set depending on if the CPU
|
||||||
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
/// supports MMX/SSE/etc extensions.
|
||||||
|
static TDStretch *newInstance();
|
||||||
/// Returns the input buffer object
|
|
||||||
FIFOSamplePipe *getInput() { return &inputBuffer; };
|
/// Returns the output buffer object
|
||||||
|
FIFOSamplePipe *getOutput() { return &outputBuffer; };
|
||||||
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
|
|
||||||
/// tempo, larger faster tempo.
|
/// Returns the input buffer object
|
||||||
void setTempo(float newTempo);
|
FIFOSamplePipe *getInput() { return &inputBuffer; };
|
||||||
|
|
||||||
/// Returns nonzero if there aren't any samples available for outputting.
|
/// Sets new target tempo. Normal tempo = 'SCALE', smaller values represent slower
|
||||||
virtual void clear();
|
/// tempo, larger faster tempo.
|
||||||
|
void setTempo(double newTempo);
|
||||||
/// Clears the input buffer
|
|
||||||
void clearInput();
|
/// Returns nonzero if there aren't any samples available for outputting.
|
||||||
|
virtual void clear() override;
|
||||||
/// Sets the number of channels, 1 = mono, 2 = stereo
|
|
||||||
void setChannels(int numChannels);
|
/// Clears the input buffer
|
||||||
|
void clearInput();
|
||||||
/// Enables/disables the quick position seeking algorithm. Zero to disable,
|
|
||||||
/// nonzero to enable
|
/// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
void enableQuickSeek(BOOL enable);
|
void setChannels(int numChannels);
|
||||||
|
|
||||||
/// Returns nonzero if the quick seeking algorithm is enabled.
|
/// Enables/disables the quick position seeking algorithm. Zero to disable,
|
||||||
BOOL isQuickSeekEnabled() const;
|
/// nonzero to enable
|
||||||
|
void enableQuickSeek(bool enable);
|
||||||
/// Sets routine control parameters. These control are certain time constants
|
|
||||||
/// defining how the sound is stretched to the desired duration.
|
/// Returns nonzero if the quick seeking algorithm is enabled.
|
||||||
//
|
bool isQuickSeekEnabled() const;
|
||||||
/// 'sampleRate' = sample rate of the sound
|
|
||||||
/// 'sequenceMS' = one processing sequence length in milliseconds
|
/// Sets routine control parameters. These control are certain time constants
|
||||||
/// 'seekwindowMS' = seeking window length for scanning the best overlapping
|
/// defining how the sound is stretched to the desired duration.
|
||||||
/// position
|
//
|
||||||
/// 'overlapMS' = overlapping length
|
/// 'sampleRate' = sample rate of the sound
|
||||||
void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
|
/// 'sequenceMS' = one processing sequence length in milliseconds
|
||||||
int sequenceMS = -1, ///< Single processing sequence length (ms)
|
/// 'seekwindowMS' = seeking window length for scanning the best overlapping
|
||||||
int seekwindowMS = -1, ///< Offset seeking window length (ms)
|
/// position
|
||||||
int overlapMS = -1 ///< Sequence overlapping length (ms)
|
/// 'overlapMS' = overlapping length
|
||||||
);
|
void setParameters(int sampleRate, ///< Samplerate of sound being processed (Hz)
|
||||||
|
int sequenceMS = -1, ///< Single processing sequence length (ms)
|
||||||
/// Get routine control parameters, see setParameters() function.
|
int seekwindowMS = -1, ///< Offset seeking window length (ms)
|
||||||
/// Any of the parameters to this function can be NULL, in such case corresponding parameter
|
int overlapMS = -1 ///< Sequence overlapping length (ms)
|
||||||
/// value isn't returned.
|
);
|
||||||
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
|
|
||||||
|
/// Get routine control parameters, see setParameters() function.
|
||||||
/// Adds 'numsamples' pcs of samples from the 'samples' memory position into
|
/// Any of the parameters to this function can be nullptr, in such case corresponding parameter
|
||||||
/// the input of the object.
|
/// value isn't returned.
|
||||||
virtual void putSamples(
|
void getParameters(int *pSampleRate, int *pSequenceMs, int *pSeekWindowMs, int *pOverlapMs) const;
|
||||||
const SAMPLETYPE *samples, ///< Input sample data
|
|
||||||
uint numSamples ///< Number of samples in 'samples' so that one sample
|
/// Adds 'numsamples' pcs of samples from the 'samples' memory position into
|
||||||
///< contains both channels if stereo
|
/// the input of the object.
|
||||||
);
|
virtual void putSamples(
|
||||||
|
const SAMPLETYPE *samples, ///< Input sample data
|
||||||
/// return nominal input sample requirement for triggering a processing batch
|
uint numSamples ///< Number of samples in 'samples' so that one sample
|
||||||
int getInputSampleReq() const
|
///< contains both channels if stereo
|
||||||
{
|
) override;
|
||||||
return (int)(nominalSkip + 0.5);
|
|
||||||
}
|
/// return nominal input sample requirement for triggering a processing batch
|
||||||
|
int getInputSampleReq() const
|
||||||
/// return nominal output sample amount when running a processing batch
|
{
|
||||||
int getOutputBatchSize() const
|
return (int)(nominalSkip + 0.5);
|
||||||
{
|
}
|
||||||
return seekWindowLength - overlapLength;
|
|
||||||
}
|
/// return nominal output sample amount when running a processing batch
|
||||||
};
|
int getOutputBatchSize() const
|
||||||
|
{
|
||||||
|
return seekWindowLength - overlapLength;
|
||||||
|
}
|
||||||
// Implementation-specific class declarations:
|
|
||||||
|
/// return approximate initial input-output latency
|
||||||
#ifdef SOUNDTOUCH_ALLOW_MMX
|
int getLatency() const
|
||||||
/// Class that implements MMX optimized routines for 16bit integer samples type.
|
{
|
||||||
class TDStretchMMX : public TDStretch
|
return sampleReq;
|
||||||
{
|
}
|
||||||
protected:
|
};
|
||||||
double calcCrossCorr(const short *mixingPos, const short *compare) const;
|
|
||||||
virtual void overlapStereo(short *output, const short *input) const;
|
|
||||||
virtual void clearCrossCorrState();
|
// Implementation-specific class declarations:
|
||||||
};
|
|
||||||
#endif /// SOUNDTOUCH_ALLOW_MMX
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
|
/// Class that implements MMX optimized routines for 16bit integer samples type.
|
||||||
|
class TDStretchMMX : public TDStretch
|
||||||
#ifdef SOUNDTOUCH_ALLOW_SSE
|
{
|
||||||
/// Class that implements SSE optimized routines for floating point samples type.
|
protected:
|
||||||
class TDStretchSSE : public TDStretch
|
double calcCrossCorr(const short *mixingPos, const short *compare, double &norm) override;
|
||||||
{
|
double calcCrossCorrAccumulate(const short *mixingPos, const short *compare, double &norm) override;
|
||||||
protected:
|
virtual void overlapStereo(short *output, const short *input) const override;
|
||||||
double calcCrossCorr(const float *mixingPos, const float *compare) const;
|
virtual void clearCrossCorrState() override;
|
||||||
};
|
};
|
||||||
|
#endif /// SOUNDTOUCH_ALLOW_MMX
|
||||||
#endif /// SOUNDTOUCH_ALLOW_SSE
|
|
||||||
|
|
||||||
}
|
#ifdef SOUNDTOUCH_ALLOW_SSE
|
||||||
#endif /// TDStretch_H
|
/// Class that implements SSE optimized routines for floating point samples type.
|
||||||
|
class TDStretchSSE : public TDStretch
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
double calcCrossCorr(const float *mixingPos, const float *compare, double &norm) override;
|
||||||
|
double calcCrossCorrAccumulate(const float *mixingPos, const float *compare, double &norm) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /// SOUNDTOUCH_ALLOW_SSE
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /// TDStretch_H
|
||||||
|
|||||||
@ -1,62 +1,55 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// A header file for detecting the Intel MMX instructions set extension.
|
/// A header file for detecting the Intel MMX instructions set extension.
|
||||||
///
|
///
|
||||||
/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
|
/// Please see 'mmx_win.cpp', 'mmx_cpp.cpp' and 'mmx_non_x86.cpp' for the
|
||||||
/// routine implementations for x86 Windows, x86 gnu version and non-x86
|
/// routine implementations for x86 Windows, x86 gnu version and non-x86
|
||||||
/// platforms, respectively.
|
/// platforms, respectively.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#ifndef _CPU_DETECT_H_
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#define _CPU_DETECT_H_
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
#include "STTypes.h"
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#define SUPPORT_MMX 0x0001
|
||||||
|
#define SUPPORT_3DNOW 0x0002
|
||||||
#ifndef _CPU_DETECT_H_
|
#define SUPPORT_ALTIVEC 0x0004
|
||||||
#define _CPU_DETECT_H_
|
#define SUPPORT_SSE 0x0008
|
||||||
|
#define SUPPORT_SSE2 0x0010
|
||||||
#include "STTypes.h"
|
|
||||||
|
/// Checks which instruction set extensions are supported by the CPU.
|
||||||
#define SUPPORT_MMX 0x0001
|
///
|
||||||
#define SUPPORT_3DNOW 0x0002
|
/// \return A bitmask of supported extensions, see SUPPORT_... defines.
|
||||||
#define SUPPORT_ALTIVEC 0x0004
|
uint detectCPUextensions(void);
|
||||||
#define SUPPORT_SSE 0x0008
|
|
||||||
#define SUPPORT_SSE2 0x0010
|
/// Disables given set of instruction extensions. See SUPPORT_... defines.
|
||||||
|
void disableExtensions(uint wDisableMask);
|
||||||
/// Checks which instruction set extensions are supported by the CPU.
|
|
||||||
///
|
#endif // _CPU_DETECT_H_
|
||||||
/// \return A bitmask of supported extensions, see SUPPORT_... defines.
|
|
||||||
uint detectCPUextensions(void);
|
|
||||||
|
|
||||||
/// Disables given set of instruction extensions. See SUPPORT_... defines.
|
|
||||||
void disableExtensions(uint wDisableMask);
|
|
||||||
|
|
||||||
#endif // _CPU_DETECT_H_
|
|
||||||
|
|||||||
@ -1,139 +1,130 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// Generic version of the x86 CPU extension detection routine.
|
/// Generic version of the x86 CPU extension detection routine.
|
||||||
///
|
///
|
||||||
/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
|
/// This file is for GNU & other non-Windows compilers, see 'cpu_detect_x86_win.cpp'
|
||||||
/// for the Microsoft compiler version.
|
/// for the Microsoft compiler version.
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include "cpu_detect.h"
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include "STTypes.h"
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
//
|
#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
#if defined(__GNUC__) && defined(__i386__)
|
||||||
#include "cpu_detect.h"
|
// gcc
|
||||||
#include "STTypes.h"
|
#include "cpuid.h"
|
||||||
|
#elif defined(_M_IX86)
|
||||||
#if defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
// windows non-gcc
|
||||||
|
#include <intrin.h>
|
||||||
#if defined(__GNUC__) && defined(__i386__)
|
#endif
|
||||||
// gcc
|
|
||||||
#include "cpuid.h"
|
#define bit_MMX (1 << 23)
|
||||||
#endif
|
#define bit_SSE (1 << 25)
|
||||||
|
#define bit_SSE2 (1 << 26)
|
||||||
#if defined(_M_IX86)
|
#endif
|
||||||
// windows
|
|
||||||
#include <intrin.h>
|
|
||||||
#define bit_MMX (1 << 23)
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
#define bit_SSE (1 << 25)
|
//
|
||||||
#define bit_SSE2 (1 << 26)
|
// processor instructions extension detection routines
|
||||||
#endif
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
#endif
|
|
||||||
|
// Flag variable indicating whick ISA extensions are disabled (for debugging)
|
||||||
|
static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
// Disables given set of instruction extensions. See SUPPORT_... defines.
|
||||||
// processor instructions extension detection routines
|
void disableExtensions(uint dwDisableMask)
|
||||||
//
|
{
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
_dwDisabledISA = dwDisableMask;
|
||||||
|
}
|
||||||
// Flag variable indicating whick ISA extensions are disabled (for debugging)
|
|
||||||
static uint _dwDisabledISA = 0x00; // 0xffffffff; //<- use this to disable all extensions
|
|
||||||
|
/// Checks which instruction set extensions are supported by the CPU.
|
||||||
// Disables given set of instruction extensions. See SUPPORT_... defines.
|
uint detectCPUextensions(void)
|
||||||
void disableExtensions(uint dwDisableMask)
|
{
|
||||||
{
|
/// If building for a 64bit system (no Itanium) and the user wants optimizations.
|
||||||
_dwDisabledISA = dwDisableMask;
|
/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19.
|
||||||
}
|
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
|
||||||
|
#if ((defined(__GNUC__) && defined(__x86_64__)) \
|
||||||
|
|| defined(_M_X64)) \
|
||||||
|
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
||||||
/// Checks which instruction set extensions are supported by the CPU.
|
return 0x19 & ~_dwDisabledISA;
|
||||||
uint detectCPUextensions(void)
|
|
||||||
{
|
/// If building for a 32bit system and the user wants optimizations.
|
||||||
/// If building for a 64bit system (no Itanium) and the user wants optimizations.
|
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
|
||||||
/// Return the OR of SUPPORT_{MMX,SSE,SSE2}. 11001 or 0x19.
|
#elif ((defined(__GNUC__) && defined(__i386__)) \
|
||||||
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
|
|| defined(_M_IX86)) \
|
||||||
#if ((defined(__GNUC__) && defined(__x86_64__)) \
|
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
||||||
|| defined(_M_X64)) \
|
|
||||||
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
if (_dwDisabledISA == 0xffffffff) return 0;
|
||||||
return 0x19 & ~_dwDisabledISA;
|
|
||||||
|
uint res = 0;
|
||||||
/// If building for a 32bit system and the user wants optimizations.
|
|
||||||
/// Keep the _dwDisabledISA test (2 more operations, could be eliminated).
|
#if defined(__GNUC__)
|
||||||
#elif ((defined(__GNUC__) && defined(__i386__)) \
|
// GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support.
|
||||||
|| defined(_M_IX86)) \
|
uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable.
|
||||||
&& defined(SOUNDTOUCH_ALLOW_X86_OPTIMIZATIONS)
|
|
||||||
|
// Check if no cpuid support.
|
||||||
if (_dwDisabledISA == 0xffffffff) return 0;
|
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions.
|
||||||
|
|
||||||
uint res = 0;
|
if (edx & bit_MMX) res = res | SUPPORT_MMX;
|
||||||
|
if (edx & bit_SSE) res = res | SUPPORT_SSE;
|
||||||
#if defined(__GNUC__)
|
if (edx & bit_SSE2) res = res | SUPPORT_SSE2;
|
||||||
// GCC version of cpuid. Requires GCC 4.3.0 or later for __cpuid intrinsic support.
|
|
||||||
uint eax, ebx, ecx, edx; // unsigned int is the standard type. uint is defined by the compiler and not guaranteed to be portable.
|
#else
|
||||||
|
// Window / VS version of cpuid. Notice that Visual Studio 2005 or later required
|
||||||
// Check if no cpuid support.
|
// for __cpuid intrinsic support.
|
||||||
if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx)) return 0; // always disable extensions.
|
int reg[4] = {-1};
|
||||||
|
|
||||||
if (edx & bit_MMX) res = res | SUPPORT_MMX;
|
// Check if no cpuid support.
|
||||||
if (edx & bit_SSE) res = res | SUPPORT_SSE;
|
__cpuid(reg,0);
|
||||||
if (edx & bit_SSE2) res = res | SUPPORT_SSE2;
|
if ((unsigned int)reg[0] == 0) return 0; // always disable extensions.
|
||||||
|
|
||||||
#else
|
__cpuid(reg,1);
|
||||||
// Window / VS version of cpuid. Notice that Visual Studio 2005 or later required
|
if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX;
|
||||||
// for __cpuid intrinsic support.
|
if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE;
|
||||||
int reg[4] = {-1};
|
if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2;
|
||||||
|
|
||||||
// Check if no cpuid support.
|
#endif
|
||||||
__cpuid(reg,0);
|
|
||||||
if ((unsigned int)reg[0] == 0) return 0; // always disable extensions.
|
return res & ~_dwDisabledISA;
|
||||||
|
|
||||||
__cpuid(reg,1);
|
#else
|
||||||
if ((unsigned int)reg[3] & bit_MMX) res = res | SUPPORT_MMX;
|
|
||||||
if ((unsigned int)reg[3] & bit_SSE) res = res | SUPPORT_SSE;
|
/// One of these is true:
|
||||||
if ((unsigned int)reg[3] & bit_SSE2) res = res | SUPPORT_SSE2;
|
/// 1) We don't want optimizations.
|
||||||
|
/// 2) Using an unsupported compiler.
|
||||||
#endif
|
/// 3) Running on a non-x86 platform.
|
||||||
|
return 0;
|
||||||
return res & ~_dwDisabledISA;
|
|
||||||
|
#endif
|
||||||
#else
|
}
|
||||||
|
|
||||||
/// One of these is true:
|
|
||||||
/// 1) We don't want optimizations.
|
|
||||||
/// 2) Using an unsupported compiler.
|
|
||||||
/// 3) Running on a non-x86 platform.
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,317 +1,396 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// MMX optimized routines. All MMX optimized functions have been gathered into
|
/// MMX optimized routines. All MMX optimized functions have been gathered into
|
||||||
/// this single source code file, regardless to their class or original source
|
/// this single source code file, regardless to their class or original source
|
||||||
/// code file, in order to ease porting the library to other compiler and
|
/// code file, in order to ease porting the library to other compiler and
|
||||||
/// processor platforms.
|
/// processor platforms.
|
||||||
///
|
///
|
||||||
/// The MMX-optimizations are programmed using MMX compiler intrinsics that
|
/// The MMX-optimizations are programmed using MMX compiler intrinsics that
|
||||||
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
|
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
|
||||||
/// should compile with both toolsets.
|
/// should compile with both toolsets.
|
||||||
///
|
///
|
||||||
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
|
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
|
||||||
/// 6.0 processor pack" update to support compiler intrinsic syntax. The update
|
/// 6.0 processor pack" update to support compiler intrinsic syntax. The update
|
||||||
/// is available for download at Microsoft Developers Network, see here:
|
/// is available for download at Microsoft Developers Network, see here:
|
||||||
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
|
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include "STTypes.h"
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
|
||||||
// License along with this library; if not, write to the Free Software
|
#ifdef SOUNDTOUCH_ALLOW_MMX
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
// MMX routines available only with integer sample type
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
using namespace soundtouch;
|
||||||
|
|
||||||
#include "STTypes.h"
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
#ifdef SOUNDTOUCH_ALLOW_MMX
|
// implementation of MMX optimized functions of class 'TDStretchMMX'
|
||||||
// MMX routines available only with integer sample type
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
using namespace soundtouch;
|
|
||||||
|
#include "TDStretch.h"
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
#include <mmintrin.h>
|
||||||
//
|
#include <limits.h>
|
||||||
// implementation of MMX optimized functions of class 'TDStretchMMX'
|
#include <math.h>
|
||||||
//
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
// Calculates cross correlation of two buffers
|
||||||
#include "TDStretch.h"
|
double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2, double &dnorm)
|
||||||
#include <mmintrin.h>
|
{
|
||||||
#include <limits.h>
|
const __m64 *pVec1, *pVec2;
|
||||||
#include <math.h>
|
__m64 shifter;
|
||||||
|
__m64 accu, normaccu;
|
||||||
|
long corr, norm;
|
||||||
// Calculates cross correlation of two buffers
|
int i;
|
||||||
double TDStretchMMX::calcCrossCorr(const short *pV1, const short *pV2) const
|
|
||||||
{
|
pVec1 = (__m64*)pV1;
|
||||||
const __m64 *pVec1, *pVec2;
|
pVec2 = (__m64*)pV2;
|
||||||
__m64 shifter;
|
|
||||||
__m64 accu, normaccu;
|
shifter = _m_from_int(overlapDividerBitsNorm);
|
||||||
long corr, norm;
|
normaccu = accu = _mm_setzero_si64();
|
||||||
int i;
|
|
||||||
|
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
|
||||||
pVec1 = (__m64*)pV1;
|
// during each round for improved CPU-level parallellization.
|
||||||
pVec2 = (__m64*)pV2;
|
for (i = 0; i < channels * overlapLength / 16; i ++)
|
||||||
|
{
|
||||||
shifter = _m_from_int(overlapDividerBits);
|
__m64 temp, temp2;
|
||||||
normaccu = accu = _mm_setzero_si64();
|
|
||||||
|
// dictionary of instructions:
|
||||||
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
|
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
|
||||||
// during each round for improved CPU-level parallellization.
|
// _mm_add_pi32 : 2*32bit add
|
||||||
for (i = 0; i < channels * overlapLength / 16; i ++)
|
// _m_psrad : 32bit right-shift
|
||||||
{
|
|
||||||
__m64 temp, temp2;
|
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter),
|
||||||
|
_mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter));
|
||||||
// dictionary of instructions:
|
temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]), shifter),
|
||||||
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
|
_mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec1[1]), shifter));
|
||||||
// _mm_add_pi32 : 2*32bit add
|
accu = _mm_add_pi32(accu, temp);
|
||||||
// _m_psrad : 32bit right-shift
|
normaccu = _mm_add_pi32(normaccu, temp2);
|
||||||
|
|
||||||
temp = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]),
|
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter),
|
||||||
_mm_madd_pi16(pVec1[1], pVec2[1]));
|
_mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter));
|
||||||
temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[0], pVec1[0]),
|
temp2 = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]), shifter),
|
||||||
_mm_madd_pi16(pVec1[1], pVec1[1]));
|
_mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec1[3]), shifter));
|
||||||
accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
|
accu = _mm_add_pi32(accu, temp);
|
||||||
normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter));
|
normaccu = _mm_add_pi32(normaccu, temp2);
|
||||||
|
|
||||||
temp = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]),
|
pVec1 += 4;
|
||||||
_mm_madd_pi16(pVec1[3], pVec2[3]));
|
pVec2 += 4;
|
||||||
temp2 = _mm_add_pi32(_mm_madd_pi16(pVec1[2], pVec1[2]),
|
}
|
||||||
_mm_madd_pi16(pVec1[3], pVec1[3]));
|
|
||||||
accu = _mm_add_pi32(accu, _mm_sra_pi32(temp, shifter));
|
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
|
||||||
normaccu = _mm_add_pi32(normaccu, _mm_sra_pi32(temp2, shifter));
|
// and finally store the result into the variable "corr"
|
||||||
|
|
||||||
pVec1 += 4;
|
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
|
||||||
pVec2 += 4;
|
corr = _m_to_int(accu);
|
||||||
}
|
|
||||||
|
normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32));
|
||||||
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
|
norm = _m_to_int(normaccu);
|
||||||
// and finally store the result into the variable "corr"
|
|
||||||
|
// Clear MMS state
|
||||||
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
|
_m_empty();
|
||||||
corr = _m_to_int(accu);
|
|
||||||
|
if (norm > (long)maxnorm)
|
||||||
normaccu = _mm_add_pi32(normaccu, _mm_srli_si64(normaccu, 32));
|
{
|
||||||
norm = _m_to_int(normaccu);
|
// modify 'maxnorm' inside critical section to avoid multi-access conflict if in OpenMP mode
|
||||||
|
#pragma omp critical
|
||||||
// Clear MMS state
|
if (norm > (long)maxnorm)
|
||||||
_m_empty();
|
{
|
||||||
|
maxnorm = norm;
|
||||||
// Normalize result by dividing by sqrt(norm) - this step is easiest
|
}
|
||||||
// done using floating point operation
|
}
|
||||||
if (norm == 0) norm = 1; // to avoid div by zero
|
|
||||||
|
// Normalize result by dividing by sqrt(norm) - this step is easiest
|
||||||
return (double)corr / sqrt((double)norm);
|
// done using floating point operation
|
||||||
// Note: Warning about the missing EMMS instruction is harmless
|
dnorm = (double)norm;
|
||||||
// as it'll be called elsewhere.
|
|
||||||
}
|
return (double)corr / sqrt(dnorm < 1e-9 ? 1.0 : dnorm);
|
||||||
|
// Note: Warning about the missing EMMS instruction is harmless
|
||||||
|
// as it'll be called elsewhere.
|
||||||
|
}
|
||||||
void TDStretchMMX::clearCrossCorrState()
|
|
||||||
{
|
|
||||||
// Clear MMS state
|
/// Update cross-correlation by accumulating "norm" coefficient by previously calculated value
|
||||||
_m_empty();
|
double TDStretchMMX::calcCrossCorrAccumulate(const short *pV1, const short *pV2, double &dnorm)
|
||||||
//_asm EMMS;
|
{
|
||||||
}
|
const __m64 *pVec1, *pVec2;
|
||||||
|
__m64 shifter;
|
||||||
|
__m64 accu;
|
||||||
|
long corr, lnorm;
|
||||||
// MMX-optimized version of the function overlapStereo
|
int i;
|
||||||
void TDStretchMMX::overlapStereo(short *output, const short *input) const
|
|
||||||
{
|
// cancel first normalizer tap from previous round
|
||||||
const __m64 *pVinput, *pVMidBuf;
|
lnorm = 0;
|
||||||
__m64 *pVdest;
|
for (i = 1; i <= channels; i ++)
|
||||||
__m64 mix1, mix2, adder, shifter;
|
{
|
||||||
int i;
|
lnorm -= (pV1[-i] * pV1[-i]) >> overlapDividerBitsNorm;
|
||||||
|
}
|
||||||
pVinput = (const __m64*)input;
|
|
||||||
pVMidBuf = (const __m64*)pMidBuffer;
|
pVec1 = (__m64*)pV1;
|
||||||
pVdest = (__m64*)output;
|
pVec2 = (__m64*)pV2;
|
||||||
|
|
||||||
// mix1 = mixer values for 1st stereo sample
|
shifter = _m_from_int(overlapDividerBitsNorm);
|
||||||
// mix1 = mixer values for 2nd stereo sample
|
accu = _mm_setzero_si64();
|
||||||
// adder = adder for updating mixer values after each round
|
|
||||||
|
// Process 4 parallel sets of 2 * stereo samples or 4 * mono samples
|
||||||
mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
|
// during each round for improved CPU-level parallellization.
|
||||||
adder = _mm_set_pi16(1, -1, 1, -1);
|
for (i = 0; i < channels * overlapLength / 16; i ++)
|
||||||
mix2 = _mm_add_pi16(mix1, adder);
|
{
|
||||||
adder = _mm_add_pi16(adder, adder);
|
__m64 temp;
|
||||||
|
|
||||||
// Overlaplength-division by shifter. "+1" is to account for "-1" deduced in
|
// dictionary of instructions:
|
||||||
// overlapDividerBits calculation earlier.
|
// _m_pmaddwd : 4*16bit multiply-add, resulting two 32bits = [a0*b0+a1*b1 ; a2*b2+a3*b3]
|
||||||
shifter = _m_from_int(overlapDividerBits + 1);
|
// _mm_add_pi32 : 2*32bit add
|
||||||
|
// _m_psrad : 32bit right-shift
|
||||||
for (i = 0; i < overlapLength / 4; i ++)
|
|
||||||
{
|
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[0], pVec2[0]), shifter),
|
||||||
__m64 temp1, temp2;
|
_mm_sra_pi32(_mm_madd_pi16(pVec1[1], pVec2[1]), shifter));
|
||||||
|
accu = _mm_add_pi32(accu, temp);
|
||||||
// load & shuffle data so that input & mixbuffer data samples are paired
|
|
||||||
temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
|
temp = _mm_add_pi32(_mm_sra_pi32(_mm_madd_pi16(pVec1[2], pVec2[2]), shifter),
|
||||||
temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
|
_mm_sra_pi32(_mm_madd_pi16(pVec1[3], pVec2[3]), shifter));
|
||||||
|
accu = _mm_add_pi32(accu, temp);
|
||||||
// temp = (temp .* mix) >> shifter
|
|
||||||
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
|
pVec1 += 4;
|
||||||
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
|
pVec2 += 4;
|
||||||
pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
|
}
|
||||||
|
|
||||||
// update mix += adder
|
// copy hi-dword of mm0 to lo-dword of mm1, then sum mmo+mm1
|
||||||
mix1 = _mm_add_pi16(mix1, adder);
|
// and finally store the result into the variable "corr"
|
||||||
mix2 = _mm_add_pi16(mix2, adder);
|
|
||||||
|
accu = _mm_add_pi32(accu, _mm_srli_si64(accu, 32));
|
||||||
// --- second round begins here ---
|
corr = _m_to_int(accu);
|
||||||
|
|
||||||
// load & shuffle data so that input & mixbuffer data samples are paired
|
// Clear MMS state
|
||||||
temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r
|
_m_empty();
|
||||||
temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r
|
|
||||||
|
// update normalizer with last samples of this round
|
||||||
// temp = (temp .* mix) >> shifter
|
pV1 = (short *)pVec1;
|
||||||
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
|
for (int j = 1; j <= channels; j ++)
|
||||||
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
|
{
|
||||||
pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
|
lnorm += (pV1[-j] * pV1[-j]) >> overlapDividerBitsNorm;
|
||||||
|
}
|
||||||
// update mix += adder
|
dnorm += (double)lnorm;
|
||||||
mix1 = _mm_add_pi16(mix1, adder);
|
|
||||||
mix2 = _mm_add_pi16(mix2, adder);
|
if (lnorm > (long)maxnorm)
|
||||||
|
{
|
||||||
pVinput += 2;
|
maxnorm = lnorm;
|
||||||
pVMidBuf += 2;
|
}
|
||||||
pVdest += 2;
|
|
||||||
}
|
// Normalize result by dividing by sqrt(norm) - this step is easiest
|
||||||
|
// done using floating point operation
|
||||||
_m_empty(); // clear MMS state
|
return (double)corr / sqrt((dnorm < 1e-9) ? 1.0 : dnorm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
void TDStretchMMX::clearCrossCorrState()
|
||||||
//
|
{
|
||||||
// implementation of MMX optimized functions of class 'FIRFilter'
|
// Clear MMS state
|
||||||
//
|
_m_empty();
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//_asm EMMS;
|
||||||
|
}
|
||||||
#include "FIRFilter.h"
|
|
||||||
|
|
||||||
|
// MMX-optimized version of the function overlapStereo
|
||||||
FIRFilterMMX::FIRFilterMMX() : FIRFilter()
|
void TDStretchMMX::overlapStereo(short *output, const short *input) const
|
||||||
{
|
{
|
||||||
filterCoeffsUnalign = NULL;
|
const __m64 *pVinput, *pVMidBuf;
|
||||||
}
|
__m64 *pVdest;
|
||||||
|
__m64 mix1, mix2, adder, shifter;
|
||||||
|
int i;
|
||||||
FIRFilterMMX::~FIRFilterMMX()
|
|
||||||
{
|
pVinput = (const __m64*)input;
|
||||||
delete[] filterCoeffsUnalign;
|
pVMidBuf = (const __m64*)pMidBuffer;
|
||||||
}
|
pVdest = (__m64*)output;
|
||||||
|
|
||||||
|
// mix1 = mixer values for 1st stereo sample
|
||||||
// (overloaded) Calculates filter coefficients for MMX routine
|
// mix1 = mixer values for 2nd stereo sample
|
||||||
void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)
|
// adder = adder for updating mixer values after each round
|
||||||
{
|
|
||||||
uint i;
|
mix1 = _mm_set_pi16(0, overlapLength, 0, overlapLength);
|
||||||
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
|
adder = _mm_set_pi16(1, -1, 1, -1);
|
||||||
|
mix2 = _mm_add_pi16(mix1, adder);
|
||||||
// Ensure that filter coeffs array is aligned to 16-byte boundary
|
adder = _mm_add_pi16(adder, adder);
|
||||||
delete[] filterCoeffsUnalign;
|
|
||||||
filterCoeffsUnalign = new short[2 * newLength + 8];
|
// Overlaplength-division by shifter. "+1" is to account for "-1" deduced in
|
||||||
filterCoeffsAlign = (short *)(((ulong)filterCoeffsUnalign + 15) & -16);
|
// overlapDividerBits calculation earlier.
|
||||||
|
shifter = _m_from_int(overlapDividerBitsPure + 1);
|
||||||
// rearrange the filter coefficients for mmx routines
|
|
||||||
for (i = 0;i < length; i += 4)
|
for (i = 0; i < overlapLength / 4; i ++)
|
||||||
{
|
{
|
||||||
filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
|
__m64 temp1, temp2;
|
||||||
filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];
|
|
||||||
filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];
|
// load & shuffle data so that input & mixbuffer data samples are paired
|
||||||
filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];
|
temp1 = _mm_unpacklo_pi16(pVMidBuf[0], pVinput[0]); // = i0l m0l i0r m0r
|
||||||
|
temp2 = _mm_unpackhi_pi16(pVMidBuf[0], pVinput[0]); // = i1l m1l i1r m1r
|
||||||
filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];
|
|
||||||
filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];
|
// temp = (temp .* mix) >> shifter
|
||||||
filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];
|
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
|
||||||
filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];
|
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
|
||||||
}
|
pVdest[0] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
|
||||||
}
|
|
||||||
|
// update mix += adder
|
||||||
|
mix1 = _mm_add_pi16(mix1, adder);
|
||||||
|
mix2 = _mm_add_pi16(mix2, adder);
|
||||||
// mmx-optimized version of the filter routine for stereo sound
|
|
||||||
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
|
// --- second round begins here ---
|
||||||
{
|
|
||||||
// Create stack copies of the needed member variables for asm routines :
|
// load & shuffle data so that input & mixbuffer data samples are paired
|
||||||
uint i, j;
|
temp1 = _mm_unpacklo_pi16(pVMidBuf[1], pVinput[1]); // = i2l m2l i2r m2r
|
||||||
__m64 *pVdest = (__m64*)dest;
|
temp2 = _mm_unpackhi_pi16(pVMidBuf[1], pVinput[1]); // = i3l m3l i3r m3r
|
||||||
|
|
||||||
if (length < 2) return 0;
|
// temp = (temp .* mix) >> shifter
|
||||||
|
temp1 = _mm_sra_pi32(_mm_madd_pi16(temp1, mix1), shifter);
|
||||||
for (i = 0; i < (numSamples - length) / 2; i ++)
|
temp2 = _mm_sra_pi32(_mm_madd_pi16(temp2, mix2), shifter);
|
||||||
{
|
pVdest[1] = _mm_packs_pi32(temp1, temp2); // pack 2*2*32bit => 4*16bit
|
||||||
__m64 accu1;
|
|
||||||
__m64 accu2;
|
// update mix += adder
|
||||||
const __m64 *pVsrc = (const __m64*)src;
|
mix1 = _mm_add_pi16(mix1, adder);
|
||||||
const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;
|
mix2 = _mm_add_pi16(mix2, adder);
|
||||||
|
|
||||||
accu1 = accu2 = _mm_setzero_si64();
|
pVinput += 2;
|
||||||
for (j = 0; j < lengthDiv8 * 2; j ++)
|
pVMidBuf += 2;
|
||||||
{
|
pVdest += 2;
|
||||||
__m64 temp1, temp2;
|
}
|
||||||
|
|
||||||
temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0
|
_m_empty(); // clear MMS state
|
||||||
temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1
|
}
|
||||||
|
|
||||||
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0
|
|
||||||
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2
|
// implementation of MMX optimized functions of class 'FIRFilter'
|
||||||
|
//
|
||||||
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1
|
|
||||||
|
#include "FIRFilter.h"
|
||||||
// accu1 += l2*f2+l0*f0 r2*f2+r0*f0
|
|
||||||
// += l3*f3+l1*f1 r3*f3+r1*f1
|
|
||||||
|
FIRFilterMMX::FIRFilterMMX() : FIRFilter()
|
||||||
// accu2 += l3*f2+l1*f0 r3*f2+r1*f0
|
{
|
||||||
// l4*f3+l2*f1 r4*f3+r2*f1
|
filterCoeffsAlign = nullptr;
|
||||||
|
filterCoeffsUnalign = nullptr;
|
||||||
pVfilter += 2;
|
}
|
||||||
pVsrc += 2;
|
|
||||||
}
|
|
||||||
// accu >>= resultDivFactor
|
FIRFilterMMX::~FIRFilterMMX()
|
||||||
accu1 = _mm_srai_pi32(accu1, resultDivFactor);
|
{
|
||||||
accu2 = _mm_srai_pi32(accu2, resultDivFactor);
|
delete[] filterCoeffsUnalign;
|
||||||
|
}
|
||||||
// pack 2*2*32bits => 4*16 bits
|
|
||||||
pVdest[0] = _mm_packs_pi32(accu1, accu2);
|
|
||||||
src += 4;
|
// (overloaded) Calculates filter coefficients for MMX routine
|
||||||
pVdest ++;
|
void FIRFilterMMX::setCoefficients(const short *coeffs, uint newLength, uint uResultDivFactor)
|
||||||
}
|
{
|
||||||
|
uint i;
|
||||||
_m_empty(); // clear emms state
|
FIRFilter::setCoefficients(coeffs, newLength, uResultDivFactor);
|
||||||
|
|
||||||
return (numSamples & 0xfffffffe) - length;
|
// Ensure that filter coeffs array is aligned to 16-byte boundary
|
||||||
}
|
delete[] filterCoeffsUnalign;
|
||||||
|
filterCoeffsUnalign = new short[2 * newLength + 8];
|
||||||
#endif // SOUNDTOUCH_ALLOW_MMX
|
filterCoeffsAlign = (short *)SOUNDTOUCH_ALIGN_POINTER_16(filterCoeffsUnalign);
|
||||||
|
|
||||||
|
// rearrange the filter coefficients for mmx routines
|
||||||
|
for (i = 0;i < length; i += 4)
|
||||||
|
{
|
||||||
|
filterCoeffsAlign[2 * i + 0] = coeffs[i + 0];
|
||||||
|
filterCoeffsAlign[2 * i + 1] = coeffs[i + 2];
|
||||||
|
filterCoeffsAlign[2 * i + 2] = coeffs[i + 0];
|
||||||
|
filterCoeffsAlign[2 * i + 3] = coeffs[i + 2];
|
||||||
|
|
||||||
|
filterCoeffsAlign[2 * i + 4] = coeffs[i + 1];
|
||||||
|
filterCoeffsAlign[2 * i + 5] = coeffs[i + 3];
|
||||||
|
filterCoeffsAlign[2 * i + 6] = coeffs[i + 1];
|
||||||
|
filterCoeffsAlign[2 * i + 7] = coeffs[i + 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// mmx-optimized version of the filter routine for stereo sound
|
||||||
|
uint FIRFilterMMX::evaluateFilterStereo(short *dest, const short *src, uint numSamples) const
|
||||||
|
{
|
||||||
|
// Create stack copies of the needed member variables for asm routines :
|
||||||
|
uint i, j;
|
||||||
|
__m64 *pVdest = (__m64*)dest;
|
||||||
|
|
||||||
|
if (length < 2) return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < (numSamples - length) / 2; i ++)
|
||||||
|
{
|
||||||
|
__m64 accu1;
|
||||||
|
__m64 accu2;
|
||||||
|
const __m64 *pVsrc = (const __m64*)src;
|
||||||
|
const __m64 *pVfilter = (const __m64*)filterCoeffsAlign;
|
||||||
|
|
||||||
|
accu1 = accu2 = _mm_setzero_si64();
|
||||||
|
for (j = 0; j < lengthDiv8 * 2; j ++)
|
||||||
|
{
|
||||||
|
__m64 temp1, temp2;
|
||||||
|
|
||||||
|
temp1 = _mm_unpacklo_pi16(pVsrc[0], pVsrc[1]); // = l2 l0 r2 r0
|
||||||
|
temp2 = _mm_unpackhi_pi16(pVsrc[0], pVsrc[1]); // = l3 l1 r3 r1
|
||||||
|
|
||||||
|
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp1, pVfilter[0])); // += l2*f2+l0*f0 r2*f2+r0*f0
|
||||||
|
accu1 = _mm_add_pi32(accu1, _mm_madd_pi16(temp2, pVfilter[1])); // += l3*f3+l1*f1 r3*f3+r1*f1
|
||||||
|
|
||||||
|
temp1 = _mm_unpacklo_pi16(pVsrc[1], pVsrc[2]); // = l4 l2 r4 r2
|
||||||
|
|
||||||
|
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp2, pVfilter[0])); // += l3*f2+l1*f0 r3*f2+r1*f0
|
||||||
|
accu2 = _mm_add_pi32(accu2, _mm_madd_pi16(temp1, pVfilter[1])); // += l4*f3+l2*f1 r4*f3+r2*f1
|
||||||
|
|
||||||
|
// accu1 += l2*f2+l0*f0 r2*f2+r0*f0
|
||||||
|
// += l3*f3+l1*f1 r3*f3+r1*f1
|
||||||
|
|
||||||
|
// accu2 += l3*f2+l1*f0 r3*f2+r1*f0
|
||||||
|
// l4*f3+l2*f1 r4*f3+r2*f1
|
||||||
|
|
||||||
|
pVfilter += 2;
|
||||||
|
pVsrc += 2;
|
||||||
|
}
|
||||||
|
// accu >>= resultDivFactor
|
||||||
|
accu1 = _mm_srai_pi32(accu1, resultDivFactor);
|
||||||
|
accu2 = _mm_srai_pi32(accu2, resultDivFactor);
|
||||||
|
|
||||||
|
// pack 2*2*32bits => 4*16 bits
|
||||||
|
pVdest[0] = _mm_packs_pi32(accu1, accu2);
|
||||||
|
src += 4;
|
||||||
|
pVdest ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_m_empty(); // clear emms state
|
||||||
|
|
||||||
|
return (numSamples & 0xfffffffe) - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// workaround to not complain about empty module
|
||||||
|
bool _dontcomplain_mmx_empty;
|
||||||
|
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_MMX
|
||||||
|
|||||||
@ -1,361 +1,362 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
///
|
///
|
||||||
/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
|
/// SSE optimized routines for Pentium-III, Athlon-XP and later CPUs. All SSE
|
||||||
/// optimized functions have been gathered into this single source
|
/// optimized functions have been gathered into this single source
|
||||||
/// code file, regardless to their class or original source code file, in order
|
/// code file, regardless to their class or original source code file, in order
|
||||||
/// to ease porting the library to other compiler and processor platforms.
|
/// to ease porting the library to other compiler and processor platforms.
|
||||||
///
|
///
|
||||||
/// The SSE-optimizations are programmed using SSE compiler intrinsics that
|
/// The SSE-optimizations are programmed using SSE compiler intrinsics that
|
||||||
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
|
/// are supported both by Microsoft Visual C++ and GCC compilers, so this file
|
||||||
/// should compile with both toolsets.
|
/// should compile with both toolsets.
|
||||||
///
|
///
|
||||||
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
|
/// NOTICE: If using Visual Studio 6.0, you'll need to install the "Visual C++
|
||||||
/// 6.0 processor pack" update to support SSE instruction set. The update is
|
/// 6.0 processor pack" update to support SSE instruction set. The update is
|
||||||
/// available for download at Microsoft Developers Network, see here:
|
/// available for download at Microsoft Developers Network, see here:
|
||||||
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
|
/// http://msdn.microsoft.com/en-us/vstudio/aa718349.aspx
|
||||||
///
|
///
|
||||||
/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
|
/// If the above URL is expired or removed, go to "http://msdn.microsoft.com" and
|
||||||
/// perform a search with keywords "processor pack".
|
/// perform a search with keywords "processor pack".
|
||||||
///
|
///
|
||||||
/// Author : Copyright (c) Olli Parviainen
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
/// Author e-mail : oparviai 'at' iki.fi
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Last changed : $Date$
|
// License :
|
||||||
// File revision : $Revision: 4 $
|
//
|
||||||
//
|
// SoundTouch audio processing library
|
||||||
// $Id$
|
// 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 :
|
// License as published by the Free Software Foundation; either
|
||||||
//
|
// version 2.1 of the License, or (at your option) any later version.
|
||||||
// SoundTouch audio processing library
|
//
|
||||||
// Copyright (c) Olli Parviainen
|
// This library is distributed in the hope that it will be useful,
|
||||||
//
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// This library is free software; you can redistribute it and/or
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// modify it under the terms of the GNU Lesser General Public
|
// Lesser General Public License for more details.
|
||||||
// License as published by the Free Software Foundation; either
|
//
|
||||||
// version 2.1 of the License, or (at your option) any later version.
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
//
|
// License along with this library; if not, write to the Free Software
|
||||||
// This library is distributed in the hope that it will be useful,
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
// 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.
|
|
||||||
//
|
#include "cpu_detect.h"
|
||||||
// You should have received a copy of the GNU Lesser General Public
|
#include "STTypes.h"
|
||||||
// License along with this library; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
using namespace soundtouch;
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
#ifdef SOUNDTOUCH_ALLOW_SSE
|
||||||
|
|
||||||
#include "cpu_detect.h"
|
// SSE routines available only with float sample type
|
||||||
#include "STTypes.h"
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
using namespace soundtouch;
|
//
|
||||||
|
// implementation of SSE optimized functions of class 'TDStretchSSE'
|
||||||
#ifdef SOUNDTOUCH_ALLOW_SSE
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// SSE routines available only with float sample type
|
|
||||||
|
#include "TDStretch.h"
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
#include <xmmintrin.h>
|
||||||
//
|
#include <math.h>
|
||||||
// implementation of SSE optimized functions of class 'TDStretchSSE'
|
|
||||||
//
|
// Calculates cross correlation of two buffers
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2, double &anorm)
|
||||||
|
{
|
||||||
#include "TDStretch.h"
|
int i;
|
||||||
#include <xmmintrin.h>
|
const float *pVec1;
|
||||||
#include <math.h>
|
const __m128 *pVec2;
|
||||||
|
__m128 vSum, vNorm;
|
||||||
// Calculates cross correlation of two buffers
|
|
||||||
double TDStretchSSE::calcCrossCorr(const float *pV1, const float *pV2) const
|
// Note. It means a major slow-down if the routine needs to tolerate
|
||||||
{
|
// unaligned __m128 memory accesses. It's way faster if we can skip
|
||||||
int i;
|
// unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
|
||||||
const float *pVec1;
|
// This can mean up to ~ 10-fold difference (incl. part of which is
|
||||||
const __m128 *pVec2;
|
// due to skipping every second round for stereo sound though).
|
||||||
__m128 vSum, vNorm;
|
//
|
||||||
|
// Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
|
||||||
// Note. It means a major slow-down if the routine needs to tolerate
|
// for choosing if this little cheating is allowed.
|
||||||
// unaligned __m128 memory accesses. It's way faster if we can skip
|
|
||||||
// unaligned slots and use _mm_load_ps instruction instead of _mm_loadu_ps.
|
#ifdef ST_SIMD_AVOID_UNALIGNED
|
||||||
// This can mean up to ~ 10-fold difference (incl. part of which is
|
// Little cheating allowed, return valid correlation only for
|
||||||
// due to skipping every second round for stereo sound though).
|
// aligned locations, meaning every second round for stereo sound.
|
||||||
//
|
|
||||||
// Compile-time define SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION is provided
|
#define _MM_LOAD _mm_load_ps
|
||||||
// for choosing if this little cheating is allowed.
|
|
||||||
|
if (((ulongptr)pV1) & 15) return -1e50; // skip unaligned locations
|
||||||
#ifdef SOUNDTOUCH_ALLOW_NONEXACT_SIMD_OPTIMIZATION
|
|
||||||
// Little cheating allowed, return valid correlation only for
|
#else
|
||||||
// aligned locations, meaning every second round for stereo sound.
|
// No cheating allowed, use unaligned load & take the resulting
|
||||||
|
// performance hit.
|
||||||
#define _MM_LOAD _mm_load_ps
|
#define _MM_LOAD _mm_loadu_ps
|
||||||
|
#endif
|
||||||
if (((ulong)pV1) & 15) return -1e50; // skip unaligned locations
|
|
||||||
|
// ensure overlapLength is divisible by 8
|
||||||
#else
|
assert((overlapLength % 8) == 0);
|
||||||
// No cheating allowed, use unaligned load & take the resulting
|
|
||||||
// performance hit.
|
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
|
||||||
#define _MM_LOAD _mm_loadu_ps
|
// Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
|
||||||
#endif
|
pVec1 = (const float*)pV1;
|
||||||
|
pVec2 = (const __m128*)pV2;
|
||||||
// ensure overlapLength is divisible by 8
|
vSum = vNorm = _mm_setzero_ps();
|
||||||
assert((overlapLength % 8) == 0);
|
|
||||||
|
// Unroll the loop by factor of 4 * 4 operations. Use same routine for
|
||||||
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
|
// stereo & mono, for mono it just means twice the amount of unrolling.
|
||||||
// Note: pV2 _must_ be aligned to 16-bit boundary, pV1 need not.
|
for (i = 0; i < channels * overlapLength / 16; i ++)
|
||||||
pVec1 = (const float*)pV1;
|
{
|
||||||
pVec2 = (const __m128*)pV2;
|
__m128 vTemp;
|
||||||
vSum = vNorm = _mm_setzero_ps();
|
// vSum += pV1[0..3] * pV2[0..3]
|
||||||
|
vTemp = _MM_LOAD(pVec1);
|
||||||
// Unroll the loop by factor of 4 * 4 operations. Use same routine for
|
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0]));
|
||||||
// stereo & mono, for mono it just means twice the amount of unrolling.
|
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
||||||
for (i = 0; i < channels * overlapLength / 16; i ++)
|
|
||||||
{
|
// vSum += pV1[4..7] * pV2[4..7]
|
||||||
__m128 vTemp;
|
vTemp = _MM_LOAD(pVec1 + 4);
|
||||||
// vSum += pV1[0..3] * pV2[0..3]
|
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1]));
|
||||||
vTemp = _MM_LOAD(pVec1);
|
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
||||||
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp ,pVec2[0]));
|
|
||||||
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
// vSum += pV1[8..11] * pV2[8..11]
|
||||||
|
vTemp = _MM_LOAD(pVec1 + 8);
|
||||||
// vSum += pV1[4..7] * pV2[4..7]
|
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2]));
|
||||||
vTemp = _MM_LOAD(pVec1 + 4);
|
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
||||||
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[1]));
|
|
||||||
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
// vSum += pV1[12..15] * pV2[12..15]
|
||||||
|
vTemp = _MM_LOAD(pVec1 + 12);
|
||||||
// vSum += pV1[8..11] * pV2[8..11]
|
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3]));
|
||||||
vTemp = _MM_LOAD(pVec1 + 8);
|
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
||||||
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[2]));
|
|
||||||
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
pVec1 += 16;
|
||||||
|
pVec2 += 4;
|
||||||
// vSum += pV1[12..15] * pV2[12..15]
|
}
|
||||||
vTemp = _MM_LOAD(pVec1 + 12);
|
|
||||||
vSum = _mm_add_ps(vSum, _mm_mul_ps(vTemp, pVec2[3]));
|
// return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
|
||||||
vNorm = _mm_add_ps(vNorm, _mm_mul_ps(vTemp ,vTemp));
|
float *pvNorm = (float*)&vNorm;
|
||||||
|
float norm = (pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]);
|
||||||
pVec1 += 16;
|
anorm = norm;
|
||||||
pVec2 += 4;
|
|
||||||
}
|
float *pvSum = (float*)&vSum;
|
||||||
|
return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / sqrt(norm < 1e-9 ? 1.0 : norm);
|
||||||
// return value = vSum[0] + vSum[1] + vSum[2] + vSum[3]
|
|
||||||
float *pvNorm = (float*)&vNorm;
|
/* This is approximately corresponding routine in C-language yet without normalization:
|
||||||
double norm = sqrt(pvNorm[0] + pvNorm[1] + pvNorm[2] + pvNorm[3]);
|
double corr, norm;
|
||||||
if (norm < 1e-9) norm = 1.0; // to avoid div by zero
|
uint i;
|
||||||
|
|
||||||
float *pvSum = (float*)&vSum;
|
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
|
||||||
return (double)(pvSum[0] + pvSum[1] + pvSum[2] + pvSum[3]) / norm;
|
corr = norm = 0.0;
|
||||||
|
for (i = 0; i < channels * overlapLength / 16; i ++)
|
||||||
/* This is approximately corresponding routine in C-language yet without normalization:
|
{
|
||||||
double corr, norm;
|
corr += pV1[0] * pV2[0] +
|
||||||
uint i;
|
pV1[1] * pV2[1] +
|
||||||
|
pV1[2] * pV2[2] +
|
||||||
// Calculates the cross-correlation value between 'pV1' and 'pV2' vectors
|
pV1[3] * pV2[3] +
|
||||||
corr = norm = 0.0;
|
pV1[4] * pV2[4] +
|
||||||
for (i = 0; i < channels * overlapLength / 16; i ++)
|
pV1[5] * pV2[5] +
|
||||||
{
|
pV1[6] * pV2[6] +
|
||||||
corr += pV1[0] * pV2[0] +
|
pV1[7] * pV2[7] +
|
||||||
pV1[1] * pV2[1] +
|
pV1[8] * pV2[8] +
|
||||||
pV1[2] * pV2[2] +
|
pV1[9] * pV2[9] +
|
||||||
pV1[3] * pV2[3] +
|
pV1[10] * pV2[10] +
|
||||||
pV1[4] * pV2[4] +
|
pV1[11] * pV2[11] +
|
||||||
pV1[5] * pV2[5] +
|
pV1[12] * pV2[12] +
|
||||||
pV1[6] * pV2[6] +
|
pV1[13] * pV2[13] +
|
||||||
pV1[7] * pV2[7] +
|
pV1[14] * pV2[14] +
|
||||||
pV1[8] * pV2[8] +
|
pV1[15] * pV2[15];
|
||||||
pV1[9] * pV2[9] +
|
|
||||||
pV1[10] * pV2[10] +
|
for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j];
|
||||||
pV1[11] * pV2[11] +
|
|
||||||
pV1[12] * pV2[12] +
|
pV1 += 16;
|
||||||
pV1[13] * pV2[13] +
|
pV2 += 16;
|
||||||
pV1[14] * pV2[14] +
|
}
|
||||||
pV1[15] * pV2[15];
|
return corr / sqrt(norm);
|
||||||
|
*/
|
||||||
for (j = 0; j < 15; j ++) norm += pV1[j] * pV1[j];
|
}
|
||||||
|
|
||||||
pV1 += 16;
|
|
||||||
pV2 += 16;
|
|
||||||
}
|
double TDStretchSSE::calcCrossCorrAccumulate(const float *pV1, const float *pV2, double &norm)
|
||||||
return corr / sqrt(norm);
|
{
|
||||||
*/
|
// call usual calcCrossCorr function because SSE does not show big benefit of
|
||||||
}
|
// accumulating "norm" value, and also the "norm" rolling algorithm would get
|
||||||
|
// complicated due to SSE-specific alignment-vs-nonexact correlation rules.
|
||||||
|
return calcCrossCorr(pV1, pV2, norm);
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
}
|
||||||
//
|
|
||||||
// implementation of SSE optimized functions of class 'FIRFilter'
|
|
||||||
//
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//
|
||||||
|
// implementation of SSE optimized functions of class 'FIRFilter'
|
||||||
#include "FIRFilter.h"
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
FIRFilterSSE::FIRFilterSSE() : FIRFilter()
|
|
||||||
{
|
#include "FIRFilter.h"
|
||||||
filterCoeffsAlign = NULL;
|
|
||||||
filterCoeffsUnalign = NULL;
|
FIRFilterSSE::FIRFilterSSE() : FIRFilter()
|
||||||
}
|
{
|
||||||
|
filterCoeffsAlign = nullptr;
|
||||||
|
filterCoeffsUnalign = nullptr;
|
||||||
FIRFilterSSE::~FIRFilterSSE()
|
}
|
||||||
{
|
|
||||||
delete[] filterCoeffsUnalign;
|
|
||||||
filterCoeffsAlign = NULL;
|
FIRFilterSSE::~FIRFilterSSE()
|
||||||
filterCoeffsUnalign = NULL;
|
{
|
||||||
}
|
delete[] filterCoeffsUnalign;
|
||||||
|
filterCoeffsAlign = nullptr;
|
||||||
|
filterCoeffsUnalign = nullptr;
|
||||||
// (overloaded) Calculates filter coefficients for SSE routine
|
}
|
||||||
void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
|
|
||||||
{
|
|
||||||
uint i;
|
// (overloaded) Calculates filter coefficients for SSE routine
|
||||||
float fDivider;
|
void FIRFilterSSE::setCoefficients(const float *coeffs, uint newLength, uint uResultDivFactor)
|
||||||
|
{
|
||||||
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
|
||||||
// also rearrange coefficients suitably for SSE
|
// also rearrange coefficients suitably for SSE
|
||||||
// Ensure that filter coeffs array is aligned to 16-byte boundary
|
// Ensure that filter coeffs array is aligned to 16-byte boundary
|
||||||
delete[] filterCoeffsUnalign;
|
delete[] filterCoeffsUnalign;
|
||||||
filterCoeffsUnalign = new float[2 * newLength + 4];
|
filterCoeffsUnalign = new float[2 * newLength + 4];
|
||||||
filterCoeffsAlign = (float *)(((unsigned long)filterCoeffsUnalign + 15) & (ulong)-16);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// SSE-optimized version of the filter routine for stereo sound
|
// SSE-optimized version of the filter routine for stereo sound
|
||||||
uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const
|
uint FIRFilterSSE::evaluateFilterStereo(float *dest, const float *source, uint numSamples) const
|
||||||
{
|
{
|
||||||
int count = (int)((numSamples - length) & (uint)-2);
|
int count = (int)((numSamples - length) & (uint)-2);
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
assert(count % 2 == 0);
|
assert(count % 2 == 0);
|
||||||
|
|
||||||
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(((ulong)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'
|
||||||
for (j = 0; j < count; j += 2)
|
#pragma omp parallel for
|
||||||
{
|
for (j = 0; j < count; j += 2)
|
||||||
const float *pSrc;
|
{
|
||||||
const __m128 *pFil;
|
const float *pSrc;
|
||||||
__m128 sum1, sum2;
|
float *pDest;
|
||||||
uint i;
|
const __m128 *pFil;
|
||||||
|
__m128 sum1, sum2;
|
||||||
pSrc = (const float*)source; // source audio data
|
uint i;
|
||||||
pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
|
|
||||||
// are aligned to 16-byte boundary
|
pSrc = (const float*)source + j * 2; // source audio data
|
||||||
sum1 = sum2 = _mm_setzero_ps();
|
pDest = dest + j * 2; // destination audio data
|
||||||
|
pFil = (const __m128*)filterCoeffsAlign; // filter coefficients. NOTE: Assumes coefficients
|
||||||
for (i = 0; i < length / 8; i ++)
|
// are aligned to 16-byte boundary
|
||||||
{
|
sum1 = sum2 = _mm_setzero_ps();
|
||||||
// Unroll loop for efficiency & calculate filter for 2*2 stereo samples
|
|
||||||
// at each pass
|
for (i = 0; i < length / 8; i ++)
|
||||||
|
{
|
||||||
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
|
// Unroll loop for efficiency & calculate filter for 2*2 stereo samples
|
||||||
// sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
|
// at each pass
|
||||||
|
|
||||||
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0]));
|
// sum1 is accu for 2*2 filtered stereo sound data at the primary sound data offset
|
||||||
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));
|
// sum2 is accu for 2*2 filtered stereo sound data for the next sound sample offset.
|
||||||
|
|
||||||
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));
|
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc) , pFil[0]));
|
||||||
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));
|
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 2), pFil[0]));
|
||||||
|
|
||||||
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2]));
|
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 4), pFil[1]));
|
||||||
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));
|
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 6), pFil[1]));
|
||||||
|
|
||||||
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));
|
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 8) , pFil[2]));
|
||||||
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
|
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 10), pFil[2]));
|
||||||
|
|
||||||
pSrc += 16;
|
sum1 = _mm_add_ps(sum1, _mm_mul_ps(_mm_loadu_ps(pSrc + 12), pFil[3]));
|
||||||
pFil += 4;
|
sum2 = _mm_add_ps(sum2, _mm_mul_ps(_mm_loadu_ps(pSrc + 14), pFil[3]));
|
||||||
}
|
|
||||||
|
pSrc += 16;
|
||||||
// Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need
|
pFil += 4;
|
||||||
// to sum the two hi- and lo-floats of these registers together.
|
}
|
||||||
|
|
||||||
// post-shuffle & add the filtered values and store to dest.
|
// Now sum1 and sum2 both have a filtered 2-channel sample each, but we still need
|
||||||
_mm_storeu_ps(dest, _mm_add_ps(
|
// to sum the two hi- and lo-floats of these registers together.
|
||||||
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
|
|
||||||
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
|
// post-shuffle & add the filtered values and store to dest.
|
||||||
));
|
_mm_storeu_ps(pDest, _mm_add_ps(
|
||||||
source += 4;
|
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(1,0,3,2)), // s2_1 s2_0 s1_3 s1_2
|
||||||
dest += 4;
|
_mm_shuffle_ps(sum1, sum2, _MM_SHUFFLE(3,2,1,0)) // s2_3 s2_2 s1_1 s1_0
|
||||||
}
|
));
|
||||||
|
}
|
||||||
// Ideas for further improvement:
|
|
||||||
// 1. If it could be guaranteed that 'source' were always aligned to 16-byte
|
// Ideas for further improvement:
|
||||||
// boundary, a faster aligned '_mm_load_ps' instruction could be used.
|
// 1. If it could be guaranteed that 'source' were always aligned to 16-byte
|
||||||
// 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
|
// boundary, a faster aligned '_mm_load_ps' instruction could be used.
|
||||||
// boundary, a faster '_mm_store_ps' instruction could be used.
|
// 2. If it could be guaranteed that 'dest' were always aligned to 16-byte
|
||||||
|
// boundary, a faster '_mm_store_ps' instruction could be used.
|
||||||
return (uint)count;
|
|
||||||
|
return (uint)count;
|
||||||
/* original routine in C-language. please notice the C-version has differently
|
|
||||||
organized coefficients though.
|
/* original routine in C-language. please notice the C-version has differently
|
||||||
double suml1, suml2;
|
organized coefficients though.
|
||||||
double sumr1, sumr2;
|
double suml1, suml2;
|
||||||
uint i, j;
|
double sumr1, sumr2;
|
||||||
|
uint i, j;
|
||||||
for (j = 0; j < count; j += 2)
|
|
||||||
{
|
for (j = 0; j < count; j += 2)
|
||||||
const float *ptr;
|
{
|
||||||
const float *pFil;
|
const float *ptr;
|
||||||
|
const float *pFil;
|
||||||
suml1 = sumr1 = 0.0;
|
|
||||||
suml2 = sumr2 = 0.0;
|
suml1 = sumr1 = 0.0;
|
||||||
ptr = src;
|
suml2 = sumr2 = 0.0;
|
||||||
pFil = filterCoeffs;
|
ptr = src;
|
||||||
for (i = 0; i < lengthLocal; i ++)
|
pFil = filterCoeffs;
|
||||||
{
|
for (i = 0; i < lengthLocal; i ++)
|
||||||
// unroll loop for efficiency.
|
{
|
||||||
|
// unroll loop for efficiency.
|
||||||
suml1 += ptr[0] * pFil[0] +
|
|
||||||
ptr[2] * pFil[2] +
|
suml1 += ptr[0] * pFil[0] +
|
||||||
ptr[4] * pFil[4] +
|
ptr[2] * pFil[2] +
|
||||||
ptr[6] * pFil[6];
|
ptr[4] * pFil[4] +
|
||||||
|
ptr[6] * pFil[6];
|
||||||
sumr1 += ptr[1] * pFil[1] +
|
|
||||||
ptr[3] * pFil[3] +
|
sumr1 += ptr[1] * pFil[1] +
|
||||||
ptr[5] * pFil[5] +
|
ptr[3] * pFil[3] +
|
||||||
ptr[7] * pFil[7];
|
ptr[5] * pFil[5] +
|
||||||
|
ptr[7] * pFil[7];
|
||||||
suml2 += ptr[8] * pFil[0] +
|
|
||||||
ptr[10] * pFil[2] +
|
suml2 += ptr[8] * pFil[0] +
|
||||||
ptr[12] * pFil[4] +
|
ptr[10] * pFil[2] +
|
||||||
ptr[14] * pFil[6];
|
ptr[12] * pFil[4] +
|
||||||
|
ptr[14] * pFil[6];
|
||||||
sumr2 += ptr[9] * pFil[1] +
|
|
||||||
ptr[11] * pFil[3] +
|
sumr2 += ptr[9] * pFil[1] +
|
||||||
ptr[13] * pFil[5] +
|
ptr[11] * pFil[3] +
|
||||||
ptr[15] * pFil[7];
|
ptr[13] * pFil[5] +
|
||||||
|
ptr[15] * pFil[7];
|
||||||
ptr += 16;
|
|
||||||
pFil += 8;
|
ptr += 16;
|
||||||
}
|
pFil += 8;
|
||||||
dest[0] = (float)suml1;
|
}
|
||||||
dest[1] = (float)sumr1;
|
dest[0] = (float)suml1;
|
||||||
dest[2] = (float)suml2;
|
dest[1] = (float)sumr1;
|
||||||
dest[3] = (float)sumr2;
|
dest[2] = (float)suml2;
|
||||||
|
dest[3] = (float)sumr2;
|
||||||
src += 4;
|
|
||||||
dest += 4;
|
src += 4;
|
||||||
}
|
dest += 4;
|
||||||
*/
|
}
|
||||||
}
|
*/
|
||||||
|
}
|
||||||
#endif // SOUNDTOUCH_ALLOW_SSE
|
|
||||||
|
#endif // SOUNDTOUCH_ALLOW_SSE
|
||||||
|
|||||||
115
source/SoundTouchDLL/DllTest/DllTest.cpp
Normal file
115
source/SoundTouchDLL/DllTest/DllTest.cpp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
///
|
||||||
|
/// DllTest.cpp : This is small app main routine used for testing sound processing
|
||||||
|
/// with SoundTouch.dll API
|
||||||
|
///
|
||||||
|
/// Author : Copyright (c) Olli Parviainen
|
||||||
|
/// Author e-mail : oparviai 'at' iki.fi
|
||||||
|
/// SoundTouch WWW: http://www.surina.net/soundtouch
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include "../SoundTouchDLL.h"
|
||||||
|
#include "../../SoundStretch/WavFile.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace soundstretch;
|
||||||
|
|
||||||
|
// DllTest main
|
||||||
|
int wmain(int argc, const wchar_t *argv[])
|
||||||
|
{
|
||||||
|
// Check program arguments
|
||||||
|
if (argc < 4)
|
||||||
|
{
|
||||||
|
cout << "Too few arguments. Usage: DllTest [infile.wav] [outfile.wav] [sampletype]" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wstring inFileName = argv[1];
|
||||||
|
wstring outFileName = argv[2];
|
||||||
|
wstring str_sampleType = argv[3];
|
||||||
|
|
||||||
|
bool floatSample;
|
||||||
|
if (str_sampleType == L"float")
|
||||||
|
{
|
||||||
|
floatSample = true;
|
||||||
|
}
|
||||||
|
else if (str_sampleType == L"short")
|
||||||
|
{
|
||||||
|
floatSample = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cerr << "Missing or invalid sampletype. Expected either short or float" << endl;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Open input & output WAV files
|
||||||
|
WavInFile inFile(inFileName);
|
||||||
|
int numChannels = inFile.getNumChannels();
|
||||||
|
int sampleRate = inFile.getSampleRate();
|
||||||
|
WavOutFile outFile(outFileName, sampleRate, inFile.getNumBits(), numChannels);
|
||||||
|
|
||||||
|
// Create SoundTouch DLL instance
|
||||||
|
HANDLE st = soundtouch_createInstance();
|
||||||
|
soundtouch_setChannels(st, numChannels);
|
||||||
|
soundtouch_setSampleRate(st, sampleRate);
|
||||||
|
soundtouch_setPitchSemiTones(st, 2);
|
||||||
|
|
||||||
|
cout << "processing with soundtouch.dll routines";
|
||||||
|
|
||||||
|
if (floatSample)
|
||||||
|
{
|
||||||
|
// Process file with SoundTouch.DLL float sample (default) API
|
||||||
|
float fbuffer[2048];
|
||||||
|
int nmax = 2048 / numChannels;
|
||||||
|
|
||||||
|
cout << " using float api ..." << endl;
|
||||||
|
while (inFile.eof() == false)
|
||||||
|
{
|
||||||
|
int n = inFile.read(fbuffer, nmax * numChannels) / numChannels;
|
||||||
|
soundtouch_putSamples(st, fbuffer, n);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n = soundtouch_receiveSamples(st, fbuffer, nmax);
|
||||||
|
outFile.write(fbuffer, n * numChannels);
|
||||||
|
} while (n > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Process file with SoundTouch.DLL int16 (short) sample API.
|
||||||
|
// Notice that SoundTouch.dll does internally processing using floating
|
||||||
|
// point routines so the int16 API is not any faster, but provided for
|
||||||
|
// convenience.
|
||||||
|
short i16buffer[2048];
|
||||||
|
int nmax = 2048 / numChannels;
|
||||||
|
|
||||||
|
cout << " using i16 api ..." << endl;
|
||||||
|
while (inFile.eof() == false)
|
||||||
|
{
|
||||||
|
int n = inFile.read(i16buffer, nmax * numChannels) / numChannels;
|
||||||
|
soundtouch_putSamples_i16(st, i16buffer, n);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
n = soundtouch_receiveSamples_i16(st, i16buffer, nmax);
|
||||||
|
outFile.write(i16buffer, n * numChannels);
|
||||||
|
} while (n > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
soundtouch_destroyInstance(st);
|
||||||
|
cout << "done." << endl;
|
||||||
|
}
|
||||||
|
catch (const runtime_error &e)
|
||||||
|
{
|
||||||
|
cerr << e.what() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
180
source/SoundTouchDLL/DllTest/DllTest.vcxproj
Normal file
180
source/SoundTouchDLL/DllTest/DllTest.vcxproj
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{E3C0726F-28F4-4F0B-8183-B87CA60C063C}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>DllTest</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<TargetName>$(ProjectName)D</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<TargetName>$(ProjectName)D_x64</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<IntDir>$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(Platform)\$(Configuration)\</OutDir>
|
||||||
|
<TargetName>$(ProjectName)_x64</TargetName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
|
||||||
|
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>..\..\..\lib\SoundTouchDllD.lib</AdditionalDependencies>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
|
||||||
|
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>..\..\..\lib\SoundTouchDllD_x64.lib</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
|
||||||
|
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>..\..\..\lib\SoundTouchDll.lib</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>../../../include</AdditionalIncludeDirectories>
|
||||||
|
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>..\..\..\lib\SoundTouchDll_x64.lib</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Text Include="ReadMe.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="stdafx.h" />
|
||||||
|
<ClInclude Include="targetver.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\..\SoundStretch\WavFile.cpp" />
|
||||||
|
<ClCompile Include="DllTest.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
||||||
10
source/SoundTouchDLL/LazarusTest/README.txt
Normal file
10
source/SoundTouchDLL/LazarusTest/README.txt
Normal 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.
|
||||||
@ -2,13 +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
|
|
||||||
//
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// $Id$
|
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@ -35,58 +30,60 @@ unit SoundTouchDLL;
|
|||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
//uses
|
||||||
Windows;
|
//Windows;
|
||||||
|
|
||||||
type
|
type
|
||||||
TSoundTouchHandle = THandle;
|
TSoundTouchHandle = THandle;
|
||||||
|
|
||||||
// Create a new instance of SoundTouch processor.
|
// Create a new instance of SoundTouch processor.
|
||||||
TSoundTouchCreateInstance = function : TSoundTouchHandle; stdcall;
|
TSoundTouchCreateInstance = function : TSoundTouchHandle; cdecl;
|
||||||
|
|
||||||
// Destroys a SoundTouch processor instance.
|
// Destroys a SoundTouch processor instance.
|
||||||
TSoundTouchDestroyInstance = procedure (Handle: TSoundTouchHandle); stdcall;
|
TSoundTouchDestroyInstance = procedure (Handle: TSoundTouchHandle); cdecl;
|
||||||
|
|
||||||
// Get SoundTouch library version string
|
// Get SoundTouch library version string
|
||||||
TSoundTouchGetVersionString = function : PChar; stdcall;
|
TSoundTouchGetVersionString = function : PAnsiChar; cdecl;
|
||||||
|
|
||||||
|
// Get SoundTouch library version string 2
|
||||||
|
TSoundTouchGetVersionString2 = procedure(VersionString : PAnsiChar; BufferSize : Integer); cdecl;
|
||||||
|
|
||||||
// Get SoundTouch library version Id
|
// Get SoundTouch library version Id
|
||||||
TSoundTouchGetVersionId = function : Cardinal; stdcall;
|
TSoundTouchGetVersionId = function : Cardinal; cdecl;
|
||||||
|
|
||||||
// Sets new rate control value. Normal rate = 1.0, smaller values
|
// Sets new rate control value. Normal rate = 1.0, smaller values
|
||||||
// represent slower rate, larger faster rates.
|
// represent slower rate, larger faster rates.
|
||||||
TSoundTouchSetRate = procedure (Handle: TSoundTouchHandle; newRate: Single); stdcall;
|
TSoundTouchSetRate = procedure (Handle: TSoundTouchHandle; NewRate: Single); cdecl;
|
||||||
|
|
||||||
// Sets new tempo control value. Normal tempo = 1.0, smaller values
|
// Sets new tempo control value. Normal tempo = 1.0, smaller values
|
||||||
// represent slower tempo, larger faster tempo.
|
// represent slower tempo, larger faster tempo.
|
||||||
TSoundTouchSetTempo = procedure (Handle: TSoundTouchHandle; newTempo: Single); stdcall;
|
TSoundTouchSetTempo = procedure (Handle: TSoundTouchHandle; NewTempo: Single); cdecl;
|
||||||
|
|
||||||
// Sets new rate control value as a difference in percents compared
|
// Sets new rate control value as a difference in percents compared
|
||||||
// to the original rate (-50 .. +100 %);
|
// to the original rate (-50 .. +100 %);
|
||||||
TSoundTouchSetRateChange = procedure (Handle: TSoundTouchHandle; newRate: Single); stdcall;
|
TSoundTouchSetRateChange = procedure (Handle: TSoundTouchHandle; NewRate: Single); cdecl;
|
||||||
|
|
||||||
// Sets new tempo control value as a difference in percents compared
|
// Sets new tempo control value as a difference in percents compared
|
||||||
// to the original tempo (-50 .. +100 %);
|
// to the original tempo (-50 .. +100 %);
|
||||||
TSoundTouchSetTempoChange = procedure (Handle: TSoundTouchHandle; newTempo: Single); stdcall;
|
TSoundTouchSetTempoChange = procedure (Handle: TSoundTouchHandle; NewTempo: Single); cdecl;
|
||||||
|
|
||||||
// Sets new pitch control value. Original pitch = 1.0, smaller values
|
// Sets new pitch control value. Original pitch = 1.0, smaller values
|
||||||
// represent lower pitches, larger values higher pitch.
|
// represent lower pitches, larger values higher pitch.
|
||||||
TSoundTouchSetPitch = procedure (Handle: TSoundTouchHandle; newPitch: Single); stdcall;
|
TSoundTouchSetPitch = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;
|
||||||
|
|
||||||
// Sets pitch change in octaves compared to the original pitch
|
// Sets pitch change in octaves compared to the original pitch
|
||||||
// (-1.00 .. +1.00);
|
// (-1.00 .. +1.00);
|
||||||
TSoundTouchSetPitchOctaves = procedure (Handle: TSoundTouchHandle; newPitch: Single); stdcall;
|
TSoundTouchSetPitchOctaves = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;
|
||||||
|
|
||||||
// Sets pitch change in semi-tones compared to the original pitch
|
// Sets pitch change in semi-tones compared to the original pitch
|
||||||
// (-12 .. +12);
|
// (-12 .. +12);
|
||||||
TSoundTouchSetPitchSemiTones = procedure (Handle: TSoundTouchHandle; newPitch: Single); stdcall;
|
TSoundTouchSetPitchSemiTones = procedure (Handle: TSoundTouchHandle; NewPitch: Single); cdecl;
|
||||||
|
|
||||||
|
|
||||||
// Sets the number of channels, 1 = mono, 2 = stereo
|
// Sets the number of channels, 1 = mono, 2 = stereo
|
||||||
TSoundTouchSetChannels = procedure (Handle: TSoundTouchHandle; numChannels: Cardinal); stdcall;
|
TSoundTouchSetChannels = procedure (Handle: TSoundTouchHandle; NumChannels: Cardinal); cdecl;
|
||||||
|
|
||||||
// Sets sample rate.
|
// Sets sample rate.
|
||||||
TSoundTouchSetSampleRate = procedure (Handle: TSoundTouchHandle; SampleRate: Cardinal); stdcall;
|
TSoundTouchSetSampleRate = procedure (Handle: TSoundTouchHandle; SampleRate: Cardinal); cdecl;
|
||||||
|
|
||||||
// Flushes the last samples from the processing pipeline to the output.
|
// Flushes the last samples from the processing pipeline to the output.
|
||||||
// Clears also the internal processing buffers.
|
// Clears also the internal processing buffers.
|
||||||
@ -95,7 +92,7 @@ type
|
|||||||
// 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
|
// of the sound stream, and thus it
|
||||||
// in the middle of a sound stream.
|
// in the middle of a sound stream.
|
||||||
TSoundTouchFlush = procedure (Handle: TSoundTouchHandle); stdcall;
|
TSoundTouchFlush = procedure (Handle: TSoundTouchHandle); cdecl;
|
||||||
|
|
||||||
// Adds 'numSamples' pcs of samples from the 'samples' memory position into
|
// 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
|
||||||
@ -105,53 +102,64 @@ type
|
|||||||
NumSamples: Cardinal //< Number of samples in buffer. Notice
|
NumSamples: Cardinal //< 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.
|
||||||
); stdcall;
|
); cdecl;
|
||||||
|
|
||||||
|
TSoundTouchPutSamplesI16 = procedure (Handle: TSoundTouchHandle;
|
||||||
|
const Samples: Pint16; //< Pointer to sample buffer.
|
||||||
|
NumSamples: Cardinal //< Number of samples in buffer. Notice
|
||||||
|
//< that in case of stereo-sound a single sample
|
||||||
|
//< contains data for both channels.
|
||||||
|
); cdecl;
|
||||||
|
|
||||||
// Clears all the samples in the object's output and internal processing
|
// Clears all the samples in the object's output and internal processing
|
||||||
// buffers.
|
// buffers.
|
||||||
TSoundTouchClear = procedure (Handle: TSoundTouchHandle); stdcall;
|
TSoundTouchClear = procedure (Handle: TSoundTouchHandle); cdecl;
|
||||||
|
|
||||||
// Changes a setting controlling the processing system behaviour. See the
|
// Changes a setting controlling the processing system behaviour. See the
|
||||||
// 'SETTING_...' defines for available setting ID's.
|
// 'SETTING_...' defines for available setting ID's.
|
||||||
//
|
//
|
||||||
// \return 'TRUE' if the setting was succesfully changed
|
// \return 'TRUE' if the setting was successfully changed
|
||||||
TSoundTouchSetSetting = function (Handle: TSoundTouchHandle;
|
TSoundTouchSetSetting = function (Handle: TSoundTouchHandle;
|
||||||
SettingId: Integer; //< Setting ID number. see SETTING_... defines.
|
SettingId: Integer; //< Setting ID number. see SETTING_... defines.
|
||||||
Value: Integer //< New setting value.
|
Value: Integer //< New setting value.
|
||||||
): Boolean; stdcall;
|
): Boolean; cdecl;
|
||||||
|
|
||||||
// Reads a setting controlling the processing system behaviour. See the
|
// Reads a setting controlling the processing system behaviour. See the
|
||||||
// 'SETTING_...' defines for available setting ID's.
|
// 'SETTING_...' defines for available setting ID's.
|
||||||
//
|
//
|
||||||
// \return the setting value.
|
// \return the setting value.
|
||||||
TSoundTouchGetSetting = function (Handle: TSoundTouchHandle;
|
TSoundTouchGetSetting = function (Handle: TSoundTouchHandle;
|
||||||
settingId: Integer //< Setting ID number, see SETTING_... defines.
|
SettingId: Integer //< Setting ID number, see SETTING_... defines.
|
||||||
): Integer; stdcall;
|
): Integer; cdecl;
|
||||||
|
|
||||||
|
|
||||||
// Returns number of samples currently unprocessed.
|
// Returns number of samples currently unprocessed.
|
||||||
TSoundTouchNumUnprocessedSamples = function (Handle: TSoundTouchHandle): Cardinal; stdcall;
|
TSoundTouchNumUnprocessedSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;
|
||||||
|
|
||||||
// Adjusts book-keeping so that given number of samples are removed from beginning of the
|
/// 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; stdcall;
|
): 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; stdcall;
|
TSoundTouchNumSamples = function (Handle: TSoundTouchHandle): Cardinal; cdecl;
|
||||||
|
|
||||||
// Returns nonzero if there aren't any samples available for outputting.
|
// Returns nonzero if there aren't any samples available for outputting.
|
||||||
TSoundTouchIsEmpty = function (Handle: TSoundTouchHandle): Integer; stdcall;
|
TSoundTouchIsEmpty = function (Handle: TSoundTouchHandle): Integer; cdecl;
|
||||||
|
|
||||||
var
|
var
|
||||||
SoundTouchCreateInstance : TSoundTouchCreateInstance;
|
SoundTouchCreateInstance : TSoundTouchCreateInstance;
|
||||||
SoundTouchDestroyInstance : TSoundTouchDestroyInstance;
|
SoundTouchDestroyInstance : TSoundTouchDestroyInstance;
|
||||||
SoundTouchGetVersionString : TSoundTouchGetVersionString;
|
SoundTouchGetVersionString : TSoundTouchGetVersionString;
|
||||||
|
SoundTouchGetVersionString2 : TSoundTouchGetVersionString2;
|
||||||
SoundTouchGetVersionId : TSoundTouchGetVersionId;
|
SoundTouchGetVersionId : TSoundTouchGetVersionId;
|
||||||
SoundTouchSetRate : TSoundTouchSetRate;
|
SoundTouchSetRate : TSoundTouchSetRate;
|
||||||
SoundTouchSetTempo : TSoundTouchSetTempo;
|
SoundTouchSetTempo : TSoundTouchSetTempo;
|
||||||
@ -164,11 +172,13 @@ var
|
|||||||
SoundTouchSetSampleRate : TSoundTouchSetSampleRate;
|
SoundTouchSetSampleRate : TSoundTouchSetSampleRate;
|
||||||
SoundTouchFlush : TSoundTouchFlush;
|
SoundTouchFlush : TSoundTouchFlush;
|
||||||
SoundTouchPutSamples : TSoundTouchPutSamples;
|
SoundTouchPutSamples : TSoundTouchPutSamples;
|
||||||
|
SoundTouchPutSamplesI16 : TSoundTouchPutSamplesI16;
|
||||||
SoundTouchClear : TSoundTouchClear;
|
SoundTouchClear : TSoundTouchClear;
|
||||||
SoundTouchSetSetting : TSoundTouchSetSetting;
|
SoundTouchSetSetting : TSoundTouchSetSetting;
|
||||||
SoundTouchGetSetting : TSoundTouchGetSetting;
|
SoundTouchGetSetting : TSoundTouchGetSetting;
|
||||||
SoundTouchNumUnprocessedSamples : TSoundTouchNumUnprocessedSamples;
|
SoundTouchNumUnprocessedSamples : TSoundTouchNumUnprocessedSamples;
|
||||||
SoundTouchReceiveSamples : TSoundTouchReceiveSamples;
|
SoundTouchReceiveSamples : TSoundTouchReceiveSamples;
|
||||||
|
SoundTouchReceiveSamplesI16 : TSoundTouchReceiveSamplesI16;
|
||||||
SoundTouchNumSamples : TSoundTouchNumSamples;
|
SoundTouchNumSamples : TSoundTouchNumSamples;
|
||||||
SoundTouchIsEmpty : TSoundTouchIsEmpty;
|
SoundTouchIsEmpty : TSoundTouchIsEmpty;
|
||||||
|
|
||||||
@ -210,10 +220,10 @@ type
|
|||||||
procedure Clear; virtual;
|
procedure Clear; virtual;
|
||||||
|
|
||||||
procedure PutSamples(const Samples: PSingle; const NumSamples: Cardinal);
|
procedure PutSamples(const Samples: PSingle; const NumSamples: Cardinal);
|
||||||
function ReceiveSamples(const outBuffer: PSingle; const maxSamples: Integer): Cardinal;
|
function ReceiveSamples(const OutBuffer: PSingle; const MaxSamples: Integer): Cardinal;
|
||||||
|
|
||||||
function SetSetting(const SettingId: Integer; const Value: Integer): Boolean;
|
function SetSetting(const SettingId: Integer; const Value: Integer): Boolean;
|
||||||
function GetSetting(const settingId: Integer): Integer;
|
function GetSetting(const SettingId: Integer): Integer;
|
||||||
|
|
||||||
property VersionString: string read GetVersionString;
|
property VersionString: string read GetVersionString;
|
||||||
property VersionID: Cardinal read GetVersionId;
|
property VersionID: Cardinal read GetVersionId;
|
||||||
@ -231,17 +241,17 @@ type
|
|||||||
property IsEmpty: Integer read GetIsEmpty;
|
property IsEmpty: Integer read GetIsEmpty;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
implementation
|
// list of exported functions and procedures
|
||||||
|
function IsSoundTouchLoaded: Boolean;
|
||||||
|
|
||||||
uses
|
implementation
|
||||||
SysUtils;
|
|
||||||
|
|
||||||
{ TSoundTouch }
|
{ TSoundTouch }
|
||||||
|
|
||||||
constructor TSoundTouch.Create;
|
constructor TSoundTouch.Create;
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
FHandle := SoundTouchCreateInstance;
|
FHandle := SoundTouchCreateInstance();
|
||||||
FRate := 1;
|
FRate := 1;
|
||||||
FTempo := 1;
|
FTempo := 1;
|
||||||
FPitch := 1;
|
FPitch := 1;
|
||||||
@ -299,12 +309,12 @@ end;
|
|||||||
|
|
||||||
class function TSoundTouch.GetVersionId: Cardinal;
|
class function TSoundTouch.GetVersionId: Cardinal;
|
||||||
begin
|
begin
|
||||||
result := SoundTouchGetVersionId;
|
result := SoundTouchGetVersionId();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class function TSoundTouch.GetVersionString: string;
|
class function TSoundTouch.GetVersionString: string;
|
||||||
begin
|
begin
|
||||||
result := StrPas(SoundTouchGetVersionString);
|
result := StrPas(SoundTouchGetVersionString());
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSoundTouch.SetChannels(const Value: Cardinal);
|
procedure TSoundTouch.SetChannels(const Value: Cardinal);
|
||||||
@ -347,10 +357,10 @@ begin
|
|||||||
SoundTouchSetRate(FHandle, FRate);
|
SoundTouchSetRate(FHandle, FRate);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSoundTouch.ReceiveSamples(const outBuffer: PSingle;
|
function TSoundTouch.ReceiveSamples(const OutBuffer: PSingle;
|
||||||
const maxSamples: Integer): Cardinal;
|
const MaxSamples: Integer): Cardinal;
|
||||||
begin
|
begin
|
||||||
result := SoundTouchReceiveSamples(FHandle, outBuffer, maxSamples);
|
result := SoundTouchReceiveSamples(FHandle, OutBuffer, MaxSamples);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TSoundTouch.SetPitchChange(const Value: Single);
|
procedure TSoundTouch.SetPitchChange(const Value: Single);
|
||||||
@ -418,36 +428,55 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
var
|
var
|
||||||
SoundTouchLibHandle: HINST;
|
SoundTouchLibHandle: THandle;
|
||||||
SoundTouchDLL: PAnsiChar = 'SoundTouch.DLL';
|
SoundTouchDLLFile: AnsiString = 'libSoundTouchDll.so';
|
||||||
|
//SoundTouchDLLFile: AnsiString = 'SoundTouch.dll';
|
||||||
|
|
||||||
|
// bpm detect functions. untested -- if these don't work then remove:
|
||||||
|
bpm_createInstance: function(chan: int32; sampleRate : int32): THandle; cdecl;
|
||||||
|
bpm_destroyInstance: procedure(h: THandle); cdecl;
|
||||||
|
bpm_getBpm: function(h: THandle): Single; cdecl;
|
||||||
|
bpm_putSamples: procedure(h: THandle; const samples: PSingle; numSamples: cardinal); cdecl;
|
||||||
|
|
||||||
procedure InitDLL;
|
procedure InitDLL;
|
||||||
begin
|
begin
|
||||||
SoundTouchLibHandle := LoadLibrary(SoundTouchDLL);
|
{$ifdef mswindows} // Windows
|
||||||
|
SoundTouchLibHandle := LoadLibrary('.\SoundTouchDll.dll');
|
||||||
|
{$else} // Unix
|
||||||
|
SoundTouchLibHandle := LoadLibrary('./libSoundTouchDll.so');
|
||||||
|
{$endif}
|
||||||
if SoundTouchLibHandle <> 0 then
|
if SoundTouchLibHandle <> 0 then
|
||||||
try
|
try
|
||||||
SoundTouchCreateInstance := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 2)); //'soundtouch_createInstance');
|
Pointer(SoundTouchCreateInstance) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_createInstance');
|
||||||
SoundTouchDestroyInstance := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 3)); //'soundtouch_destroyInstance');
|
Pointer(SoundTouchDestroyInstance) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_destroyInstance');
|
||||||
SoundTouchGetVersionString := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 7)); //'soundtouch_getVersionString');
|
Pointer(SoundTouchGetVersionString) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionString');
|
||||||
SoundTouchGetVersionId := GetProcAddress(SoundTouchLibHandle, PAnsiChar( 6)); //'soundtouch_getVersionId');
|
Pointer(SoundTouchGetVersionString2) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionString2');
|
||||||
SoundTouchSetRate := GetProcAddress(SoundTouchLibHandle, PAnsiChar(17)); //'soundtouch_setRate');
|
Pointer(SoundTouchGetVersionId) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_getVersionId');
|
||||||
SoundTouchSetTempo := GetProcAddress(SoundTouchLibHandle, PAnsiChar(21)); //'soundtouch_setTempo');
|
Pointer(SoundTouchSetRate) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setRate');
|
||||||
SoundTouchSetRateChange := GetProcAddress(SoundTouchLibHandle, PAnsiChar(18)); //'soundtouch_setRateChange');
|
Pointer(SoundTouchSetTempo) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setTempo');
|
||||||
SoundTouchSetTempoChange := GetProcAddress(SoundTouchLibHandle, PAnsiChar(22)); //'soundtouch_setTempoChange');
|
Pointer(SoundTouchSetRateChange) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setRateChange');
|
||||||
SoundTouchSetPitch := GetProcAddress(SoundTouchLibHandle, PAnsiChar(14)); //'soundtouch_setPitch');
|
Pointer(SoundTouchSetTempoChange) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setTempoChange');
|
||||||
SoundTouchSetPitchOctaves := GetProcAddress(SoundTouchLibHandle, PAnsiChar(15)); //'soundtouch_setPitchOctaves');
|
Pointer(SoundTouchSetPitch) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitch');
|
||||||
SoundTouchSetPitchSemiTones := GetProcAddress(SoundTouchLibHandle, PAnsiChar(16)); //'soundtouch_setPitchSemiTones');
|
Pointer(SoundTouchSetPitchOctaves) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitchOctaves');
|
||||||
SoundTouchSetChannels := GetProcAddress(SoundTouchLibHandle, PAnsiChar(13)); //'soundtouch_setChannels');
|
Pointer(SoundTouchSetPitchSemiTones) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setPitchSemiTones');
|
||||||
SoundTouchSetSampleRate := GetProcAddress(SoundTouchLibHandle, PAnsiChar(19)); //'soundtouch_setSampleRate');
|
Pointer(SoundTouchSetChannels) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setChannels');
|
||||||
SoundTouchFlush := GetProcAddress(SoundTouchLibHandle, PAnsiChar(4)); //'soundtouch_flush');
|
Pointer(SoundTouchSetSampleRate) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setSampleRate');
|
||||||
SoundTouchPutSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(11)); //'soundtouch_putSamples');
|
Pointer(SoundTouchFlush) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_flush');
|
||||||
SoundTouchClear := GetProcAddress(SoundTouchLibHandle, PAnsiChar(1)); //'soundtouch_clear');
|
Pointer(SoundTouchPutSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_putSamples');
|
||||||
SoundTouchSetSetting := GetProcAddress(SoundTouchLibHandle, PAnsiChar(20)); //'soundtouch_SetSetting');
|
Pointer(SoundTouchPutSamplesI16) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_putSamples_i16');
|
||||||
SoundTouchGetSetting := GetProcAddress(SoundTouchLibHandle, PAnsiChar(5)); //'soundtouch_setSetting');
|
Pointer(SoundTouchClear) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_clear');
|
||||||
SoundTouchNumUnprocessedSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(10)); //'soundtouch_numUnprocessedSamples');
|
Pointer(SoundTouchSetSetting) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_SetSetting');
|
||||||
SoundTouchReceiveSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(12)); //'soundtouch_receiveSamples');
|
Pointer(SoundTouchGetSetting) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_setSetting');
|
||||||
SoundTouchNumSamples := GetProcAddress(SoundTouchLibHandle, PAnsiChar(9)); //'soundtouch_numSamples');
|
Pointer(SoundTouchNumUnprocessedSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_numUnprocessedSamples');
|
||||||
SoundTouchIsEmpty := GetProcAddress(SoundTouchLibHandle, PAnsiChar(8)); //'soundtouch_isEmpty');
|
Pointer(SoundTouchReceiveSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_receiveSamples');
|
||||||
|
Pointer(SoundTouchReceiveSamplesI16) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_receiveSamples_i16');
|
||||||
|
Pointer(SoundTouchNumSamples) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_numSamples');
|
||||||
|
Pointer(SoundTouchIsEmpty) := GetProcAddress(SoundTouchLibHandle, 'soundtouch_isEmpty');
|
||||||
|
|
||||||
|
Pointer(bpm_createInstance) :=GetProcAddress(SoundTouchLibHandle, 'bpm_createInstance');
|
||||||
|
Pointer(bpm_destroyInstance) :=GetProcAddress(SoundTouchLibHandle, 'bpm_destroyInstance');
|
||||||
|
Pointer(bpm_getBpm) :=GetProcAddress(SoundTouchLibHandle, 'bpm_getBpm');
|
||||||
|
Pointer(bpm_putSamples) :=GetProcAddress(SoundTouchLibHandle, 'bpm_putSamples');
|
||||||
|
|
||||||
except
|
except
|
||||||
FreeLibrary(SoundTouchLibHandle);
|
FreeLibrary(SoundTouchLibHandle);
|
||||||
@ -460,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;
|
||||||
|
|
||||||
1
source/SoundTouchDLL/LazarusTest/libSoundTouchDll.so
Symbolic link
1
source/SoundTouchDLL/LazarusTest/libSoundTouchDll.so
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../.libs/libSoundTouchDll.so
|
||||||
36
source/SoundTouchDLL/LazarusTest/main.lfm
Normal file
36
source/SoundTouchDLL/LazarusTest/main.lfm
Normal 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
|
||||||
49
source/SoundTouchDLL/LazarusTest/main.pas
Normal file
49
source/SoundTouchDLL/LazarusTest/main.pas
Normal 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.
|
||||||
|
|
||||||
BIN
source/SoundTouchDLL/LazarusTest/soundtouchtest.ico
Normal file
BIN
source/SoundTouchDLL/LazarusTest/soundtouchtest.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
78
source/SoundTouchDLL/LazarusTest/soundtouchtest.lpi
Normal file
78
source/SoundTouchDLL/LazarusTest/soundtouchtest.lpi
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<CONFIG>
|
||||||
|
<ProjectOptions>
|
||||||
|
<Version Value="12"/>
|
||||||
|
<General>
|
||||||
|
<SessionStorage Value="InProjectDir"/>
|
||||||
|
<Title Value="soundtouchtest"/>
|
||||||
|
<Scaled Value="True"/>
|
||||||
|
<ResourceType Value="res"/>
|
||||||
|
<UseXPManifest Value="True"/>
|
||||||
|
<XPManifest>
|
||||||
|
<DpiAware Value="True"/>
|
||||||
|
</XPManifest>
|
||||||
|
<Icon Value="0"/>
|
||||||
|
</General>
|
||||||
|
<BuildModes>
|
||||||
|
<Item Name="Default" Default="True"/>
|
||||||
|
</BuildModes>
|
||||||
|
<PublishOptions>
|
||||||
|
<Version Value="2"/>
|
||||||
|
<UseFileFilters Value="True"/>
|
||||||
|
</PublishOptions>
|
||||||
|
<RunParams>
|
||||||
|
<FormatVersion Value="2"/>
|
||||||
|
</RunParams>
|
||||||
|
<RequiredPackages>
|
||||||
|
<Item>
|
||||||
|
<PackageName Value="LCL"/>
|
||||||
|
</Item>
|
||||||
|
</RequiredPackages>
|
||||||
|
<Units>
|
||||||
|
<Unit>
|
||||||
|
<Filename Value="soundtouchtest.lpr"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
</Unit>
|
||||||
|
<Unit>
|
||||||
|
<Filename Value="main.pas"/>
|
||||||
|
<IsPartOfProject Value="True"/>
|
||||||
|
<ComponentName Value="Form1"/>
|
||||||
|
<HasResources Value="True"/>
|
||||||
|
<ResourceBaseClass Value="Form"/>
|
||||||
|
</Unit>
|
||||||
|
</Units>
|
||||||
|
</ProjectOptions>
|
||||||
|
<CompilerOptions>
|
||||||
|
<Version Value="11"/>
|
||||||
|
<Target>
|
||||||
|
<Filename Value="soundtouchtest"/>
|
||||||
|
</Target>
|
||||||
|
<SearchPaths>
|
||||||
|
<IncludeFiles Value="$(ProjOutDir)"/>
|
||||||
|
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
|
||||||
|
</SearchPaths>
|
||||||
|
<Linking>
|
||||||
|
<Debugging>
|
||||||
|
<DebugInfoType Value="dsDwarf3"/>
|
||||||
|
</Debugging>
|
||||||
|
<Options>
|
||||||
|
<Win32>
|
||||||
|
<GraphicApplication Value="True"/>
|
||||||
|
</Win32>
|
||||||
|
</Options>
|
||||||
|
</Linking>
|
||||||
|
</CompilerOptions>
|
||||||
|
<Debugging>
|
||||||
|
<Exceptions>
|
||||||
|
<Item>
|
||||||
|
<Name Value="EAbort"/>
|
||||||
|
</Item>
|
||||||
|
<Item>
|
||||||
|
<Name Value="ECodetoolError"/>
|
||||||
|
</Item>
|
||||||
|
<Item>
|
||||||
|
<Name Value="EFOpenError"/>
|
||||||
|
</Item>
|
||||||
|
</Exceptions>
|
||||||
|
</Debugging>
|
||||||
|
</CONFIG>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user