Merge from branch r3

This commit is contained in:
Chris Cannam
2022-07-01 17:11:29 +01:00
119 changed files with 10471 additions and 3450 deletions

View File

@@ -16,7 +16,11 @@ build_script:
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
- meson build "-Dextra_include_dirs=C:\Program Files\libsndfile\include" "-Dextra_lib_dirs=C:\Program Files\libsndfile\lib"
- ninja -C build
- meson test -C build
# Test the VC++ static library build, which is separate
- msbuild otherbuilds\rubberband-library.vcxproj /t:Build /p:Configuration=Release
# And test the .NET FFI interface build, which is again separate
# Test the .NET FFI interface build, which is again separate
- msbuild dotnet\rubberband.sln /t:Restore;Build
# And test the single-file build
- cl main\main.cpp single\RubberBandSingle.cpp .\src\ext\getopt\getopt.c src\ext\getopt\getopt_long.c "C:\Program Files\libsndfile\lib\sndfile.lib" /O2 /std:c++14 /D_USE_MATH_DEFINES /DNOMINMAX /EHs /I"C:\Program Files\libsndfile\include" /link /out:test_single.exe

View File

@@ -7,6 +7,7 @@ packages:
- ladspa-sdk
- lv2-dev
- vamp-plugin-sdk
- libboost-test-dev
- meson
- ninja-build
sources:
@@ -15,9 +16,27 @@ tasks:
- setup: |
cd rubberband
meson build
meson build_speex -Dresampler=speex
meson build_libsamplerate -Dresampler=libsamplerate
meson build_fftw -Dfft=fftw
meson build_kissfft -Dfft=kissfft
- build: |
cd rubberband
ninja -C build
meson test -C build
build/rubberband -V
ninja -C build_speex
meson test -C build_speex
build_speex/rubberband -V
ninja -C build_libsamplerate
meson test -C build_libsamplerate
build_libsamplerate/rubberband -V
ninja -C build_fftw
meson test -C build_fftw
build_fftw/rubberband -V
ninja -C build_kissfft
meson test -C build_kissfft
build_kissfft/rubberband -V
./otherbuilds/check.sh
triggers:
- action: email

View File

@@ -21,6 +21,8 @@ jobs:
run: ninja -C build_macos
- name: make ios
run: ninja -C build_ios
- name: unit test macos
run: meson test -C build_macos
- name: check otherbuilds
run: otherbuilds/check.sh

View File

@@ -26,3 +26,7 @@ build
build_*
build-*
UpgradeLog*
out-*/
playlist-out/*
formant-out-*/
out*.wav

View File

@@ -16,3 +16,10 @@ fa6a54be7e6bf0c5adffd19ccec622481a8140a5 v1.8.2
4a6f7059b6b77fb34a9f29037f3ece47755e99a0 v2.0.0
190ba65557c06823ef576d5d62b99e2d27771759 v2.0.1
4e2177c66756fecacccf211df5f8a97d01070ef0 v2.0.2
590cb5c496f868d9806db5205bfe22ddeb7f5767 v3.0.0-beta1
acc04c20175ebc3f8138c4e14c9108cb33024fb1 v3.0.0-beta2
acc04c20175ebc3f8138c4e14c9108cb33024fb1 v3.0.0-beta2
ed9acf241b1076e84ba0b41dc9d8edd904f69f25 v3.0.0-beta2
58b588a580a126adb16de96f8eade96111758085 v3.0.0-beta3
58b588a580a126adb16de96f8eade96111758085 v3.0.0-beta3
78a701fb6daa670fc49648816f040a70689c86a7 v3.0.0-beta3

View File

@@ -1,4 +1,27 @@
Changes in Rubber Band v3.0.0
* Introduce a new processing engine, the R3 (Finer) engine, which
typically produces higher-quality output than the existing R2
engine but at significantly higher CPU cost. The R2 engine is
still the default, and R3 can be selected using the new
OptionEngineFiner option on construction. See the documentation
for more details.
* Add ability to provide a custom set of log callbacks, so that
debug and warning logs can be routed to the application's log
stream and/or handled in a realtime-safe way
* Add option to shift formant independently of pitch (R3 engine
only)
The library is both binary and API compatible all the way back to
version 1.2 for forward compatibility, but not backward compatibility,
as several new functions and enum values have been added. Code
written to use 3.0 is not necessarily compatible with 2.x or 1.x, but
code written to use any earlier version can update to 3.0 without
modification (and it will continue to use the same processing engine
if the calling code is unchanged).
Changes in Rubber Band v2.0.2
* Fix a crash in certain configurations when using mid-side

524
COMPILING.md Normal file
View File

@@ -0,0 +1,524 @@
# Compiling Rubber Band Library
## Contents of this file
1. General instructions
2. Building on Linux
3. Building on macOS
4. Building for iOS
5. Building on Windows
6. Building for Android and Java integration
7. FFT and resampler selection
8. Other supported #defines
9. Copyright notes for bundled libraries
## 1. General instructions
**Full configurable build.** The primary supported build system for
Rubber Band on all platforms is Meson (https://mesonbuild.com). The
Meson build system can be used to build all targets (static and
dynamic library, command-line utility, and plugins) and to
cross-compile. See below for details.
**Single-file build.** If you want to include Rubber Band in a C++
project and would prefer not to build it as a separate library, there
is a single `.cpp` file at `single/RubberBandSingle.cpp` which can be
added to your project as-is. It produces a single compilation-unit
build using the built-in FFT and resampler implementations with no
further library dependencies. See the comments at the top of that file
for more information.
**Other build options.** If you only need a static library and don't
wish to use Meson, some alternative build files (Makefiles and Visual
C++ projects) are included in the `otherbuilds` directory. See the
platform-specific build sections below for more details.
To build with Meson, ensure Meson and Ninja are installed and run:
```
$ meson build && ninja -C build
```
This checks for necessary dependencies, reports what it finds, and if
all is well, builds the code into a subdirectory called `build`. It
will build everything it can find the requisite dependencies for:
static and dynamic libraries, LADSPA, LV2, and Vamp plugins, and
command-line utility.
Some configuration options are provided, described in the
`meson_options.txt` file. To set one of these, add a `-D` option to
Meson:
```
$ meson build -Dipp_path=/opt/intel/ipp
```
The options are documented in the library- and platform-specific
sections below.
Rubber Band Library is written entirely in C++ and requires a C++11
compiler. It is unlikely to make any difference (performance or
otherwise) which C++ standard you compile with, as long as it's no
older than C++11.
If you are building this software using either of the Speex or KissFFT
library options, please be sure to review the terms for those
libraries in `src/speex/COPYING` and `src/kissfft/COPYING` as
applicable.
## 2. Building on Linux
Optionally, if you want the command-line tool and plugins to be built,
first install libsndfile and the LADSPA, LV2, and Vamp plugin headers
so they can be found using `pkg-config`. Then
```
$ meson build && ninja -C build
```
See "FFT and resampler selection" below for further build options.
Alternatively, if you only need the static library and prefer a
Makefile, try
```
$ make -f otherbuilds/Makefile.linux
```
## 3. Building on macOS
Ensure the Xcode command-line tools are installed, and if you want the
command-line tool to be built, also install libsndfile.
To build for the default architecture:
```
$ meson build && ninja -C build
```
Which architecture is the default may depend on the version of Meson
and/or the current shell. To force a particular architecture you can
use a Meson cross-file, as follows.
To build for Apple Silicon (arm64):
```
$ meson build --cross-file cross/macos-arm64.txt && ninja -C build
```
To build for Intel (x86_64):
```
$ meson build --cross-file cross/macos-x86_64.txt && ninja -C build
```
You can build a universal binary library for both architectures like
this:
```
$ meson build --cross-file cross/macos-universal.txt && ninja -C build
```
Note that the universal cross file also sets the minimum OS version to
the earliest supported macOS versions for both architectures. (In
practice, compatibility will also depend on how the dependent
libraries have been compiled.) You can edit this in the
`cross/macos-universal.txt` file if you want a specific target.
See "FFT and resampler selection" below for further build options.
Note that you cannot legally distribute applications using Rubber Band
in the Mac App Store, unless you have first obtained a commercial
licence for Rubber Band Library. GPL code is not permitted in the app
store. See https://breakfastquay.com/technology/license.html for
commercial terms.
## 4. Building for iOS
Ensure the Xcode command-line tools are installed, and
```
$ meson build_ios --cross-file cross/ios.txt && ninja -C build_ios
```
The output files will be found in the `build_ios` directory.
To build for the simulator,
```
$ meson build_sim --cross-file cross/ios-simulator.txt && ninja -C build_sim
```
The output files will be found in the `build_sim` directory.
See "FFT and resampler selection" below for further build options.
Note that you cannot legally distribute applications using Rubber Band
in the iOS App Store, unless you have a first obtained a commercial
licence for Rubber Band Library. GPL code is not permitted in the app
store. See https://breakfastquay.com/technology/license.html for
commercial terms.
## 5. Building on Windows
If you only need to build the static library for integration into your
project, and you prefer a Visual Studio project file, you can find a
simple one in `otherbuilds\rubberband-library.vcxproj`.
The rest of this section describes the "full" build system, which uses
Meson just as on the other platforms. So to build this way, start by
ensuring Meson and Ninja are installed and available. Then, in a
terminal window with the compiler tools available in the path (e.g. a
Visual Studio command-line prompt for the relevant build architecture)
run
```
> meson build
> ninja -C build
```
The output files will be found in the `build` directory.
The Rubber Band code is compatible with both the traditional Visual
C++ compiler (`cl`) and the Clang front-end (`clang`), and the build
system will use whichever appears (first) in your path.
To build against a specific Visual C++ runtime, use the built-in Meson
option `b_vscrt`:
```
> meson build -Db_vscrt=mt
```
See "FFT and resampler selection" below for further build options.
## 6. Building for Android and Java integration
Currently only a very old Android NDK build file is provided, as
`otherbuilds/Android.mk`. This includes compile definitions for a
shared library built for ARM architectures which can be loaded from a
Java application using the Java native interface (i.e. the Android
NDK).
The Java side of the interface can be found in
`com/breakfastquay/rubberband/RubberBandStretcher.java`.
See
https://hg.sr.ht/~breakfastquay/rubberband-android-simple-sample
for a very trivial example of integration with Android Java code.
The supplied `.mk` file uses KissFFT and the Speex resampler.
## 7. FFT and resampler selection
Rubber Band requires the selection of library code for FFT calculation
and resampling. Several libraries are supported. The selection is
controlled (in Meson) using `-D` options and (in the code itself)
using preprocessor flags set by the build system. These options and
flags are detailed in the tables below.
At least one resampler implementation and one FFT implementation must
be enabled. It is technically possible to enable more than one, but
it's confusing and not often useful.
If you are building this software using the bundled Speex or KissFFT
library code, please be sure to review the terms for those libraries
in `src/speex/COPYING` and `src/kissfft/COPYING` as applicable.
If you are proposing to package Rubber Band for a Linux distribution,
please select either the built-in FFT or FFTW, and either the built-in
resampler or libsamplerate.
### FFT libraries supported
```
Library Build option CPP define Notes
---- ------------ ---------- -----
Built-in -Dfft=builtin -DUSE_BUILTIN_FFT
Default except on macOS/iOS.
Can be distributed with either
the Rubber Band GPL or
commercial licence.
Accelerate -Dfft=vdsp -DHAVE_VDSP Default on macOS/iOS.
Best option on these platforms.
FFTW3 -Dfft=fftw -DHAVE_FFTW3 GPL.
A bit faster than built-in,
a bit slower than Accelerate.
KissFFT -Dfft=kissfft -DHAVE_KISSFFT
Single precision.
Only indicated for use with
single-precision sample type
(see below).
Bundled, can be distributed with
either the Rubber Band GPL or
commercial licence.
Intel IPP -Dfft=ipp -DHAVE_IPP Proprietary, can only be used with
Rubber Band commercial licence.
```
### Resampler libraries supported
```
Library Build option CPP define Notes
---- ------------ ---------- -----
Built-in -Dfft=builtin -DUSE_BQRESAMPLER
Default.
Can be distributed with either
the Rubber Band GPL or
commercial licence. Intended to
give best quality for time-varying
pitch shifts in real-time mode.
Newer than, and not as well-tested
as, libsamplerate.
libsamplerate -DHAVE_LIBSAMPLERATE
-Dresampler=libsamplerate Good choice in most cases.
Speex -DUSE_SPEEX
-Dresampler=speex Can be distributed with
either the Rubber Band GPL or
commercial licence.
```
## 8. Other supported #defines
Other known preprocessor symbols are as follows. (Usually the supplied
build files will handle these for you.)
-DLACK_BAD_ALLOC
Define on systems lacking std::bad_alloc in the C++ library.
-DLACK_POSIX_MEMALIGN
Define on systems lacking posix_memalign.
-DUSE_OWN_ALIGNED_MALLOC
Define on systems lacking any aligned malloc implementation.
-DLACK_SINCOS
Define on systems lacking sincos().
-DNO_EXCEPTIONS
Build without use of C++ exceptions.
-DNO_THREADING
Build without any multithread support.
-DUSE_PTHREADS
Use the pthreads library (required unless NO_THREADING or on Windows)
-DPROCESS_SAMPLE_TYPE=float
Select single precision for internal calculations. The default is
double precision. Consider in conjunction with single-precision
KissFFT for mobile architectures with slower double-precision
support.
-DUSE_POMMIER_MATHFUN
Select the Julien Pommier implementations of trig functions for ARM
NEON or x86 SSE architectures. These are usually faster but may be
of lower precision than system implementations. Consider using this
for 32-bit mobile architectures.
## 9. Copyright notes for bundled libraries
### 5a. Speex
```
[files in src/speex]
Copyright 2002-2007 Xiph.org Foundation
Copyright 2002-2007 Jean-Marc Valin
Copyright 2005-2007 Analog Devices Inc.
Copyright 2005-2007 Commonwealth Scientific and Industrial Research
Organisation (CSIRO)
Copyright 1993, 2002, 2006 David Rowe
Copyright 2003 EpicGames
Copyright 1992-1994 Jutta Degener, Carsten Bormann
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
### 5b. KissFFT
```
[files in src/kissfft]
Copyright (c) 2003-2004 Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the author nor the names of any contributors may be used
to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
### 5c. Pommier math functions
```
[files in src/pommier]
Copyright (C) 2011 Julien Pommier
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
```
### 5d. float_cast
```
[files in src/float_cast]
Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
Permission to use, copy, modify, distribute, and sell this file for any
purpose is hereby granted without fee, provided that the above copyright
and this permission notice appear in all copies. No representations are
made about the suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
```
### 5e. getopt
```
[files in src/getopt, used by command-line tool on some platforms]
Copyright (c) 2000 The NetBSD Foundation, Inc.
All rights reserved.
This code is derived from software contributed to The NetBSD Foundation
by Dieter Baron and Thomas Klausner.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the NetBSD
Foundation, Inc. and its contributors.
4. Neither the name of The NetBSD Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
```
### 5f. rubberband-sharp
```
[files in rubberband-dll and rubberband-sharp]
Copyright 2018-2019 Jonathan Gilbert
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Jonathan Gilbert
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
```

View File

@@ -31,7 +31,7 @@ PROJECT_NAME = "Rubber Band Library"
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 2.0.2
PROJECT_NUMBER = 3.0.0
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.

569
README.md
View File

@@ -53,7 +53,8 @@ responsibility to ensure that you redistribute these only in
accordance with their own licence terms, regardless of the conditions
under which you are redistributing the Rubber Band code itself. The
licences for some relevant library code are as follows, to the best of
our knowledge. See also the end of this README for detailed terms.
our knowledge. See also the file [COMPILING.md](COMPILING.md) for more
details.
* FFTW3 - GPL; proprietary licence needed for redistribution
* Intel IPP - Proprietary; licence needed for redistribution
@@ -63,20 +64,17 @@ our knowledge. See also the end of this README for detailed terms.
* Pommier math functions - BSD-like
## Compiling Rubber Band Library
Please refer to the file [COMPILING.md](COMPILING.md) for details of
how to configure and build the library.
## Contents of this README
1. Code components
2. Using the Rubber Band command-line tool
3. Using Rubber Band Library
4. Compiling Rubber Band:
a. Building on Linux
b. Building on macOS
c. Building for iOS
d. Building on Windows
e. Building for Android and Java integration
f. FFT and resampler selection
g. Other supported #defines
5. Copyright notes for bundled libraries
## 1. Code components
@@ -87,7 +85,8 @@ Rubber Band consists of:
be used by your applications. The headers for this are in the
`rubberband/` directory, and the source code is in `src/`.
The Rubber Band Library may also depend upon external resampler
and FFT code; see section 4 below for details.
and FFT code, if so configured; see section 7 of COMPILING.md for
details.
* The Rubber Band command-line tool. This is in `main/main.cpp`.
This program uses Rubber Band Library and also requires libsndfile
@@ -106,7 +105,7 @@ Rubber Band consists of:
## 2. Using the Rubber Band command-line tool
The Rubber Band command-line tool builds as `bin/rubberband`. The
The Rubber Band command-line tool builds as `build/rubberband`. The
basic incantation is
```
@@ -124,8 +123,25 @@ duration, shifts it up in pitch by a whole tone, and writes the output
to `output.wav`.
Several further options are available: run `rubberband -h` for help.
In particular, different types of music may benefit from different
"crispness" options (`-c` flag, with a numerical argument from 0 to 6).
The most important are the options `-2` and `-3`. These select between
two different processing engines, known as the R2 (Faster) engine and
the R3 (Finer) engine. The R3 engine produces higher-quality results
than R2 for most material, especially complex mixes, vocals and other
sounds that have soft onsets and smooth pitch changes, and music with
substantial bass content. However, it uses much more CPU than the R2
engine.
The R2 engine was the only method available in Rubber Band Library up
to versions 2.x, and for compatibility it remains the default (in the
case that neither `-2` nor `-3` is requested explicitly) whenever the
command-line tool is invoked as `rubberband`. The R3 engine is the
default if the tool is invoked as `rubberband-r3`.
Many further options are available, most of which only have an effect
when using the R2 engine. In particular, different types of music may
benefit from different "crispness" options (`-c` flag, with a
numerical argument from 0 to 6).
## 3. Using Rubber Band Library
@@ -150,520 +166,19 @@ provides a good example of how to use Rubber Band in offline mode; the
pitch shifter plugin (`ladspa-lv2/RubberBandPitchShifter.cpp`) may be
used as an example of Rubber Band in real-time mode.
IMPORTANT: Please ensure you have read and understood the licensing
terms for Rubber Band before using it in your application. This
library is provided under the GNU General Public License, which means
that any application that uses it must also be published under the GPL
or a compatible licence (i.e. with its full source code also available
for modification and redistribution) unless you have separately
acquired a commercial licence from the author.
**IMPORTANT:** Please ensure you have read and understood the
licensing terms for Rubber Band before using it in your application.
This library is provided under the GNU General Public License, which
means that any application that uses it must also be published under
the GPL or a compatible licence (i.e. with its full source code also
available for modification and redistribution) unless you have
separately acquired a commercial licence from the author.
## 4. Compiling Rubber Band Library
## 4. Further documentation
**Full configurable build.** The primary supported build system for
Rubber Band on all platforms is Meson (https://mesonbuild.com). The
Meson build system can be used to build all targets (static and
dynamic library, command-line utility, and plugins) and to
cross-compile. See below for details.
* The [API documentation](https://breakfastquay.com/rubberband/code-doc/index.html) is thorough and we encourage you to read it
* [Conceptual notes and examples](https://breakfastquay.com/rubberband/integration.html) for integration into an application
* [Help text](https://breakfastquay.com/rubberband/usage.txt) of the command-line application
* [Rubber Band Library home page](https://breakfastquay.com/rubberband/)
**Single-file build.** If you want to include Rubber Band in a C++
project and would prefer not to build it as a separate library, there
is a single `.cpp` file at `single/RubberBandSingle.cpp` which can be
added to your project as-is. It produces a single compilation-unit
build using the built-in FFT and resampler implementations with no
further library dependencies. See the comments at the top of that file
for more information.
**Other build options.** If you only need a static library and don't
wish to use Meson, some alternative build files (Makefiles and Visual
C++ projects) are included in the `otherbuilds` directory. See the
platform-specific build sections below for more details.
To build with Meson, ensure Meson and Ninja are installed and run:
```
$ meson build && ninja -C build
```
This checks for necessary dependencies, reports what it finds, and if
all is well, builds the code into a subdirectory called `build`. It
will build everything it can find the requisite dependencies for:
static and dynamic libraries, LADSPA, LV2, and Vamp plugins, and
command-line utility.
Some configuration options are provided, described in the
`meson_options.txt` file. To set one of these, add a `-D` option to
Meson:
```
$ meson build -Dipp_path=/opt/intel/ipp
```
The options are documented in the library- and platform-specific
sections below.
Rubber Band Library is written entirely in C++ and requires a C++11
compiler. It is unlikely to make any difference (performance or
otherwise) which C++ standard you compile with, as long as it's no
older than C++11.
If you are building this software using either of the Speex or KissFFT
library options, please be sure to review the terms for those
libraries in `src/speex/COPYING` and `src/kissfft/COPYING` as
applicable.
### 4a. Building on Linux
Optionally, if you want the command-line tool and plugins to be built,
first install libsndfile and the LADSPA, LV2, and Vamp plugin headers
so they can be found using `pkg-config`. Then
```
$ meson build && ninja -C build
```
See "FFT and resampler selection" below for further build options.
Alternatively, if you only need the static library and prefer a
Makefile, try
```
$ make -f otherbuilds/Makefile.linux
```
### 4b. Building on macOS
Ensure the Xcode command-line tools are installed, and if you want the
command-line tool to be built, also install libsndfile.
To build for the default architecture:
```
$ meson build && ninja -C build
```
Which architecture is the default may depend on the version of Meson
and/or the current shell. To force a particular architecture you can
use a Meson cross-file, as follows.
To build for Apple Silicon (arm64):
```
$ meson build --cross-file cross/macos-arm64.txt && ninja -C build
```
To build for Intel (x86_64):
```
$ meson build --cross-file cross/macos-x86_64.txt && ninja -C build
```
You can build a universal binary library for both architectures like
this:
```
$ meson build --cross-file cross/macos-universal.txt && ninja -C build
```
Note that the universal cross file also sets the minimum OS version to
the earliest supported macOS versions for both architectures. (In
practice, compatibility will also depend on how the dependent
libraries have been compiled.) You can edit this in the
`cross/macos-universal.txt` file if you want a specific target.
See "FFT and resampler selection" below for further build options.
Note that you cannot legally distribute applications using Rubber Band
in the Mac App Store, unless you have first obtained a commercial
licence for Rubber Band Library. GPL code is not permitted in the app
store. See https://breakfastquay.com/technology/license.html for
commercial terms.
### 4c. Building for iOS
Ensure the Xcode command-line tools are installed, and
```
$ meson build_ios --cross-file cross/ios.txt && ninja -C build_ios
```
The output files will be found in the `build_ios` directory.
To build for the simulator,
```
$ meson build_sim --cross-file cross/ios-simulator.txt && ninja -C build_sim
```
The output files will be found in the `build_sim` directory.
See "FFT and resampler selection" below for further build options.
Note that you cannot legally distribute applications using Rubber Band
in the iOS App Store, unless you have a first obtained a commercial
licence for Rubber Band Library. GPL code is not permitted in the app
store. See https://breakfastquay.com/technology/license.html for
commercial terms.
### 4d. Building on Windows
If you only need to build the static library for integration into your
project, and you prefer a Visual Studio project file, you can find a
simple one in `otherbuilds\rubberband-library.vcxproj`.
The rest of this section describes the "full" build system, which uses
Meson just as on the other platforms. So to build this way, start by
ensuring Meson and Ninja are installed and available. Then, in a
terminal window with the compiler tools available in the path (e.g. a
Visual Studio command-line prompt for the relevant build architecture)
run
```
> meson build
> ninja -C build
```
The output files will be found in the `build` directory.
The Rubber Band code is compatible with both the traditional Visual
C++ compiler (`cl`) and the Clang front-end (`clang`), and the build
system will use whichever appears (first) in your path.
To build against a specific Visual C++ runtime, use the built-in Meson
option `b_vscrt`:
```
> meson build -Db_vscrt=mt
```
See "FFT and resampler selection" below for further build options.
### 4e. Building for Android and Java integration
Currently only a very old Android NDK build file is provided, as
`otherbuilds/Android.mk`. This includes compile definitions for a
shared library built for ARM architectures which can be loaded from a
Java application using the Java native interface (i.e. the Android
NDK).
The Java side of the interface can be found in
`com/breakfastquay/rubberband/RubberBandStretcher.java`.
See
https://hg.sr.ht/~breakfastquay/rubberband-android-simple-sample
for a very trivial example of integration with Android Java code.
The supplied `.mk` file uses KissFFT and the Speex resampler.
### 4f. FFT and resampler selection
Rubber Band requires the selection of library code for FFT calculation
and resampling. Several libraries are supported. The selection is
controlled (in Meson) using `-D` options and (in the code itself)
using preprocessor flags set by the build system. These options and
flags are detailed in the tables below.
At least one resampler implementation and one FFT implementation must
be enabled. It is technically possible to enable more than one, but
it's confusing and not often useful.
If you are building this software using the bundled Speex or KissFFT
library code, please be sure to review the terms for those libraries
in `src/speex/COPYING` and `src/kissfft/COPYING` as applicable.
If you are proposing to package Rubber Band for a Linux distribution,
please select either the built-in FFT or FFTW, and either the built-in
resampler or libsamplerate.
#### FFT libraries supported
```
Library Build option CPP define Notes
---- ------------ ---------- -----
Built-in -Dfft=builtin -DUSE_BUILTIN_FFT
Default except on macOS/iOS.
Can be distributed with either
the Rubber Band GPL or
commercial licence.
Accelerate -Dfft=vdsp -DHAVE_VDSP Default on macOS/iOS.
Best option on these platforms.
FFTW3 -Dfft=fftw -DHAVE_FFTW3 GPL.
A bit faster than built-in,
a bit slower than Accelerate.
KissFFT -Dfft=kissfft -DHAVE_KISSFFT
Single precision.
Only indicated for use with
single-precision sample type
(see below).
Bundled, can be distributed with
either the Rubber Band GPL or
commercial licence.
Intel IPP -Dfft=ipp -DHAVE_IPP Proprietary, can only be used with
Rubber Band commercial licence.
```
#### Resampler libraries supported
```
Library Build option CPP define Notes
---- ------------ ---------- -----
Built-in -Dfft=builtin -DUSE_BQRESAMPLER
Default.
Can be distributed with either
the Rubber Band GPL or
commercial licence. Intended to
give best quality for time-varying
pitch shifts in real-time mode.
Newer than, and not as well-tested
as, libsamplerate.
libsamplerate -DHAVE_LIBSAMPLERATE
-Dresampler=libsamplerate Good choice in most cases.
Speex -DUSE_SPEEX
-Dresampler=speex Can be distributed with
either the Rubber Band GPL or
commercial licence.
```
### 4g. Other supported #defines
Other known preprocessor symbols are as follows. (Usually the supplied
build files will handle these for you.)
-DLACK_BAD_ALLOC
Define on systems lacking std::bad_alloc in the C++ library.
-DLACK_POSIX_MEMALIGN
Define on systems lacking posix_memalign.
-DUSE_OWN_ALIGNED_MALLOC
Define on systems lacking any aligned malloc implementation.
-DLACK_SINCOS
Define on systems lacking sincos().
-DNO_EXCEPTIONS
Build without use of C++ exceptions.
-DNO_THREADING
Build without any multithread support.
-DUSE_PTHREADS
Use the pthreads library (required unless NO_THREADING or on Windows)
-DPROCESS_SAMPLE_TYPE=float
Select single precision for internal calculations. The default is
double precision. Consider in conjunction with single-precision
KissFFT for mobile architectures with slower double-precision
support.
-DUSE_POMMIER_MATHFUN
Select the Julien Pommier implementations of trig functions for ARM
NEON or x86 SSE architectures. These are usually faster but may be
of lower precision than system implementations. Consider using this
for 32-bit mobile architectures.
## 5. Copyright notes for bundled libraries
### 5a. Speex
```
[files in src/speex]
Copyright 2002-2007 Xiph.org Foundation
Copyright 2002-2007 Jean-Marc Valin
Copyright 2005-2007 Analog Devices Inc.
Copyright 2005-2007 Commonwealth Scientific and Industrial Research
Organisation (CSIRO)
Copyright 1993, 2002, 2006 David Rowe
Copyright 2003 EpicGames
Copyright 1992-1994 Jutta Degener, Carsten Bormann
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
### 5b. KissFFT
```
[files in src/kissfft]
Copyright (c) 2003-2004 Mark Borgerding
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the author nor the names of any contributors may be used
to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
### 5c. Pommier math functions
```
[files in src/pommier]
Copyright (C) 2011 Julien Pommier
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
```
### 5d. float_cast
```
[files in src/float_cast]
Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
Permission to use, copy, modify, distribute, and sell this file for any
purpose is hereby granted without fee, provided that the above copyright
and this permission notice appear in all copies. No representations are
made about the suitability of this software for any purpose. It is
provided "as is" without express or implied warranty.
```
### 5e. getopt
```
[files in src/getopt, used by command-line tool on some platforms]
Copyright (c) 2000 The NetBSD Foundation, Inc.
All rights reserved.
This code is derived from software contributed to The NetBSD Foundation
by Dieter Baron and Thomas Klausner.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the NetBSD
Foundation, Inc. and its contributors.
4. Neither the name of The NetBSD Foundation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
```
### 5f. rubberband-sharp
```
[files in rubberband-dll and rubberband-sharp]
Copyright 2018-2019 Jonathan Gilbert
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of Jonathan Gilbert
shall not be used in advertising or otherwise to promote the sale,
use or other dealings in this Software without prior written
authorization.
```

View File

@@ -77,7 +77,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_BQRESAMPLER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -91,7 +91,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_BQRESAMPLER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
@@ -109,7 +109,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_BQRESAMPLER;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -127,7 +127,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_BQRESAMPLER;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -139,55 +139,26 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\rubberband\rubberband-c.h" />
<ClInclude Include="..\rubberband\RubberBandStretcher.h" />
<ClInclude Include="..\src\audiocurves\CompoundAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\ConstantAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\HighFrequencyAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\PercussiveAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\SilentAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\SpectralDifferenceAudioCurve.h" />
<ClInclude Include="..\src\base\Profiler.h" />
<ClInclude Include="..\src\base\RingBuffer.h" />
<ClInclude Include="..\src\base\Scavenger.h" />
<ClInclude Include="..\src\dsp\AudioCurveCalculator.h" />
<ClInclude Include="..\src\dsp\FFT.h" />
<ClInclude Include="..\src\dsp\MovingMedian.h" />
<ClInclude Include="..\src\dsp\Resampler.h" />
<ClInclude Include="..\src\dsp\SampleFilter.h" />
<ClInclude Include="..\src\dsp\SincWindow.h" />
<ClInclude Include="..\src\dsp\Window.h" />
<ClInclude Include="..\src\float_cast\float_cast.h" />
<ClInclude Include="..\src\speex\speex_resampler.h" />
<ClInclude Include="..\src\StretchCalculator.h" />
<ClInclude Include="..\src\StretcherChannelData.h" />
<ClInclude Include="..\src\StretcherImpl.h" />
<ClInclude Include="..\src\system\Allocators.h" />
<ClInclude Include="..\src\system\sysutils.h" />
<ClInclude Include="..\src\system\Thread.h" />
<ClInclude Include="..\src\system\VectorOps.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\audiocurves\CompoundAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\ConstantAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\HighFrequencyAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\PercussiveAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\SilentAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\SpectralDifferenceAudioCurve.cpp" />
<ClCompile Include="..\src\base\Profiler.cpp" />
<ClCompile Include="..\src\dsp\AudioCurveCalculator.cpp" />
<ClCompile Include="..\src\dsp\FFT.cpp" />
<ClCompile Include="..\src\dsp\Resampler.cpp" />
<ClCompile Include="..\src\rubberband-c.cpp" />
<ClCompile Include="..\src\RubberBandStretcher.cpp" />
<ClCompile Include="..\src\speex\resample.c" />
<ClCompile Include="..\src\StretchCalculator.cpp" />
<ClCompile Include="..\src\StretcherChannelData.cpp" />
<ClCompile Include="..\src\StretcherImpl.cpp" />
<ClCompile Include="..\src\StretcherProcess.cpp" />
<ClCompile Include="..\src\system\Allocators.cpp" />
<ClCompile Include="..\src\system\sysutils.cpp" />
<ClCompile Include="..\src\system\Thread.cpp" />
<ClCompile Include="..\src\faster\AudioCurveCalculator.cpp" />
<ClCompile Include="..\src\faster\CompoundAudioCurve.cpp" />
<ClCompile Include="..\src\faster\HighFrequencyAudioCurve.cpp" />
<ClCompile Include="..\src\faster\SilentAudioCurve.cpp" />
<ClCompile Include="..\src\faster\PercussiveAudioCurve.cpp" />
<ClCompile Include="..\src\faster\StretcherChannelData.cpp" />
<ClCompile Include="..\src\faster\R2Stretcher.cpp" />
<ClCompile Include="..\src\faster\StretcherProcess.cpp" />
<ClCompile Include="..\src\common\BQResampler.cpp" />
<ClCompile Include="..\src\common\Profiler.cpp" />
<ClCompile Include="..\src\common\Resampler.cpp" />
<ClCompile Include="..\src\common\FFT.cpp" />
<ClCompile Include="..\src\common\Log.cpp" />
<ClCompile Include="..\src\common\Allocators.cpp" />
<ClCompile Include="..\src\common\StretchCalculator.cpp" />
<ClCompile Include="..\src\common\sysutils.cpp" />
<ClCompile Include="..\src\common\Thread.cpp" />
<ClCompile Include="..\src\finer\R3Stretcher.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -40,7 +40,7 @@
#include <lv2.h>
#endif
#include "base/RingBuffer.h"
#include "common/RingBuffer.h"
namespace RubberBand {
class RubberBandStretcher;

View File

@@ -0,0 +1,646 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#include "RubberBandR3PitchShifter.h"
#include "RubberBandStretcher.h"
#include <iostream>
#include <cmath>
using namespace RubberBand;
using std::cout;
using std::cerr;
using std::endl;
using std::min;
#ifdef RB_PLUGIN_LADSPA
const char *const
RubberBandR3PitchShifter::portNamesMono[PortCountMono] =
{
"latency",
"Cents",
"Semitones",
"Octaves",
"Formant Preserving",
"Wet-Dry Mix",
"Input",
"Output"
};
const char *const
RubberBandR3PitchShifter::portNamesStereo[PortCountStereo] =
{
"latency",
"Cents",
"Semitones",
"Octaves",
"Formant Preserving",
"Wet-Dry Mix",
"Input L",
"Output L",
"Input R",
"Output R"
};
const LADSPA_PortDescriptor
RubberBandR3PitchShifter::portsMono[PortCountMono] =
{
LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
};
const LADSPA_PortDescriptor
RubberBandR3PitchShifter::portsStereo[PortCountStereo] =
{
LADSPA_PORT_OUTPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
};
const LADSPA_PortRangeHint
RubberBandR3PitchShifter::hintsMono[PortCountMono] =
{
{ 0, 0, 0 }, // latency
{ LADSPA_HINT_DEFAULT_0 | // cents
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
-100.0, 100.0 },
{ LADSPA_HINT_DEFAULT_0 | // semitones
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
{ LADSPA_HINT_DEFAULT_0 | // octaves
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-2.0, 2.0 },
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // wet-dry mix
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
0.0, 1.0 },
{ 0, 0, 0 },
{ 0, 0, 0 }
};
const LADSPA_PortRangeHint
RubberBandR3PitchShifter::hintsStereo[PortCountStereo] =
{
{ 0, 0, 0 }, // latency
{ LADSPA_HINT_DEFAULT_0 | // cents
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
-100.0, 100.0 },
{ LADSPA_HINT_DEFAULT_0 | // semitones
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-12.0, 12.0 },
{ LADSPA_HINT_DEFAULT_0 | // octaves
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER,
-2.0, 2.0 },
{ LADSPA_HINT_DEFAULT_0 | // formant preserving
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ LADSPA_HINT_DEFAULT_0 | // wet-dry mix
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE,
0.0, 1.0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 }
};
const LADSPA_Properties
RubberBandR3PitchShifter::properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
const LADSPA_Descriptor
RubberBandR3PitchShifter::ladspaDescriptorMono =
{
29790, // "Unique" ID
"rubberband-r3-pitchshifter-mono", // Label
properties,
"Rubber Band R3 Mono Pitch Shifter", // Name
"Breakfast Quay",
"GPL",
PortCountMono,
portsMono,
portNamesMono,
hintsMono,
nullptr, // Implementation data
instantiate,
connectPort,
activate,
run,
nullptr, // Run adding
nullptr, // Set run adding gain
deactivate,
cleanup
};
const LADSPA_Descriptor
RubberBandR3PitchShifter::ladspaDescriptorStereo =
{
97920, // "Unique" ID
"rubberband-r3-pitchshifter-stereo", // Label
properties,
"Rubber Band R3 Stereo Pitch Shifter", // Name
"Breakfast Quay",
"GPL",
PortCountStereo,
portsStereo,
portNamesStereo,
hintsStereo,
nullptr, // Implementation data
instantiate,
connectPort,
activate,
run,
nullptr, // Run adding
nullptr, // Set run adding gain
deactivate,
cleanup
};
const LADSPA_Descriptor *
RubberBandR3PitchShifter::getDescriptor(unsigned long index)
{
if (index == 0) return &ladspaDescriptorMono;
if (index == 1) return &ladspaDescriptorStereo;
else return 0;
}
#else
const LV2_Descriptor
RubberBandR3PitchShifter::lv2DescriptorMono =
{
"http://breakfastquay.com/rdf/lv2-rubberband-r3#mono",
instantiate,
connectPort,
activate,
run,
deactivate,
cleanup,
nullptr
};
const LV2_Descriptor
RubberBandR3PitchShifter::lv2DescriptorStereo =
{
"http://breakfastquay.com/rdf/lv2-rubberband-r3#stereo",
instantiate,
connectPort,
activate,
run,
deactivate,
cleanup,
nullptr
};
const LV2_Descriptor *
RubberBandR3PitchShifter::getDescriptor(uint32_t index)
{
if (index == 0) return &lv2DescriptorMono;
if (index == 1) return &lv2DescriptorStereo;
else return 0;
}
#endif
RubberBandR3PitchShifter::RubberBandR3PitchShifter(int sampleRate, size_t channels) :
m_latency(nullptr),
m_cents(nullptr),
m_semitones(nullptr),
m_octaves(nullptr),
m_formant(nullptr),
m_wetDry(nullptr),
m_ratio(1.0),
m_prevRatio(1.0),
m_currentFormant(false),
m_blockSize(1024),
m_reserve(8192),
m_bufsize(0),
m_minfill(0),
m_stretcher(new RubberBandStretcher
(sampleRate, channels,
RubberBandStretcher::OptionProcessRealTime |
RubberBandStretcher::OptionEngineFiner)),
m_sampleRate(sampleRate),
m_channels(channels)
{
m_input = new float *[m_channels];
m_output = new float *[m_channels];
m_outputBuffer = new RingBuffer<float> *[m_channels];
m_delayMixBuffer = new RingBuffer<float> *[m_channels];
m_scratch = new float *[m_channels];
m_inptrs = new float *[m_channels];
m_bufsize = m_blockSize + m_reserve + 8192;
for (size_t c = 0; c < m_channels; ++c) {
m_input[c] = 0;
m_output[c] = 0;
m_outputBuffer[c] = new RingBuffer<float>(m_bufsize);
m_delayMixBuffer[c] = new RingBuffer<float>(m_bufsize);
m_scratch[c] = new float[m_bufsize];
for (size_t i = 0; i < m_bufsize; ++i) {
m_scratch[c][i] = 0.f;
}
m_inptrs[c] = 0;
}
activateImpl();
}
RubberBandR3PitchShifter::~RubberBandR3PitchShifter()
{
delete m_stretcher;
for (size_t c = 0; c < m_channels; ++c) {
delete m_outputBuffer[c];
delete m_delayMixBuffer[c];
delete[] m_scratch[c];
}
delete[] m_outputBuffer;
delete[] m_delayMixBuffer;
delete[] m_inptrs;
delete[] m_scratch;
delete[] m_output;
delete[] m_input;
}
#ifdef RB_PLUGIN_LADSPA
LADSPA_Handle
RubberBandR3PitchShifter::instantiate(const LADSPA_Descriptor *desc, unsigned long rate)
{
if (desc->PortCount == ladspaDescriptorMono.PortCount) {
return new RubberBandR3PitchShifter(rate, 1);
} else if (desc->PortCount == ladspaDescriptorStereo.PortCount) {
return new RubberBandR3PitchShifter(rate, 2);
}
return nullptr;
}
#else
LV2_Handle
RubberBandR3PitchShifter::instantiate(const LV2_Descriptor *desc, double rate,
const char *, const LV2_Feature *const *)
{
if (rate < 1.0) {
std::cerr << "RubberBandR3PitchShifter::instantiate: invalid sample rate "
<< rate << " provided" << std::endl;
return nullptr;
}
size_t srate = size_t(round(rate));
if (std::string(desc->URI) == lv2DescriptorMono.URI) {
return new RubberBandR3PitchShifter(srate, 1);
} else if (std::string(desc->URI) == lv2DescriptorStereo.URI) {
return new RubberBandR3PitchShifter(srate, 2);
} else {
std::cerr << "RubberBandR3PitchShifter::instantiate: unrecognised URI "
<< desc->URI << " requested" << std::endl;
return nullptr;
}
}
#endif
#ifdef RB_PLUGIN_LADSPA
void
RubberBandR3PitchShifter::connectPort(LADSPA_Handle handle,
unsigned long port, LADSPA_Data *location)
#else
void
RubberBandR3PitchShifter::connectPort(LV2_Handle handle,
uint32_t port, void *location)
#endif
{
RubberBandR3PitchShifter *shifter = (RubberBandR3PitchShifter *)handle;
float **ports[PortCountStereo] = {
&shifter->m_latency,
&shifter->m_cents,
&shifter->m_semitones,
&shifter->m_octaves,
&shifter->m_formant,
&shifter->m_wetDry,
&shifter->m_input[0],
&shifter->m_output[0],
&shifter->m_input[1],
&shifter->m_output[1]
};
if (shifter->m_channels == 1) {
if (port >= PortCountMono) return;
} else {
if (port >= PortCountStereo) return;
}
*ports[port] = (float *)location;
if (shifter->m_latency) {
*(shifter->m_latency) = shifter->getLatency();
}
}
#ifdef RB_PLUGIN_LADSPA
void
RubberBandR3PitchShifter::activate(LADSPA_Handle handle)
#else
void
RubberBandR3PitchShifter::activate(LV2_Handle handle)
#endif
{
RubberBandR3PitchShifter *shifter = (RubberBandR3PitchShifter *)handle;
shifter->activateImpl();
}
#ifdef RB_PLUGIN_LADSPA
void
RubberBandR3PitchShifter::run(LADSPA_Handle handle, unsigned long samples)
#else
void
RubberBandR3PitchShifter::run(LV2_Handle handle, uint32_t samples)
#endif
{
RubberBandR3PitchShifter *shifter = (RubberBandR3PitchShifter *)handle;
shifter->runImpl(samples);
}
#ifdef RB_PLUGIN_LADSPA
void
RubberBandR3PitchShifter::deactivate(LADSPA_Handle handle)
#else
void
RubberBandR3PitchShifter::deactivate(LV2_Handle handle)
#endif
{
activate(handle); // both functions just reset the plugin
}
#ifdef RB_PLUGIN_LADSPA
void
RubberBandR3PitchShifter::cleanup(LADSPA_Handle handle)
#else
void
RubberBandR3PitchShifter::cleanup(LV2_Handle handle)
#endif
{
delete (RubberBandR3PitchShifter *)handle;
}
int
RubberBandR3PitchShifter::getLatency() const
{
return m_reserve;
}
void
RubberBandR3PitchShifter::activateImpl()
{
updateRatio();
m_prevRatio = m_ratio;
m_stretcher->reset();
m_stretcher->setPitchScale(m_ratio);
for (size_t c = 0; c < m_channels; ++c) {
m_outputBuffer[c]->reset();
}
for (size_t c = 0; c < m_channels; ++c) {
m_delayMixBuffer[c]->reset();
m_delayMixBuffer[c]->zero(getLatency());
}
for (size_t c = 0; c < m_channels; ++c) {
for (size_t i = 0; i < m_bufsize; ++i) {
m_scratch[c][i] = 0.f;
}
}
m_minfill = 0;
m_stretcher->process(m_scratch, m_reserve, false);
}
void
RubberBandR3PitchShifter::updateRatio()
{
// The octaves, semitones, and cents parameters are supposed to be
// integral: we want to enforce that, just to avoid
// inconsistencies between hosts if some respect the hints more
// than others
#ifdef RB_PLUGIN_LADSPA
// But we don't want to change the long-standing behaviour of the
// LADSPA plugin, so let's leave this as-is and only do "the right
// thing" for LV2
double oct = (m_octaves ? *m_octaves : 0.0);
oct += (m_semitones ? *m_semitones : 0.0) / 12;
oct += (m_cents ? *m_cents : 0.0) / 1200;
m_ratio = pow(2.0, oct);
#else
// LV2
double octaves = round(m_octaves ? *m_octaves : 0.0);
if (octaves < -2.0) octaves = -2.0;
if (octaves > 2.0) octaves = 2.0;
double semitones = round(m_semitones ? *m_semitones : 0.0);
if (semitones < -12.0) semitones = -12.0;
if (semitones > 12.0) semitones = 12.0;
double cents = round(m_cents ? *m_cents : 0.0);
if (cents < -100.0) cents = -100.0;
if (cents > 100.0) cents = 100.0;
m_ratio = pow(2.0,
octaves +
semitones / 12.0 +
cents / 1200.0);
#endif
}
void
RubberBandR3PitchShifter::updateFormant()
{
if (!m_formant) return;
bool f = (*m_formant > 0.5f);
if (f == m_currentFormant) return;
RubberBandStretcher *s = m_stretcher;
s->setFormantOption(f ?
RubberBandStretcher::OptionFormantPreserved :
RubberBandStretcher::OptionFormantShifted);
m_currentFormant = f;
}
void
RubberBandR3PitchShifter::runImpl(uint32_t insamples)
{
for (size_t c = 0; c < m_channels; ++c) {
m_delayMixBuffer[c]->write(m_input[c], insamples);
}
size_t offset = 0;
// We have to break up the input into chunks like this because
// insamples could be arbitrarily large and our output buffer is
// of limited size
while (offset < insamples) {
size_t block = m_blockSize;
if (offset + block > insamples) {
block = insamples - offset;
}
runImpl(block, offset);
offset += block;
}
float mix = 0.0;
if (m_wetDry) mix = *m_wetDry;
for (size_t c = 0; c < m_channels; ++c) {
if (mix > 0.0) {
for (size_t i = 0; i < insamples; ++i) {
float dry = m_delayMixBuffer[c]->readOne();
m_output[c][i] *= (1.0 - mix);
m_output[c][i] += dry * mix;
}
} else {
m_delayMixBuffer[c]->skip(insamples);
}
}
}
void
RubberBandR3PitchShifter::runImpl(uint32_t insamples, uint32_t offset)
{
updateRatio();
if (m_ratio != m_prevRatio) {
m_stretcher->setPitchScale(m_ratio);
m_prevRatio = m_ratio;
}
if (m_latency) {
*m_latency = getLatency();
}
updateFormant();
const int samples = insamples;
int processed = 0;
size_t outTotal = 0;
while (processed < samples) {
// never feed more than the minimum necessary number of
// samples at a time; ensures nothing will overflow internally
// and we don't need to call setMaxProcessSize
int toCauseProcessing = m_stretcher->getSamplesRequired();
int inchunk = min(samples - processed, toCauseProcessing);
for (size_t c = 0; c < m_channels; ++c) {
m_inptrs[c] = &(m_input[c][offset + processed]);
}
m_stretcher->process(m_inptrs, inchunk, false);
processed += inchunk;
int avail = m_stretcher->available();
int writable = m_outputBuffer[0]->getWriteSpace();
int outchunk = avail;
if (outchunk > writable) {
cerr << "RubberBandR3PitchShifter::runImpl: buffer is not large enough: size = " << m_outputBuffer[0]->getSize() << ", chunk = " << outchunk << ", space = " << writable << " (buffer contains " << m_outputBuffer[0]->getReadSpace() << " unread)" << endl;
outchunk = writable;
}
size_t actual = m_stretcher->retrieve(m_scratch, outchunk);
outTotal += actual;
for (size_t c = 0; c < m_channels; ++c) {
m_outputBuffer[c]->write(m_scratch[c], actual);
}
}
for (size_t c = 0; c < m_channels; ++c) {
int toRead = m_outputBuffer[c]->getReadSpace();
if (toRead < samples && c == 0) {
cerr << "RubberBandR3PitchShifter::runImpl: buffer underrun: required = " << samples << ", available = " << toRead << endl;
}
int chunk = min(toRead, samples);
m_outputBuffer[c]->read(&(m_output[c][offset]), chunk);
}
size_t fill = m_outputBuffer[0]->getReadSpace();
if (fill < m_minfill || m_minfill == 0) {
m_minfill = fill;
// cerr << "minfill = " << m_minfill << endl;
}
}

View File

@@ -0,0 +1,149 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_R3_PITCH_SHIFTER_H
#define RUBBERBAND_R3_PITCH_SHIFTER_H
#ifdef RB_PLUGIN_LADSPA
#ifdef RB_PLUGIN_LV2
#error "Only one of RB_PLUGIN_LADSPA and RB_PLUGIN_LV2 may be defined at once"
#endif
#else
#ifndef RB_PLUGIN_LV2
#error "Including code must define either RB_PLUGIN_LADSPA or RB_PLUGIN_LV2"
#endif
#endif
#ifdef RB_PLUGIN_LADSPA
#include <ladspa.h>
#else
#include <lv2.h>
#endif
#include "common/RingBuffer.h"
namespace RubberBand {
class RubberBandStretcher;
}
class RubberBandR3PitchShifter
{
public:
#ifdef RB_PLUGIN_LADSPA
static const LADSPA_Descriptor *getDescriptor(unsigned long index);
#else
static const LV2_Descriptor *getDescriptor(uint32_t index);
#endif
protected:
RubberBandR3PitchShifter(int sampleRate, size_t channels);
~RubberBandR3PitchShifter();
enum {
LatencyPort = 0,
CentsPort = 1,
SemitonesPort = 2,
OctavesPort = 3,
FormantPort = 4,
WetDryPort = 5,
InputPort1 = 6,
OutputPort1 = 7,
PortCountMono = OutputPort1 + 1,
InputPort2 = 8,
OutputPort2 = 9,
PortCountStereo = OutputPort2 + 1
};
#ifdef RB_PLUGIN_LADSPA
static const char *const portNamesMono[PortCountMono];
static const LADSPA_PortDescriptor portsMono[PortCountMono];
static const LADSPA_PortRangeHint hintsMono[PortCountMono];
static const char *const portNamesStereo[PortCountStereo];
static const LADSPA_PortDescriptor portsStereo[PortCountStereo];
static const LADSPA_PortRangeHint hintsStereo[PortCountStereo];
static const LADSPA_Properties properties;
static const LADSPA_Descriptor ladspaDescriptorMono;
static const LADSPA_Descriptor ladspaDescriptorStereo;
static LADSPA_Handle instantiate(const LADSPA_Descriptor *, unsigned long);
static void connectPort(LADSPA_Handle, unsigned long, LADSPA_Data *);
static void activate(LADSPA_Handle);
static void run(LADSPA_Handle, unsigned long);
static void deactivate(LADSPA_Handle);
static void cleanup(LADSPA_Handle);
#else
static const LV2_Descriptor lv2DescriptorMono;
static const LV2_Descriptor lv2DescriptorStereo;
static LV2_Handle instantiate(const LV2_Descriptor *, double,
const char *, const LV2_Feature *const *);
static void connectPort(LV2_Handle, uint32_t, void *);
static void activate(LV2_Handle);
static void run(LV2_Handle, uint32_t);
static void deactivate(LV2_Handle);
static void cleanup(LV2_Handle);
#endif
void activateImpl();
void runImpl(uint32_t count);
void runImpl(uint32_t count, uint32_t offset);
void updateRatio();
void updateFormant();
int getLatency() const;
float **m_input;
float **m_output;
float *m_latency;
float *m_cents;
float *m_semitones;
float *m_octaves;
float *m_formant;
float *m_wetDry;
double m_ratio;
double m_prevRatio;
bool m_currentFormant;
size_t m_blockSize;
size_t m_reserve;
size_t m_bufsize;
size_t m_minfill;
RubberBand::RubberBandStretcher *m_stretcher;
RubberBand::RingBuffer<float> **m_outputBuffer;
RubberBand::RingBuffer<float> **m_delayMixBuffer;
float **m_scratch;
float **m_inptrs;
int m_sampleRate;
size_t m_channels;
};
#endif

View File

@@ -1,2 +1,4 @@
ladspa:ladspa-rubberband:rubberband-pitchshifter-mono::Frequency > Pitch shifters
ladspa:ladspa-rubberband:rubberband-pitchshifter-stereo::Frequency > Pitch shifters
ladspa:ladspa-rubberband:rubberband-r3-pitchshifter-mono::Frequency > Pitch shifters
ladspa:ladspa-rubberband:rubberband-r3-pitchshifter-stereo::Frequency > Pitch shifters

View File

@@ -24,6 +24,7 @@
#define RB_PLUGIN_LADSPA 1
#undef RB_PLUGIN_LV2
#include "RubberBandPitchShifter.cpp"
#include "RubberBandR3PitchShifter.cpp"
#include <stdio.h>
@@ -31,7 +32,11 @@ extern "C" {
const LADSPA_Descriptor *ladspa_descriptor(unsigned long index)
{
if (index < 2) {
return RubberBandPitchShifter::getDescriptor(index);
} else {
return RubberBandR3PitchShifter::getDescriptor(index - 2);
}
}
}

View File

@@ -24,6 +24,7 @@
#define RB_PLUGIN_LV2 1
#undef RB_PLUGIN_LADSPA
#include "RubberBandPitchShifter.cpp"
#include "RubberBandR3PitchShifter.cpp"
#include <stdio.h>
@@ -32,7 +33,11 @@ extern "C" {
LV2_SYMBOL_EXPORT
const LV2_Descriptor *lv2_descriptor(uint32_t index)
{
if (index < 2) {
return RubberBandPitchShifter::getDescriptor(index);
} else {
return RubberBandR3PitchShifter::getDescriptor(index - 2);
}
}
}

View File

@@ -78,6 +78,16 @@
lv2:maximum 1 ;
lv2:portProperty lv2:integer, lv2:toggled .
:formantPortR3
a lv2:ControlPort, lv2:InputPort ;
lv2:index 4 ;
lv2:symbol "formant" ;
lv2:name "Formant Preserving" ;
lv2:default 0 ;
lv2:minimum 0 ;
lv2:maximum 1 ;
lv2:portProperty lv2:integer, lv2:toggled .
:wetDryPort
a lv2:ControlPort, lv2:InputPort ;
lv2:index 6 ;
@@ -87,6 +97,15 @@
lv2:minimum 0 ;
lv2:maximum 1 .
:wetDryPortR3
a lv2:ControlPort, lv2:InputPort ;
lv2:index 5 ;
lv2:symbol "wetdry" ;
lv2:name "Wet-Dry Mix" ;
lv2:default 0 ;
lv2:minimum 0 ;
lv2:maximum 1 .
rubberband:mono_in_group
a pg:MonoGroup, pg:InputGroup ;
lv2:symbol "mono_in" ;
@@ -146,6 +165,44 @@ rubberband:mono
lv2:designation pg:center ;
] .
rubberband:r3mono
a doap:Project, lv2:Plugin, lv2:PitchPlugin ;
doap:name "Rubber Band R3 Mono Pitch Shifter" ;
doap:license <http://usefulinc.com/doap/licenses/gpl> ;
foaf:maker :maker ;
doap:developer :maker ;
doap:maintainer :maker ;
# Minor version will be 2x the Rubber Band API minor version,
# but this is an initial test release, so 0
lv2:minorVersion 0 ;
lv2:microVersion 0 ;
lv2:optionalFeature lv2:hardRTCapable ;
pg:mainInput rubberband:mono_in_group ;
pg:mainOutput rubberband:mono_out_group ;
dc:replaces <urn:ladspa:29790> ;
lv2:port :latencyPort ,
:centsPort ,
:semitonesPort ,
:octavesPort ,
:formantPortR3 ,
:wetDryPortR3 ,
[ a lv2:AudioPort, lv2:InputPort ;
lv2:index 6 ;
lv2:symbol "input" ;
lv2:name "Input" ;
lv2:shortName "Input" ;
pg:group rubberband:mono_in_group ;
lv2:designation pg:center ;
], [
a lv2:AudioPort, lv2:OutputPort ;
lv2:index 7 ;
lv2:symbol "output" ;
lv2:name "Output" ;
lv2:shortName "Output" ;
pg:group rubberband:mono_out_group ;
lv2:designation pg:center ;
] .
rubberband:stereo
a doap:Project, lv2:Plugin, lv2:PitchPlugin ;
doap:name "Rubber Band Stereo Pitch Shifter" ;
@@ -200,3 +257,56 @@ rubberband:stereo
lv2:designation pg:right ;
] .
rubberband:r3stereo
a doap:Project, lv2:Plugin, lv2:PitchPlugin ;
doap:name "Rubber Band R3 Stereo Pitch Shifter" ;
doap:license <http://usefulinc.com/doap/licenses/gpl> ;
foaf:maker :maker ;
doap:developer :maker ;
doap:maintainer :maker ;
# Minor version will be 2x the Rubber Band API minor version,
# but this is an initial test release, so 0
lv2:minorVersion 0 ;
lv2:microVersion 0 ;
lv2:optionalFeature lv2:hardRTCapable ;
pg:mainInput rubberband:stereo_in_group ;
pg:mainOutput rubberband:stereo_out_group ;
dc:replaces <urn:ladspa:97920> ;
lv2:port :latencyPort ,
:centsPort ,
:semitonesPort ,
:octavesPort ,
:formantPortR3 ,
:wetDryPortR3 ,
[ a lv2:AudioPort, lv2:InputPort ;
lv2:index 6 ;
lv2:symbol "input_l" ;
lv2:name "Input L" ;
lv2:shortName "Input L" ;
pg:group rubberband:stereo_in_group ;
lv2:designation pg:left ;
], [
a lv2:AudioPort, lv2:OutputPort ;
lv2:index 7 ;
lv2:symbol "output_l" ;
lv2:name "Output L" ;
lv2:shortName "Output L" ;
pg:group rubberband:stereo_out_group ;
lv2:designation pg:left ;
], [ a lv2:AudioPort, lv2:InputPort ;
lv2:index 8 ;
lv2:symbol "input_r" ;
lv2:name "Input R" ;
lv2:shortName "Input R" ;
pg:group rubberband:stereo_in_group ;
lv2:designation pg:right ;
], [
a lv2:AudioPort, lv2:OutputPort ;
lv2:index 9 ;
lv2:symbol "output_r" ;
lv2:name "Output R" ;
lv2:shortName "Output R" ;
pg:group rubberband:stereo_out_group ;
lv2:designation pg:right ;
] .

View File

@@ -7,8 +7,18 @@ rubberband:mono
lv2:binary <lv2-rubberband.so> ;
rdfs:seeAlso <lv2-rubberband.ttl> .
rubberband:r3mono
a lv2:Plugin ;
lv2:binary <lv2-rubberband.so> ;
rdfs:seeAlso <lv2-rubberband.ttl> .
rubberband:stereo
a lv2:Plugin ;
lv2:binary <lv2-rubberband.so> ;
rdfs:seeAlso <lv2-rubberband.ttl> .
rubberband:r3stereo
a lv2:Plugin ;
lv2:binary <lv2-rubberband.so> ;
rdfs:seeAlso <lv2-rubberband.ttl> .

View File

@@ -33,24 +33,26 @@
#include <fstream>
#include "../src/system/sysutils.h"
#include "../src/common/sysutils.h"
#include "../src/common/Profiler.h"
#ifdef _MSC_VER
#include "../src/getopt/getopt.h"
#include "../src/ext/getopt/getopt.h"
#else
#include <getopt.h>
#include <unistd.h>
#include <sys/time.h>
#endif
#include "../src/base/Profiler.h"
#ifdef _WIN32
using RubberBand::gettimeofday;
#endif
#ifdef _MSC_VER
using RubberBand::usleep;
#include <windows.h>
static void usleep(unsigned long usec) {
::Sleep(usec == 0 ? 0 : usec < 1000 ? 1 : usec / 1000);
}
#define strdup _strdup
#endif
@@ -82,15 +84,13 @@ double tempo_convert(const char *str)
int main(int argc, char **argv)
{
int c;
double ratio = 1.0;
double duration = 0.0;
double pitchshift = 0.0;
double frequencyshift = 1.0;
int debug = 0;
bool realtime = false;
bool precise = true;
bool precisiongiven = false;
int threading = 0;
bool lamination = true;
bool longwin = false;
@@ -101,7 +101,10 @@ int main(int argc, char **argv)
bool together = false;
bool crispchanged = false;
int crispness = -1;
bool faster = false;
bool finer = false;
bool help = false;
bool fullHelp = false;
bool version = false;
bool quiet = false;
@@ -126,11 +129,22 @@ int main(int argc, char **argv)
bool ignoreClipping = false;
std::string myName(argv[0]);
bool isR3 =
((myName.size() > 3 &&
myName.substr(myName.size() - 3, 3) == "-r3") ||
(myName.size() > 7 &&
myName.substr(myName.size() - 7, 7) == "-r3.exe") ||
(myName.size() > 7 &&
myName.substr(myName.size() - 7, 7) == "-R3.EXE"));
while (1) {
int optionIndex = 0;
static struct option longOpts[] = {
{ "help", 0, 0, 'h' },
{ "full-help", 0, 0, 'H' },
{ "version", 0, 0, 'V' },
{ "time", 1, 0, 't' },
{ "tempo", 1, 0, 'T' },
@@ -146,10 +160,10 @@ int main(int argc, char **argv)
{ "formant", 0, 0, 'F' },
{ "no-threads", 0, 0, '0' },
{ "no-transients", 0, 0, '1' },
{ "no-lamination", 0, 0, '2' },
{ "no-lamination", 0, 0, '.' },
{ "centre-focus", 0, 0, '7' },
{ "window-long", 0, 0, '3' },
{ "window-short", 0, 0, '4' },
{ "window-long", 0, 0, '>' },
{ "window-short", 0, 0, '<' },
{ "bl-transients", 0, 0, '8' },
{ "detector-perc", 0, 0, '5' },
{ "detector-soft", 0, 0, '6' },
@@ -161,16 +175,19 @@ int main(int argc, char **argv)
{ "freqmap", 1, 0, 'Q' },
{ "pitchmap", 1, 0, 'C' },
{ "ignore-clipping", 0, 0, 'i' },
{ "fast", 0, 0, '2' },
{ "fine", 0, 0, '3' },
{ 0, 0, 0, 0 }
};
c = getopt_long(argc, argv,
"t:p:d:RLPFc:f:T:D:qhVM:",
int optionChar = getopt_long(argc, argv,
"t:p:d:RLPFc:f:T:D:qhHVM:23",
longOpts, &optionIndex);
if (c == -1) break;
if (optionChar == -1) break;
switch (c) {
switch (optionChar) {
case 'h': help = true; break;
case 'H': fullHelp = true; break;
case 'V': version = true; break;
case 't': ratio *= atof(optarg); haveRatio = true; break;
case 'T': ratio *= tempo_convert(optarg); haveRatio = true; break;
@@ -179,15 +196,15 @@ int main(int argc, char **argv)
case 'f': frequencyshift = atof(optarg); haveRatio = true; break;
case 'd': debug = atoi(optarg); break;
case 'R': realtime = true; break;
case 'L': precise = false; break;
case 'P': precise = true; break;
case 'L': precisiongiven = true; break;
case 'P': precisiongiven = true; break;
case 'F': formant = true; break;
case '0': threading = 1; break;
case '@': threading = 2; break;
case '1': transients = NoTransients; crispchanged = true; break;
case '2': lamination = false; crispchanged = true; break;
case '3': longwin = true; crispchanged = true; break;
case '4': shortwin = true; crispchanged = true; break;
case '.': lamination = false; crispchanged = true; break;
case '>': longwin = true; crispchanged = true; break;
case '<': shortwin = true; crispchanged = true; break;
case '5': detector = PercussiveDetector; crispchanged = true; break;
case '6': detector = SoftDetector; crispchanged = true; break;
case '7': together = true; break;
@@ -200,6 +217,8 @@ int main(int argc, char **argv)
case 'Q': freqMapFile = optarg; freqOrPitchMapSpecified = true; break;
case 'C': pitchMapFile = optarg; freqOrPitchMapSpecified = true; break;
case 'i': ignoreClipping = true; break;
case '2': faster = true; break;
case '3': finer = true; break;
default: help = true; break;
}
}
@@ -218,15 +237,15 @@ int main(int argc, char **argv)
realtime = true;
}
if (help || !haveRatio || optind + 2 != argc) {
if (help || fullHelp || !haveRatio || optind + 2 != argc) {
cerr << endl;
cerr << "Rubber Band" << endl;
cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl;
cerr << "Copyright 2007-2022 Particular Programs Ltd." << endl;
cerr << endl;
cerr << " Usage: " << argv[0] << " [options] <infile.wav> <outfile.wav>" << endl;
cerr << " Usage: " << myName << " [options] <infile.wav> <outfile.wav>" << endl;
cerr << endl;
cerr << "You must specify at least one of the following time and pitch ratio options." << endl;
cerr << "You must specify at least one of the following time and pitch ratio options:" << endl;
cerr << endl;
cerr << " -t<X>, --time <X> Stretch to X times original duration, or" << endl;
cerr << " -T<X>, --tempo <X> Change tempo by multiple X (same as --time 1/X), or" << endl;
@@ -237,7 +256,7 @@ int main(int argc, char **argv)
cerr << " -f<X>, --frequency <X> Change frequency by multiple X" << endl;
cerr << endl;
cerr << "The following options provide ways of making the time and frequency ratios" << endl;
cerr << "change during the audio." << endl;
cerr << "change during the audio:" << endl;
cerr << endl;
cerr << " -M<F>, --timemap <F> Use file F as the source for time map" << endl;
cerr << endl;
@@ -265,20 +284,42 @@ int main(int argc, char **argv)
cerr << " lists frequency multipliers rather than pitch offsets (like the difference" << endl;
cerr << " between pitch and frequency options above)." << endl;
cerr << endl;
cerr << "The following options provide a simple way to adjust the sound. See below" << endl;
cerr << "for more details." << endl;
cerr << "The following options affect the sound manipulation and quality:" << endl;
cerr << endl;
cerr << " -2, --fast Use the R2 (faster) engine" << endl;
cerr << endl;
cerr << " This is the default (for backward compatibility) when this tool is invoked" << endl;
cerr << " as \"rubberband\". It was the only engine available in versions prior to v3.0." << endl;
cerr << endl;
cerr << " -3, --fine Use the R3 (finer) engine" << endl;
cerr << endl;
cerr << " This is the default when this tool is invoked as \"rubberband-r3\". It almost" << endl;
cerr << " always produces better results than the R2 engine, but with significantly" << endl;
cerr << " higher CPU load." << endl;
cerr << endl;
cerr << " -c<N>, --crisp <N> Crispness (N = 0,1,2,3,4,5,6); default 5 (see below)" << endl;
cerr << " -F, --formant Enable formant preservation when pitch shifting" << endl;
cerr << endl;
cerr << " This option attempts to keep the formant envelope unchanged when changing" << endl;
cerr << " the pitch, retaining the original timbre of vocals and instruments in a" << endl;
cerr << " recognisable way." << endl;
cerr << endl;
if (fullHelp || !isR3) {
cerr << " -c<N>, --crisp <N> Crispness (N = 0,1,2,3,4,5,6); default 5" << endl;
cerr << endl;
cerr << " This option only has an effect when using the R2 (faster) engine. See below" << endl;
cerr << " for details of the different levels." << endl;
cerr << endl;
}
if (fullHelp) {
cerr << "The remaining options fine-tune the processing mode and stretch algorithm." << endl;
cerr << "These are mostly included for test purposes; the default settings and standard" << endl;
cerr << "crispness parameter are intended to provide the best sounding set of options" << endl;
cerr << "for most situations. The default is to use none of these options." << endl;
cerr << endl;
cerr << " -L, --loose Relax timing in hope of better transient preservation" << endl;
cerr << " -P, --precise Ignored: The opposite of -L, this is default from 1.6" << endl;
cerr << " -R, --realtime Select realtime mode (implies --no-threads)" << endl;
cerr << " -R, --realtime Select realtime mode (implies --no-threads)." << endl;
cerr << " This utility does not do realtime stream processing;" << endl;
cerr << " the option merely selects realtime mode for the" << endl;
cerr << " stretcher it uses" << endl;
cerr << " --no-threads No extra threads regardless of CPU and channel count" << endl;
cerr << " --threads Assume multi-CPU even if only one CPU is identified" << endl;
cerr << " --no-transients Disable phase resynchronisation at transients" << endl;
@@ -294,14 +335,21 @@ int main(int argc, char **argv)
cerr << " (at a cost in width and individual channel quality)" << endl;
cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl;
cerr << " with reduced gain if clipping occurs" << endl;
cerr << " -L, --loose [Accepted for compatibility but ignored; always off]" << endl;
cerr << " -P, --precise [Accepted for compatibility but ignored; always on]" << endl;
cerr << endl;
cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl;
cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl;
cerr << endl;
}
cerr << "The following options are for output control and administration:" << endl;
cerr << endl;
cerr << " -q, --quiet Suppress progress output" << endl;
cerr << endl;
cerr << " -V, --version Show version number and exit" << endl;
cerr << " -h, --help Show this help" << endl;
cerr << " -h, --help Show the normal help output" << endl;
cerr << " -H, --full-help Show the full help output" << endl;
cerr << endl;
if (fullHelp) {
cerr << "\"Crispness\" levels:" << endl;
cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl;
cerr << " -c 1 equivalent to --detector-soft --no-lamination --window-long (for piano)" << endl;
@@ -311,6 +359,11 @@ int main(int argc, char **argv)
cerr << " -c 5 default processing options" << endl;
cerr << " -c 6 equivalent to --no-lamination --window-short (may be good for drums)" << endl;
cerr << endl;
} else {
cerr << "Numerous other options are available, mostly for tuning the behaviour of" << endl;
cerr << "the R2 engine. Run \"" << myName << " --full-help\" for details." << endl;
cerr << endl;
}
return 2;
}
@@ -319,6 +372,23 @@ int main(int argc, char **argv)
return 1;
}
if (faster && finer) {
cerr << "WARNING: Both fast (R2) and fine (R3) engines selected, will use default for" << endl;
cerr << " this tool (" << (isR3 ? "fine" : "fast") << ")" << endl;
faster = false;
finer = false;
}
if (isR3) {
if (!faster) {
finer = true;
}
} else {
if (!finer) {
faster = true;
}
}
if (crispness >= 0 && crispchanged) {
cerr << "WARNING: Both crispness option and transients, lamination or window options" << endl;
cerr << " provided -- crispness will override these other options" << endl;
@@ -330,6 +400,11 @@ int main(int argc, char **argv)
hqpitch = false;
}
if (precisiongiven) {
cerr << "NOTE: The -L/--loose and -P/--precise options are both ignored -- precise" << endl;
cerr << " became the default in v1.6 and loose was removed in v3.0" << endl;
}
switch (crispness) {
case -1: crispness = 5; break;
case 0: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
@@ -342,6 +417,10 @@ int main(int argc, char **argv)
};
if (!quiet) {
if (finer) {
cerr << "Using R3 (finer) engine" << endl;
} else {
cerr << "Using R2 (faster) engine" << endl;
cerr << "Using crispness level: " << crispness << " (";
switch (crispness) {
case 0: cerr << "Mushy"; break;
@@ -354,6 +433,7 @@ int main(int argc, char **argv)
}
cerr << ")" << endl;
}
}
std::map<size_t, size_t> timeMap;
if (timeMapFile != "") {
@@ -492,8 +572,11 @@ int main(int argc, char **argv)
}
RubberBandStretcher::Options options = 0;
if (finer) {
options = RubberBandStretcher::OptionEngineFiner;
}
if (realtime) options |= RubberBandStretcher::OptionProcessRealTime;
if (precise) options |= RubberBandStretcher::OptionStretchPrecise;
if (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent;
if (longwin) options |= RubberBandStretcher::OptionWindowLong;
if (shortwin) options |= RubberBandStretcher::OptionWindowShort;
@@ -782,19 +865,21 @@ int main(int argc, char **argv)
}
if (clipping) {
const float mingain = 0.75f;
if (gain < mingain) {
cerr << "NOTE: Clipping detected at output sample "
<< countOut << ", but not reducing gain as it would "
<< "mean dropping below minimum " << mingain << endl;
gain = mingain;
ignoreClipping = true;
} else {
if (!quiet) {
cerr << "NOTE: Clipping detected at output sample "
<< countOut << ", restarting with "
<< "reduced gain of " << gain
<< " (supply --ignore-clipping to avoid this)" << endl;
<< " (supply --ignore-clipping to avoid this)"
<< endl;
}
const float mingain = 0.75f;
if (gain < mingain) {
cerr << "WARNING: Clipped values were implausibly high: "
<< "something wrong with input or process - "
<< "not reducing gain below " << mingain << endl;
gain = mingain;
ignoreClipping = true;
}
successful = false;
break;
@@ -900,7 +985,11 @@ int main(int argc, char **argv)
if (!quiet) {
cerr << "in: " << countIn << ", out: " << countOut << ", ratio: " << float(countOut)/float(countIn) << ", ideal output: " << lrint(countIn * ratio) << ", error: " << abs(lrint(countIn * ratio) - int(countOut)) << endl;
cerr << "in: " << countIn << ", out: " << countOut
<< ", ratio: " << float(countOut)/float(countIn)
<< ", ideal output: " << lrint(countIn * ratio)
<< ", error: " << abs(lrint(countIn * ratio) - int(countOut))
<< endl;
#ifdef _WIN32
RubberBand::
@@ -916,7 +1005,9 @@ int main(int argc, char **argv)
etv.tv_usec -= tv.tv_usec;
double sec = double(etv.tv_sec) + (double(etv.tv_usec) / 1000000.0);
cerr << "elapsed time: " << sec << " sec, in frames/sec: " << countIn/sec << ", out frames/sec: " << countOut/sec << endl;
cerr << "elapsed time: " << sec << " sec, in frames/sec: "
<< int64_t(countIn/sec) << ", out frames/sec: "
<< int64_t(countOut/sec) << endl;
}
RubberBand::Profiler::dump();

View File

@@ -2,10 +2,11 @@
project(
'Rubber Band Library',
'c', 'cpp',
version: '2.0.2',
version: '3.0.0-beta3',
license: 'GPL-2.0-or-later',
default_options: [
'cpp_std=c++14',
'cpp_std=c++11',
'warning_level=3',
'buildtype=release',
'default_library=both',
'b_ndebug=if-release',
@@ -33,23 +34,23 @@ public_headers = [
library_sources = [
'src/rubberband-c.cpp',
'src/RubberBandStretcher.cpp',
'src/StretcherProcess.cpp',
'src/StretchCalculator.cpp',
'src/base/Profiler.cpp',
'src/dsp/AudioCurveCalculator.cpp',
'src/audiocurves/CompoundAudioCurve.cpp',
'src/audiocurves/SpectralDifferenceAudioCurve.cpp',
'src/audiocurves/HighFrequencyAudioCurve.cpp',
'src/audiocurves/SilentAudioCurve.cpp',
'src/audiocurves/ConstantAudioCurve.cpp',
'src/audiocurves/PercussiveAudioCurve.cpp',
'src/dsp/Resampler.cpp',
'src/dsp/FFT.cpp',
'src/system/Allocators.cpp',
'src/system/sysutils.cpp',
'src/system/Thread.cpp',
'src/StretcherChannelData.cpp',
'src/StretcherImpl.cpp',
'src/faster/AudioCurveCalculator.cpp',
'src/faster/CompoundAudioCurve.cpp',
'src/faster/HighFrequencyAudioCurve.cpp',
'src/faster/SilentAudioCurve.cpp',
'src/faster/PercussiveAudioCurve.cpp',
'src/faster/R2Stretcher.cpp',
'src/faster/StretcherChannelData.cpp',
'src/faster/StretcherProcess.cpp',
'src/common/Allocators.cpp',
'src/common/FFT.cpp',
'src/common/Log.cpp',
'src/common/Profiler.cpp',
'src/common/Resampler.cpp',
'src/common/StretchCalculator.cpp',
'src/common/sysutils.cpp',
'src/common/Thread.cpp',
'src/finer/R3Stretcher.cpp',
]
jni_sources = [
@@ -66,8 +67,8 @@ program_sources = [
if system == 'windows'
program_sources += [
'src/getopt/getopt.c',
'src/getopt/getopt_long.c'
'src/ext/getopt/getopt.c',
'src/ext/getopt/getopt_long.c'
]
endif
@@ -84,6 +85,19 @@ lv2_sources = [
'ladspa-lv2/libmain-lv2.cpp',
]
unit_test_sources = [
'src/test/TestAllocators.cpp',
'src/test/TestFFT.cpp',
'src/test/TestResampler.cpp',
'src/test/TestVectorOpsComplex.cpp',
'src/test/TestVectorOps.cpp',
'src/test/TestSignalBits.cpp',
'src/test/TestStretchCalculator.cpp',
'src/test/TestStretcher.cpp',
'src/test/TestBinClassifier.cpp',
'src/test/test.cpp',
]
general_include_dirs = [
'rubberband',
'src',
@@ -101,6 +115,7 @@ fftw3_dep = dependency('fftw3', version: '>= 3.0.0', required: false)
samplerate_dep = dependency('samplerate', version: '>= 0.1.8', required: false)
sndfile_dep = dependency('sndfile', version: '>= 1.0.16', required: false)
vamp_dep = dependency('vamp-sdk', version: '>= 2.9', required: false)
boost_unit_test_dep = dependency('boost', modules: ['unit_test_framework'], version: '>= 1.73', required: false)
thread_dep = dependency('threads')
have_ladspa = cpp.has_header('ladspa.h', args: extra_include_args)
have_lv2 = cpp.has_header('lv2.h', args: extra_include_args)
@@ -157,9 +172,9 @@ elif fft == 'kissfft'
if fftw3_dep.found()
message('(to use FFTW instead, reconfigure with -Dfft=fftw)')
endif
feature_sources += ['src/kissfft/kiss_fft.c', 'src/kissfft/kiss_fftr.c']
feature_sources += ['src/ext/kissfft/kiss_fft.c', 'src/ext/kissfft/kiss_fftr.c']
feature_defines += ['-DHAVE_KISSFFT']
general_include_dirs += 'src/kissfft'
general_include_dirs += 'src/ext/kissfft'
elif fft == 'fftw'
if fftw3_dep.found()
@@ -204,7 +219,7 @@ if resampler == 'builtin'
if samplerate_dep.found()
message('(to use libsamplerate instead, reconfigure with -Dresampler=libsamplerate)')
endif
library_sources += 'src/dsp/BQResampler.cpp'
library_sources += 'src/common/BQResampler.cpp'
feature_defines += ['-DUSE_BQRESAMPLER']
elif resampler == 'libsamplerate'
@@ -226,7 +241,7 @@ elif resampler == 'speex'
config_summary += { 'Resampler': 'Speex' }
message('For resampler: using Speex')
message('(consider libsamplerate if time-varying pitch shift is required)')
feature_sources += ['src/speex/resample.c']
feature_sources += ['src/ext/speex/resample.c']
feature_defines += ['-DUSE_SPEEX']
elif resampler == 'ipp'
@@ -313,6 +328,8 @@ if not sndfile_dep.found()
endif
have_sndfile = sndfile_dep.found()
have_boost_unit_test = boost_unit_test_dep.found()
# General platform and compiler expectations
@@ -427,18 +444,22 @@ if cpp.get_id() == 'msvc'
endif
rubberband_library_name = 'rubberband'
rubberband_program_name = 'rubberband-program'
rubberband_program_name_r3 = 'rubberband-program-r3'
rubberband_ladspa_name = 'ladspa-rubberband'
rubberband_lv2_name = 'lv2-rubberband'
rubberband_vamp_name = 'vamp-rubberband'
rubberband_jni_name = 'rubberband-jni'
unit_tests_name = 'tests'
else
rubberband_library_name = 'rubberband'
rubberband_dynamic_name = 'rubberband'
rubberband_program_name = 'rubberband'
rubberband_program_name_r3 = 'rubberband-r3'
rubberband_ladspa_name = 'ladspa-rubberband'
rubberband_lv2_name = 'lv2-rubberband'
rubberband_vamp_name = 'vamp-rubberband'
rubberband_jni_name = 'rubberband-jni'
unit_tests_name = 'tests'
endif
rubberband_objlib = static_library(
@@ -663,8 +684,8 @@ else
endif
if have_sndfile
target_summary += { 'Command-line utility': [ true, 'Name: ' + rubberband_program_name ] }
message('Will build command-line utility')
message('Will build command-line utilities')
target_summary += { 'Command-line utility (R2)': [ true, 'Name: ' + rubberband_program_name ] }
rubberband_program = executable(
rubberband_program_name,
program_sources,
@@ -682,9 +703,66 @@ if have_sndfile
],
install: true,
)
target_summary += { 'Command-line utility (R3)': [ true, 'Name: ' + rubberband_program_name_r3 ] }
rubberband_program_r3 = executable(
rubberband_program_name_r3,
program_sources,
include_directories: general_include_dirs,
cpp_args: general_compile_args,
c_args: general_compile_args,
link_args: [
arch_flags,
feature_libraries,
],
dependencies: [
rubberband_objlib_dep,
general_dependencies,
sndfile_dep,
],
install: true,
)
else
target_summary += { 'Command-line utility': false }
message('Not building command-line utility: libsndfile dependency not found')
message('Not building command-line utilities: libsndfile dependency not found')
target_summary += { 'Command-line utility (R2)': false }
target_summary += { 'Command-line utility (R3)': false }
endif
if have_boost_unit_test
target_summary += { 'Unit tests': [ true, 'Name: ' + unit_tests_name ] }
message('Will build unit tests: use "meson test -C <builddir>" to run them')
unit_tests = executable(
unit_tests_name,
unit_test_sources,
cpp_args: general_compile_args,
c_args: general_compile_args,
link_args: [
arch_flags,
feature_libraries,
],
dependencies: [
rubberband_objlib_dep,
general_dependencies,
boost_unit_test_dep,
],
install: false,
build_by_default: false
)
general_test_args = [ '--log_level=message' ]
test('Allocators',
unit_tests, args: [ '--run_test=TestAllocators', general_test_args ])
test('FFT',
unit_tests, args: [ '--run_test=TestFFT', general_test_args ])
test('Resampler',
unit_tests, args: [ '--run_test=TestResampler', general_test_args ])
test('VectorOps',
unit_tests, args: [ '--run_test=TestVectorOps', general_test_args ])
test('VectorOpsComplex',
unit_tests, args: [ '--run_test=TestVectorOpsComplex', general_test_args ])
test('SignalBits',
unit_tests, args: [ '--run_test=TestSignalBits', general_test_args ])
else
target_summary += { 'Unit tests': false }
message('Not building unit tests: boost_unit_test_framework dependency not found')
endif
pkg.generate(

View File

@@ -11,52 +11,39 @@ RUBBERBAND_JNI_FILES := \
$(RUBBERBAND_SRC_PATH)/jni/RubberBandStretcherJNI.cpp
RUBBERBAND_SRC_FILES := \
$(RUBBERBAND_SRC_PATH)/base/Profiler.cpp \
$(RUBBERBAND_SRC_PATH)/system/Thread.cpp \
$(RUBBERBAND_SRC_PATH)/system/Allocators.cpp \
$(RUBBERBAND_SRC_PATH)/system/sysutils.cpp \
$(RUBBERBAND_SRC_PATH)/system/VectorOpsComplex.cpp \
$(RUBBERBAND_SRC_PATH)/StretcherChannelData.cpp \
$(RUBBERBAND_SRC_PATH)/dsp/AudioCurveCalculator.cpp \
$(RUBBERBAND_SRC_PATH)/dsp/FFT.cpp \
$(RUBBERBAND_SRC_PATH)/dsp/Resampler.cpp \
$(RUBBERBAND_SRC_PATH)/audiocurves/SilentAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/audiocurves/CompoundAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/audiocurves/HighFrequencyAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/audiocurves/SpectralDifferenceAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/audiocurves/ConstantAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/audiocurves/PercussiveAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/StretcherImpl.cpp \
$(RUBBERBAND_SRC_PATH)/StretcherProcess.cpp \
$(RUBBERBAND_SRC_PATH)/StretchCalculator.cpp \
$(RUBBERBAND_SRC_PATH)/RubberBandStretcher.cpp \
$(RUBBERBAND_SRC_PATH)/rubberband-c.cpp \
$(RUBBERBAND_SRC_PATH)/speex/resample.c
$(RUBBERBAND_SRC_PATH)/RubberBandStretcher.cpp \
$(RUBBERBAND_SRC_PATH)/faster/AudioCurveCalculator.cpp \
$(RUBBERBAND_SRC_PATH)/faster/CompoundAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/faster/HighFrequencyAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/faster/SilentAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/faster/PercussiveAudioCurve.cpp \
$(RUBBERBAND_SRC_PATH)/faster/StretcherChannelData.cpp \
$(RUBBERBAND_SRC_PATH)/faster/StretcherImpl.cpp \
$(RUBBERBAND_SRC_PATH)/faster/StretcherProcess.cpp \
$(RUBBERBAND_SRC_PATH)/common/BQResampler.cpp \
$(RUBBERBAND_SRC_PATH)/common/Profiler.cpp \
$(RUBBERBAND_SRC_PATH)/common/Resampler.cpp \
$(RUBBERBAND_SRC_PATH)/common/FFT.cpp \
$(RUBBERBAND_SRC_PATH)/common/Allocators.cpp \
$(RUBBERBAND_SRC_PATH)/common/StretchCalculator.cpp \
$(RUBBERBAND_SRC_PATH)/common/sysutils.cpp \
$(RUBBERBAND_SRC_PATH)/common/Thread.cpp \
$(RUBBERBAND_SRC_PATH)/finer/R3StretcherImpl.cpp
LOCAL_SRC_FILES += \
$(RUBBERBAND_JNI_FILES) \
$(RUBBERBAND_SRC_FILES)
LOCAL_SRC_FILES += \
$(RUBBERBAND_SRC_PATH)/kissfft/kiss_fft.c \
$(RUBBERBAND_SRC_PATH)/kissfft/kiss_fftr.c
LOCAL_CFLAGS_DEBUG := \
-g \
-mfloat-abi=softfp \
-DWANT_TIMING \
-DFFT_MEASUREMENT
LOCAL_CFLAGS_RELEASE := \
-O3 \
-mfpu=neon \
-mfloat-abi=softfp \
-ffast-math \
-ftree-vectorize \
-freciprocal-math \
-fsingle-precision-constant \
-D__ARM_ARCH_7__ \
-DUSE_POMMIER_MATHFUN \
-DNO_TIMING \
-DNO_TIMING_COMPLETE_NOOP
@@ -64,9 +51,8 @@ LOCAL_CFLAGS := \
-Wall \
-I$(RUBBERBAND_PATH) \
-I$(RUBBERBAND_SRC_PATH) \
-DUSE_SPEEX \
-DUSE_KISSFFT \
-DPROCESS_SAMPLE_TYPE=float \
-DUSE_BQRESAMPLER \
-DUSE_BUILTIN_FFT \
-DLACK_POSIX_MEMALIGN \
-DUSE_OWN_ALIGNED_MALLOC \
-DLACK_SINCOS \

View File

@@ -1,16 +1,16 @@
CXX := clang++
CXX := clang++ -stdlib=libc++ -std=c++11
CC := clang
OPTFLAGS := -DNDEBUG -ffast-math -freciprocal-math -O3 -ftree-vectorize
OPTFLAGS := -DNDEBUG -ffast-math -O3 -ftree-vectorize
# For the device
ARCHFLAGS_DEV := -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -miphoneos-version-min=6 -stdlib=libc++ -arch armv7 -arch arm64 -fembed-bitcode
ARCHFLAGS_DEV := -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -miphoneos-version-min=6 -arch armv7 -arch arm64 -fembed-bitcode
# Or for the simulator
ARCHFLAGS_SIM := -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -miphoneos-version-min=6 -stdlib=libc++ -arch i386 -arch x86_64 -fembed-bitcode
ARCHFLAGS_SIM := -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -miphoneos-version-min=6 -arch x86_64 -fembed-bitcode
CXXFLAGS_ANY := $(OPTFLAGS) -I. -Isrc -Irubberband -DMALLOC_IS_ALIGNED -DHAVE_VDSP -DUSE_SPEEX -DUSE_POMMIER_MATHFUN -DNO_THREADING -DNO_THREAD_CHECKS -DNO_TIMING -DNO_TIMING_COMPLETE_NOOP -DNDEBUG
CXXFLAGS_ANY := $(OPTFLAGS) -I. -Isrc -Irubberband -DUSE_BQRESAMPLER -DHAVE_VDSP -DNO_THREAD_CHECKS -DUSE_PTHREADS -DNO_TIMING -DMALLOC_IS_ALIGNED -DNDEBUG
CXXFLAGS_DEV := $(ARCHFLAGS_DEV) $(CXXFLAGS_ANY)
CXXFLAGS_SIM := $(ARCHFLAGS_SIM) $(CXXFLAGS_ANY)
@@ -36,59 +36,27 @@ PUBLIC_INCLUDES := \
rubberband/rubberband-c.h \
rubberband/RubberBandStretcher.h
LIBRARY_INCLUDES := \
src/StretcherChannelData.h \
src/float_cast/float_cast.h \
src/StretcherImpl.h \
src/StretchCalculator.h \
src/base/Profiler.h \
src/base/RingBuffer.h \
src/base/Scavenger.h \
src/dsp/AudioCurveCalculator.h \
src/audiocurves/CompoundAudioCurve.h \
src/audiocurves/ConstantAudioCurve.h \
src/audiocurves/HighFrequencyAudioCurve.h \
src/audiocurves/PercussiveAudioCurve.h \
src/audiocurves/SilentAudioCurve.h \
src/audiocurves/SpectralDifferenceAudioCurve.h \
src/dsp/Resampler.h \
src/dsp/FFT.h \
src/dsp/MovingMedian.h \
src/dsp/SincWindow.h \
src/dsp/Window.h \
src/system/Allocators.h \
src/system/Thread.h \
src/system/VectorOps.h \
src/system/VectorOpsComplex.h \
src/system/sysutils.h
LIBRARY_SOURCES := \
src/rubberband-c.cpp \
src/RubberBandStretcher.cpp \
src/StretcherProcess.cpp \
src/StretchCalculator.cpp \
src/base/Profiler.cpp \
src/dsp/AudioCurveCalculator.cpp \
src/audiocurves/CompoundAudioCurve.cpp \
src/audiocurves/SpectralDifferenceAudioCurve.cpp \
src/audiocurves/HighFrequencyAudioCurve.cpp \
src/audiocurves/SilentAudioCurve.cpp \
src/audiocurves/ConstantAudioCurve.cpp \
src/audiocurves/PercussiveAudioCurve.cpp \
src/dsp/Resampler.cpp \
src/dsp/FFT.cpp \
src/system/Allocators.cpp \
src/system/sysutils.cpp \
src/system/Thread.cpp \
src/system/VectorOpsComplex.cpp \
src/StretcherChannelData.cpp \
src/StretcherImpl.cpp
# For Speex resampler -- comment these lines out if not specifying USE_SPEEX
LIBRARY_INCLUDES := $(LIBRARY_INCLUDES) \
src/speex/speex_resampler.h
LIBRARY_SOURCES := $(LIBRARY_SOURCES) \
src/speex/resample.c
src/faster/AudioCurveCalculator.cpp \
src/faster/CompoundAudioCurve.cpp \
src/faster/HighFrequencyAudioCurve.cpp \
src/faster/SilentAudioCurve.cpp \
src/faster/PercussiveAudioCurve.cpp \
src/faster/R2Stretcher.cpp \
src/faster/StretcherChannelData.cpp \
src/faster/StretcherProcess.cpp \
src/common/Allocators.cpp \
src/common/BQResampler.cpp \
src/common/FFT.cpp \
src/common/Log.cpp \
src/common/Profiler.cpp \
src/common/Resampler.cpp \
src/common/StretchCalculator.cpp \
src/common/sysutils.cpp \
src/common/Thread.cpp \
src/finer/R3Stretcher.cpp
LIBRARY_OBJECTS_DEV := $(LIBRARY_SOURCES:.cpp=.dev.o)
LIBRARY_OBJECTS_DEV := $(LIBRARY_OBJECTS_DEV:.c=.dev.o)

View File

@@ -1,12 +1,12 @@
CXX := g++
CXX := g++ -std=c++11
CC := gcc
OPTFLAGS := -DNDEBUG -ffast-math -O3 -ftree-vectorize
ARCHFLAGS :=
CXXFLAGS := -std=c++11 $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -DHAVE_LIBSAMPLERATE -DUSE_BUILTIN_FFT -DNO_THREAD_CHECKS -DUSE_PTHREADS -DNO_TIMING -DHAVE_POSIX_MEMALIGN -DNDEBUG
CXXFLAGS := $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -DUSE_BQRESAMPLER -DUSE_BUILTIN_FFT -DNO_THREAD_CHECKS -DUSE_PTHREADS -DNO_TIMING -DHAVE_POSIX_MEMALIGN -DNDEBUG
CFLAGS := $(ARCHFLAGS) $(OPTFLAGS)
@@ -25,51 +25,27 @@ PUBLIC_INCLUDES := \
rubberband/rubberband-c.h \
rubberband/RubberBandStretcher.h
LIBRARY_INCLUDES := \
src/StretcherChannelData.h \
src/float_cast/float_cast.h \
src/StretcherImpl.h \
src/StretchCalculator.h \
src/base/Profiler.h \
src/base/RingBuffer.h \
src/base/Scavenger.h \
src/dsp/AudioCurveCalculator.h \
src/audiocurves/CompoundAudioCurve.h \
src/audiocurves/ConstantAudioCurve.h \
src/audiocurves/HighFrequencyAudioCurve.h \
src/audiocurves/PercussiveAudioCurve.h \
src/audiocurves/SilentAudioCurve.h \
src/audiocurves/SpectralDifferenceAudioCurve.h \
src/dsp/Resampler.h \
src/dsp/FFT.h \
src/dsp/MovingMedian.h \
src/dsp/SincWindow.h \
src/dsp/Window.h \
src/system/Allocators.h \
src/system/Thread.h \
src/system/VectorOps.h \
src/system/sysutils.h
LIBRARY_SOURCES := \
src/rubberband-c.cpp \
src/RubberBandStretcher.cpp \
src/StretcherProcess.cpp \
src/StretchCalculator.cpp \
src/base/Profiler.cpp \
src/dsp/AudioCurveCalculator.cpp \
src/audiocurves/CompoundAudioCurve.cpp \
src/audiocurves/SpectralDifferenceAudioCurve.cpp \
src/audiocurves/HighFrequencyAudioCurve.cpp \
src/audiocurves/SilentAudioCurve.cpp \
src/audiocurves/ConstantAudioCurve.cpp \
src/audiocurves/PercussiveAudioCurve.cpp \
src/dsp/Resampler.cpp \
src/dsp/FFT.cpp \
src/system/Allocators.cpp \
src/system/sysutils.cpp \
src/system/Thread.cpp \
src/StretcherChannelData.cpp \
src/StretcherImpl.cpp
src/faster/AudioCurveCalculator.cpp \
src/faster/CompoundAudioCurve.cpp \
src/faster/HighFrequencyAudioCurve.cpp \
src/faster/SilentAudioCurve.cpp \
src/faster/PercussiveAudioCurve.cpp \
src/faster/R2Stretcher.cpp \
src/faster/StretcherChannelData.cpp \
src/faster/StretcherProcess.cpp \
src/common/Allocators.cpp \
src/common/BQResampler.cpp \
src/common/FFT.cpp \
src/common/Log.cpp \
src/common/Profiler.cpp \
src/common/Resampler.cpp \
src/common/StretchCalculator.cpp \
src/common/sysutils.cpp \
src/common/Thread.cpp \
src/finer/R3Stretcher.cpp
LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o)
LIBRARY_OBJECTS := $(LIBRARY_OBJECTS:.c=.o)
@@ -94,88 +70,138 @@ depend:
src/rubberband-c.o: rubberband/rubberband-c.h
src/rubberband-c.o: rubberband/RubberBandStretcher.h
src/RubberBandStretcher.o: src/StretcherImpl.h
src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h src/dsp/Window.h
src/RubberBandStretcher.o: src/dsp/SincWindow.h src/dsp/FFT.h
src/RubberBandStretcher.o: src/audiocurves/CompoundAudioCurve.h
src/RubberBandStretcher.o: src/dsp/AudioCurveCalculator.h
src/RubberBandStretcher.o: src/audiocurves/PercussiveAudioCurve.h
src/RubberBandStretcher.o: src/audiocurves/HighFrequencyAudioCurve.h
src/RubberBandStretcher.o: src/dsp/SampleFilter.h src/base/RingBuffer.h
src/RubberBandStretcher.o: src/base/Scavenger.h src/system/Thread.h
src/RubberBandStretcher.o: src/system/sysutils.h
src/StretcherProcess.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherProcess.o: src/dsp/Window.h src/dsp/SincWindow.h src/dsp/FFT.h
src/StretcherProcess.o: src/audiocurves/CompoundAudioCurve.h
src/StretcherProcess.o: src/dsp/AudioCurveCalculator.h
src/StretcherProcess.o: src/audiocurves/PercussiveAudioCurve.h
src/StretcherProcess.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherProcess.o: src/dsp/SampleFilter.h src/base/RingBuffer.h
src/StretcherProcess.o: src/base/Scavenger.h src/system/Thread.h
src/StretcherProcess.o: src/system/sysutils.h src/audiocurves/PercussiveAudioCurve.h
src/StretcherProcess.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherProcess.o: src/audiocurves/ConstantAudioCurve.h src/StretchCalculator.h
src/StretcherProcess.o: src/StretcherChannelData.h src/dsp/Resampler.h
src/StretcherProcess.o: src/base/Profiler.h src/system/VectorOps.h
src/StretcherProcess.o: src/system/sysutils.h
src/StretchCalculator.o: src/StretchCalculator.h src/system/sysutils.h
src/base/Profiler.o: src/base/Profiler.h src/system/sysutils.h
src/dsp/AudioCurveCalculator.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/CompoundAudioCurve.o: src/audiocurves/CompoundAudioCurve.h
src/audiocurves/CompoundAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/CompoundAudioCurve.o: src/audiocurves/PercussiveAudioCurve.h
src/audiocurves/CompoundAudioCurve.o: src/audiocurves/HighFrequencyAudioCurve.h
src/audiocurves/CompoundAudioCurve.o: src/dsp/SampleFilter.h src/dsp/MovingMedian.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/audiocurves/SpectralDifferenceAudioCurve.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/dsp/Window.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/sysutils.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/VectorOps.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/sysutils.h
src/audiocurves/HighFrequencyAudioCurve.o: src/audiocurves/HighFrequencyAudioCurve.h
src/audiocurves/HighFrequencyAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/SilentAudioCurve.o: src/audiocurves/SilentAudioCurve.h
src/audiocurves/SilentAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/ConstantAudioCurve.o: src/audiocurves/ConstantAudioCurve.h
src/audiocurves/ConstantAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/PercussiveAudioCurve.o: src/audiocurves/PercussiveAudioCurve.h
src/audiocurves/PercussiveAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/PercussiveAudioCurve.o: src/system/VectorOps.h src/system/sysutils.h
src/dsp/Resampler.o: src/dsp/Resampler.h src/system/sysutils.h
src/dsp/Resampler.o: src/base/Profiler.h
src/dsp/FFT.o: src/dsp/FFT.h src/system/sysutils.h src/system/Thread.h
src/dsp/FFT.o: src/base/Profiler.h src/system/VectorOps.h
src/dsp/FFT.o: src/system/sysutils.h
src/system/Allocators.o: src/system/Allocators.h src/system/VectorOps.h
src/system/Allocators.o: src/system/sysutils.h
src/system/sysutils.o: src/system/sysutils.h
src/system/Thread.o: src/system/Thread.h
src/StretcherChannelData.o: src/StretcherChannelData.h src/StretcherImpl.h
src/StretcherChannelData.o: rubberband/RubberBandStretcher.h src/dsp/Window.h
src/StretcherChannelData.o: src/dsp/SincWindow.h src/dsp/FFT.h
src/StretcherChannelData.o: src/audiocurves/CompoundAudioCurve.h
src/StretcherChannelData.o: src/dsp/AudioCurveCalculator.h
src/StretcherChannelData.o: src/audiocurves/PercussiveAudioCurve.h
src/StretcherChannelData.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherChannelData.o: src/dsp/SampleFilter.h src/base/RingBuffer.h
src/StretcherChannelData.o: src/base/Scavenger.h src/system/Thread.h
src/StretcherChannelData.o: src/system/sysutils.h src/dsp/Resampler.h
src/StretcherChannelData.o: src/system/Allocators.h src/system/VectorOps.h
src/StretcherChannelData.o: src/system/sysutils.h
src/StretcherImpl.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherImpl.o: src/dsp/Window.h src/dsp/SincWindow.h src/dsp/FFT.h
src/StretcherImpl.o: src/audiocurves/CompoundAudioCurve.h
src/StretcherImpl.o: src/dsp/AudioCurveCalculator.h
src/StretcherImpl.o: src/audiocurves/PercussiveAudioCurve.h
src/StretcherImpl.o: src/audiocurves/HighFrequencyAudioCurve.h src/dsp/SampleFilter.h
src/StretcherImpl.o: src/base/RingBuffer.h src/base/Scavenger.h
src/StretcherImpl.o: src/system/Thread.h src/system/sysutils.h
src/StretcherImpl.o: src/audiocurves/PercussiveAudioCurve.h
src/StretcherImpl.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherImpl.o: src/audiocurves/SpectralDifferenceAudioCurve.h src/dsp/Window.h
src/StretcherImpl.o: src/system/VectorOps.h src/system/sysutils.h
src/StretcherImpl.o: src/audiocurves/SilentAudioCurve.h src/audiocurves/ConstantAudioCurve.h
src/StretcherImpl.o: src/dsp/Resampler.h src/StretchCalculator.h
src/StretcherImpl.o: src/StretcherChannelData.h src/base/Profiler.h
main/main.o: rubberband/RubberBandStretcher.h src/system/sysutils.h
main/main.o: src/base/Profiler.h
src/RubberBandStretcher.o: src/faster/R2Stretcher.h
src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h
src/RubberBandStretcher.o: src/common/Window.h src/common/sysutils.h
src/RubberBandStretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/RubberBandStretcher.o: src/common/FFT.h src/common/RingBuffer.h
src/RubberBandStretcher.o: src/common/Scavenger.h src/common/Thread.h
src/RubberBandStretcher.o: src/common/Thread.h src/common/Log.h
src/RubberBandStretcher.o: src/common/sysutils.h src/faster/SincWindow.h
src/RubberBandStretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/RubberBandStretcher.o: src/faster/CompoundAudioCurve.h
src/RubberBandStretcher.o: src/faster/PercussiveAudioCurve.h
src/RubberBandStretcher.o: src/faster/AudioCurveCalculator.h
src/RubberBandStretcher.o: src/faster/HighFrequencyAudioCurve.h
src/RubberBandStretcher.o: src/common/SampleFilter.h src/finer/R3Stretcher.h
src/RubberBandStretcher.o: src/finer/BinSegmenter.h src/finer/BinClassifier.h
src/RubberBandStretcher.o: src/common/MovingMedian.h
src/RubberBandStretcher.o: src/common/SampleFilter.h src/common/FixedVector.h
src/RubberBandStretcher.o: src/common/SingleThreadRingBuffer.h
src/RubberBandStretcher.o: src/common/HistogramFilter.h src/common/mathmisc.h
src/RubberBandStretcher.o: src/finer/Guide.h src/finer/Peak.h
src/RubberBandStretcher.o: src/finer/PhaseAdvance.h
src/RubberBandStretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/RubberBandStretcher.o: src/common/Resampler.h src/common/FixedVector.h
src/RubberBandStretcher.o: src/common/VectorOpsComplex.h
src/faster/AudioCurveCalculator.o: src/faster/AudioCurveCalculator.h
src/faster/AudioCurveCalculator.o: src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/faster/CompoundAudioCurve.h
src/faster/CompoundAudioCurve.o: src/faster/PercussiveAudioCurve.h
src/faster/CompoundAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/CompoundAudioCurve.o: src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/faster/HighFrequencyAudioCurve.h
src/faster/CompoundAudioCurve.o: src/common/SampleFilter.h
src/faster/CompoundAudioCurve.o: src/common/MovingMedian.h
src/faster/CompoundAudioCurve.o: src/common/SampleFilter.h
src/faster/CompoundAudioCurve.o: src/common/FixedVector.h
src/faster/CompoundAudioCurve.o: src/common/Allocators.h
src/faster/CompoundAudioCurve.o: src/common/VectorOps.h src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/common/SingleThreadRingBuffer.h
src/faster/HighFrequencyAudioCurve.o: src/faster/HighFrequencyAudioCurve.h
src/faster/HighFrequencyAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/HighFrequencyAudioCurve.o: src/common/sysutils.h
src/faster/SilentAudioCurve.o: src/faster/SilentAudioCurve.h
src/faster/SilentAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/SilentAudioCurve.o: src/common/sysutils.h
src/faster/PercussiveAudioCurve.o: src/faster/PercussiveAudioCurve.h
src/faster/PercussiveAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/PercussiveAudioCurve.o: src/common/sysutils.h
src/faster/PercussiveAudioCurve.o: src/common/Allocators.h
src/faster/PercussiveAudioCurve.o: src/common/VectorOps.h
src/faster/R2Stretcher.o: src/faster/R2Stretcher.h
src/faster/R2Stretcher.o: rubberband/RubberBandStretcher.h
src/faster/R2Stretcher.o: src/common/Window.h src/common/sysutils.h
src/faster/R2Stretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/R2Stretcher.o: src/common/FFT.h src/common/RingBuffer.h
src/faster/R2Stretcher.o: src/common/Scavenger.h src/common/Thread.h
src/faster/R2Stretcher.o: src/common/Thread.h src/common/Log.h
src/faster/R2Stretcher.o: src/common/sysutils.h src/faster/SincWindow.h
src/faster/R2Stretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/R2Stretcher.o: src/faster/CompoundAudioCurve.h
src/faster/R2Stretcher.o: src/faster/PercussiveAudioCurve.h
src/faster/R2Stretcher.o: src/faster/AudioCurveCalculator.h
src/faster/R2Stretcher.o: src/faster/HighFrequencyAudioCurve.h
src/faster/R2Stretcher.o: src/common/SampleFilter.h
src/faster/R2Stretcher.o: src/faster/SilentAudioCurve.h
src/faster/R2Stretcher.o: src/faster/StretcherChannelData.h
src/faster/R2Stretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/faster/R2Stretcher.o: src/common/Resampler.h src/common/Profiler.h
src/faster/StretcherChannelData.o: src/faster/StretcherChannelData.h
src/faster/StretcherChannelData.o: src/faster/R2Stretcher.h
src/faster/StretcherChannelData.o: rubberband/RubberBandStretcher.h
src/faster/StretcherChannelData.o: src/common/Window.h src/common/sysutils.h
src/faster/StretcherChannelData.o: src/common/VectorOps.h
src/faster/StretcherChannelData.o: src/common/Allocators.h src/common/FFT.h
src/faster/StretcherChannelData.o: src/common/RingBuffer.h
src/faster/StretcherChannelData.o: src/common/Scavenger.h src/common/Thread.h
src/faster/StretcherChannelData.o: src/common/Thread.h src/common/Log.h
src/faster/StretcherChannelData.o: src/common/sysutils.h
src/faster/StretcherChannelData.o: src/faster/SincWindow.h
src/faster/StretcherChannelData.o: src/common/VectorOps.h
src/faster/StretcherChannelData.o: src/common/Allocators.h
src/faster/StretcherChannelData.o: src/faster/CompoundAudioCurve.h
src/faster/StretcherChannelData.o: src/faster/PercussiveAudioCurve.h
src/faster/StretcherChannelData.o: src/faster/AudioCurveCalculator.h
src/faster/StretcherChannelData.o: src/faster/HighFrequencyAudioCurve.h
src/faster/StretcherChannelData.o: src/common/SampleFilter.h
src/faster/StretcherChannelData.o: src/common/Resampler.h
src/faster/StretcherProcess.o: src/faster/R2Stretcher.h
src/faster/StretcherProcess.o: rubberband/RubberBandStretcher.h
src/faster/StretcherProcess.o: src/common/Window.h src/common/sysutils.h
src/faster/StretcherProcess.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/StretcherProcess.o: src/common/FFT.h src/common/RingBuffer.h
src/faster/StretcherProcess.o: src/common/Scavenger.h src/common/Thread.h
src/faster/StretcherProcess.o: src/common/Thread.h src/common/Log.h
src/faster/StretcherProcess.o: src/common/sysutils.h src/faster/SincWindow.h
src/faster/StretcherProcess.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/StretcherProcess.o: src/faster/CompoundAudioCurve.h
src/faster/StretcherProcess.o: src/faster/PercussiveAudioCurve.h
src/faster/StretcherProcess.o: src/faster/AudioCurveCalculator.h
src/faster/StretcherProcess.o: src/faster/HighFrequencyAudioCurve.h
src/faster/StretcherProcess.o: src/common/SampleFilter.h
src/faster/StretcherProcess.o: src/faster/StretcherChannelData.h
src/faster/StretcherProcess.o: src/common/StretchCalculator.h
src/faster/StretcherProcess.o: src/common/Log.h src/common/Resampler.h
src/faster/StretcherProcess.o: src/common/Profiler.h src/common/mathmisc.h
src/common/Allocators.o: src/common/Allocators.h src/common/VectorOps.h
src/common/Allocators.o: src/common/sysutils.h
src/common/BQResampler.o: src/common/BQResampler.h src/common/Allocators.h
src/common/BQResampler.o: src/common/VectorOps.h src/common/sysutils.h
src/common/FFT.o: src/common/FFT.h src/common/sysutils.h src/common/Thread.h
src/common/FFT.o: src/common/Profiler.h src/common/Allocators.h
src/common/FFT.o: src/common/VectorOps.h src/common/VectorOpsComplex.h
src/common/Log.o: src/common/Log.h
src/common/Profiler.o: src/common/Profiler.h src/common/sysutils.h
src/common/Profiler.o: src/common/Thread.h
src/common/Resampler.o: src/common/Resampler.h src/common/sysutils.h
src/common/Resampler.o: src/common/Allocators.h src/common/VectorOps.h
src/common/StretchCalculator.o: src/common/StretchCalculator.h
src/common/StretchCalculator.o: src/common/Log.h src/common/sysutils.h
src/common/sysutils.o: src/common/sysutils.h
src/common/Thread.o: src/common/Thread.h
src/finer/R3Stretcher.o: src/finer/R3Stretcher.h src/finer/BinSegmenter.h
src/finer/R3Stretcher.o: src/finer/BinClassifier.h src/common/Allocators.h
src/finer/R3Stretcher.o: src/common/MovingMedian.h src/common/SampleFilter.h
src/finer/R3Stretcher.o: src/common/FixedVector.h src/common/Allocators.h
src/finer/R3Stretcher.o: src/common/VectorOps.h src/common/sysutils.h
src/finer/R3Stretcher.o: src/common/SingleThreadRingBuffer.h
src/finer/R3Stretcher.o: src/common/RingBuffer.h src/common/HistogramFilter.h
src/finer/R3Stretcher.o: src/common/mathmisc.h src/finer/Guide.h
src/finer/R3Stretcher.o: src/common/Log.h src/finer/Peak.h
src/finer/R3Stretcher.o: src/finer/PhaseAdvance.h
src/finer/R3Stretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/finer/R3Stretcher.o: src/common/Resampler.h src/common/FFT.h
src/finer/R3Stretcher.o: src/common/FixedVector.h src/common/Window.h
src/finer/R3Stretcher.o: src/common/VectorOpsComplex.h
src/finer/R3Stretcher.o: rubberband/RubberBandStretcher.h

View File

@@ -1,12 +1,12 @@
CXX := clang++ -stdlib=libc++
CXX := clang++ -stdlib=libc++ -std=c++11
CC := clang
OPTFLAGS := -DNDEBUG -ffast-math -O3 -ftree-vectorize
ARCHFLAGS := -mmacosx-version-min=10.7
CXXFLAGS := $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -I/usr/local/include -DUSE_PTHREADS -DMALLOC_IS_ALIGNED -DHAVE_VDSP -DUSE_SPEEX -DNO_THREAD_CHECKS -DNO_TIMING
CXXFLAGS := $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -DUSE_BQRESAMPLER -DHAVE_VDSP -DNO_THREAD_CHECKS -DUSE_PTHREADS -DNO_TIMING -DMALLOC_IS_ALIGNED -DNDEBUG
CFLAGS := $(ARCHFLAGS) $(OPTFLAGS)
@@ -25,59 +25,27 @@ PUBLIC_INCLUDES := \
rubberband/rubberband-c.h \
rubberband/RubberBandStretcher.h
LIBRARY_INCLUDES := \
src/StretcherChannelData.h \
src/float_cast/float_cast.h \
src/StretcherImpl.h \
src/StretchCalculator.h \
src/base/Profiler.h \
src/base/RingBuffer.h \
src/base/Scavenger.h \
src/dsp/AudioCurveCalculator.h \
src/audiocurves/CompoundAudioCurve.h \
src/audiocurves/ConstantAudioCurve.h \
src/audiocurves/HighFrequencyAudioCurve.h \
src/audiocurves/PercussiveAudioCurve.h \
src/audiocurves/SilentAudioCurve.h \
src/audiocurves/SpectralDifferenceAudioCurve.h \
src/dsp/Resampler.h \
src/dsp/FFT.h \
src/dsp/MovingMedian.h \
src/dsp/SincWindow.h \
src/dsp/Window.h \
src/system/Allocators.h \
src/system/Thread.h \
src/system/VectorOps.h \
src/system/VectorOpsComplex.h \
src/system/sysutils.h
LIBRARY_SOURCES := \
src/rubberband-c.cpp \
src/RubberBandStretcher.cpp \
src/StretcherProcess.cpp \
src/StretchCalculator.cpp \
src/base/Profiler.cpp \
src/dsp/AudioCurveCalculator.cpp \
src/audiocurves/CompoundAudioCurve.cpp \
src/audiocurves/SpectralDifferenceAudioCurve.cpp \
src/audiocurves/HighFrequencyAudioCurve.cpp \
src/audiocurves/SilentAudioCurve.cpp \
src/audiocurves/ConstantAudioCurve.cpp \
src/audiocurves/PercussiveAudioCurve.cpp \
src/dsp/Resampler.cpp \
src/dsp/FFT.cpp \
src/system/Allocators.cpp \
src/system/sysutils.cpp \
src/system/Thread.cpp \
src/system/VectorOpsComplex.cpp \
src/StretcherChannelData.cpp \
src/StretcherImpl.cpp
# For Speex resampler -- comment these lines out if not specifying USE_SPEEX
LIBRARY_INCLUDES := $(LIBRARY_INCLUDES) \
src/speex/speex_resampler.h
LIBRARY_SOURCES := $(LIBRARY_SOURCES) \
src/speex/resample.c
src/faster/AudioCurveCalculator.cpp \
src/faster/CompoundAudioCurve.cpp \
src/faster/HighFrequencyAudioCurve.cpp \
src/faster/SilentAudioCurve.cpp \
src/faster/PercussiveAudioCurve.cpp \
src/faster/R2Stretcher.cpp \
src/faster/StretcherChannelData.cpp \
src/faster/StretcherProcess.cpp \
src/common/Allocators.cpp \
src/common/BQResampler.cpp \
src/common/FFT.cpp \
src/common/Log.cpp \
src/common/Profiler.cpp \
src/common/Resampler.cpp \
src/common/StretchCalculator.cpp \
src/common/sysutils.cpp \
src/common/Thread.cpp \
src/finer/R3Stretcher.cpp
LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o)
LIBRARY_OBJECTS := $(LIBRARY_OBJECTS:.c=.o)
@@ -103,71 +71,138 @@ depend:
src/rubberband-c.o: rubberband/rubberband-c.h
src/rubberband-c.o: rubberband/RubberBandStretcher.h
src/RubberBandStretcher.o: src/StretcherImpl.h
src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h src/dsp/Window.h
src/RubberBandStretcher.o: src/dsp/FFT.h src/base/RingBuffer.h
src/RubberBandStretcher.o: src/base/Scavenger.h src/system/Thread.h
src/RubberBandStretcher.o: src/system/Thread.h src/system/sysutils.h
src/StretcherProcess.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherProcess.o: src/dsp/Window.h src/dsp/FFT.h src/base/RingBuffer.h
src/StretcherProcess.o: src/base/Scavenger.h src/system/Thread.h
src/StretcherProcess.o: src/system/Thread.h src/system/sysutils.h
src/StretcherProcess.o: src/audiocurves/PercussiveAudioCurve.h
src/StretcherProcess.o: src/dsp/AudioCurveCalculator.h
src/StretcherProcess.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherProcess.o: src/audiocurves/ConstantAudioCurve.h src/StretchCalculator.h
src/StretcherProcess.o: src/StretcherChannelData.h src/dsp/Resampler.h
src/StretcherProcess.o: src/base/Profiler.h src/system/VectorOps.h
src/StretcherProcess.o: src/system/sysutils.h
src/StretchCalculator.o: src/StretchCalculator.h src/system/sysutils.h
src/system/Thread.o: src/system/Thread.h
src/base/Profiler.o: src/base/Profiler.h src/system/sysutils.h
src/dsp/AudioCurveCalculator.o: src/dsp/AudioCurveCalculator.h
src/dsp/AudioCurveCalculator.o: src/system/sysutils.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/audiocurves/SpectralDifferenceAudioCurve.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/sysutils.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/dsp/Window.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/VectorOps.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/sysutils.h
src/audiocurves/HighFrequencyAudioCurve.o: src/audiocurves/HighFrequencyAudioCurve.h
src/audiocurves/HighFrequencyAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/HighFrequencyAudioCurve.o: src/system/sysutils.h
src/audiocurves/SilentAudioCurve.o: src/audiocurves/SilentAudioCurve.h
src/audiocurves/SilentAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/SilentAudioCurve.o: src/system/sysutils.h
src/audiocurves/ConstantAudioCurve.o: src/audiocurves/ConstantAudioCurve.h
src/audiocurves/ConstantAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/ConstantAudioCurve.o: src/system/sysutils.h
src/audiocurves/PercussiveAudioCurve.o: src/audiocurves/PercussiveAudioCurve.h
src/audiocurves/PercussiveAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/PercussiveAudioCurve.o: src/system/sysutils.h src/system/VectorOps.h
src/audiocurves/PercussiveAudioCurve.o: src/system/sysutils.h
src/dsp/Resampler.o: src/dsp/Resampler.h src/system/sysutils.h
src/dsp/Resampler.o: src/base/Profiler.h
src/dsp/FFT.o: src/dsp/FFT.h src/system/sysutils.h src/system/Thread.h
src/dsp/FFT.o: src/base/Profiler.h src/system/VectorOps.h
src/dsp/FFT.o: src/system/sysutils.h
src/system/Allocators.o: src/system/Allocators.h src/system/VectorOps.h
src/system/Allocators.o: src/system/sysutils.h
src/system/sysutils.o: src/system/sysutils.h
src/StretcherChannelData.o: src/StretcherChannelData.h src/StretcherImpl.h
src/StretcherChannelData.o: rubberband/RubberBandStretcher.h src/dsp/Window.h
src/StretcherChannelData.o: src/dsp/FFT.h src/base/RingBuffer.h
src/StretcherChannelData.o: src/base/Scavenger.h src/system/Thread.h
src/StretcherChannelData.o: src/system/Thread.h src/system/sysutils.h
src/StretcherChannelData.o: src/dsp/Resampler.h src/system/Allocators.h
src/StretcherChannelData.o: src/system/VectorOps.h src/system/sysutils.h
src/StretcherImpl.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherImpl.o: src/dsp/Window.h src/dsp/FFT.h src/base/RingBuffer.h
src/StretcherImpl.o: src/base/Scavenger.h src/system/Thread.h src/system/Thread.h
src/StretcherImpl.o: src/system/sysutils.h src/audiocurves/PercussiveAudioCurve.h
src/StretcherImpl.o: src/dsp/AudioCurveCalculator.h
src/StretcherImpl.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherImpl.o: src/audiocurves/SpectralDifferenceAudioCurve.h src/dsp/Window.h
src/StretcherImpl.o: src/system/VectorOps.h src/system/sysutils.h
src/StretcherImpl.o: src/audiocurves/SilentAudioCurve.h src/audiocurves/ConstantAudioCurve.h
src/StretcherImpl.o: src/dsp/Resampler.h src/StretchCalculator.h
src/StretcherImpl.o: src/StretcherChannelData.h src/base/Profiler.h
main/main.o: rubberband/RubberBandStretcher.h src/system/sysutils.h
main/main.o: src/base/Profiler.h
src/RubberBandStretcher.o: src/faster/R2Stretcher.h
src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h
src/RubberBandStretcher.o: src/common/Window.h src/common/sysutils.h
src/RubberBandStretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/RubberBandStretcher.o: src/common/FFT.h src/common/RingBuffer.h
src/RubberBandStretcher.o: src/common/Scavenger.h src/common/Thread.h
src/RubberBandStretcher.o: src/common/Thread.h src/common/Log.h
src/RubberBandStretcher.o: src/common/sysutils.h src/faster/SincWindow.h
src/RubberBandStretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/RubberBandStretcher.o: src/faster/CompoundAudioCurve.h
src/RubberBandStretcher.o: src/faster/PercussiveAudioCurve.h
src/RubberBandStretcher.o: src/faster/AudioCurveCalculator.h
src/RubberBandStretcher.o: src/faster/HighFrequencyAudioCurve.h
src/RubberBandStretcher.o: src/common/SampleFilter.h src/finer/R3Stretcher.h
src/RubberBandStretcher.o: src/finer/BinSegmenter.h src/finer/BinClassifier.h
src/RubberBandStretcher.o: src/common/MovingMedian.h
src/RubberBandStretcher.o: src/common/SampleFilter.h src/common/FixedVector.h
src/RubberBandStretcher.o: src/common/SingleThreadRingBuffer.h
src/RubberBandStretcher.o: src/common/HistogramFilter.h src/common/mathmisc.h
src/RubberBandStretcher.o: src/finer/Guide.h src/finer/Peak.h
src/RubberBandStretcher.o: src/finer/PhaseAdvance.h
src/RubberBandStretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/RubberBandStretcher.o: src/common/Resampler.h src/common/FixedVector.h
src/RubberBandStretcher.o: src/common/VectorOpsComplex.h
src/faster/AudioCurveCalculator.o: src/faster/AudioCurveCalculator.h
src/faster/AudioCurveCalculator.o: src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/faster/CompoundAudioCurve.h
src/faster/CompoundAudioCurve.o: src/faster/PercussiveAudioCurve.h
src/faster/CompoundAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/CompoundAudioCurve.o: src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/faster/HighFrequencyAudioCurve.h
src/faster/CompoundAudioCurve.o: src/common/SampleFilter.h
src/faster/CompoundAudioCurve.o: src/common/MovingMedian.h
src/faster/CompoundAudioCurve.o: src/common/SampleFilter.h
src/faster/CompoundAudioCurve.o: src/common/FixedVector.h
src/faster/CompoundAudioCurve.o: src/common/Allocators.h
src/faster/CompoundAudioCurve.o: src/common/VectorOps.h src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/common/SingleThreadRingBuffer.h
src/faster/HighFrequencyAudioCurve.o: src/faster/HighFrequencyAudioCurve.h
src/faster/HighFrequencyAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/HighFrequencyAudioCurve.o: src/common/sysutils.h
src/faster/SilentAudioCurve.o: src/faster/SilentAudioCurve.h
src/faster/SilentAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/SilentAudioCurve.o: src/common/sysutils.h
src/faster/PercussiveAudioCurve.o: src/faster/PercussiveAudioCurve.h
src/faster/PercussiveAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/PercussiveAudioCurve.o: src/common/sysutils.h
src/faster/PercussiveAudioCurve.o: src/common/Allocators.h
src/faster/PercussiveAudioCurve.o: src/common/VectorOps.h
src/faster/R2Stretcher.o: src/faster/R2Stretcher.h
src/faster/R2Stretcher.o: rubberband/RubberBandStretcher.h
src/faster/R2Stretcher.o: src/common/Window.h src/common/sysutils.h
src/faster/R2Stretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/R2Stretcher.o: src/common/FFT.h src/common/RingBuffer.h
src/faster/R2Stretcher.o: src/common/Scavenger.h src/common/Thread.h
src/faster/R2Stretcher.o: src/common/Thread.h src/common/Log.h
src/faster/R2Stretcher.o: src/common/sysutils.h src/faster/SincWindow.h
src/faster/R2Stretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/R2Stretcher.o: src/faster/CompoundAudioCurve.h
src/faster/R2Stretcher.o: src/faster/PercussiveAudioCurve.h
src/faster/R2Stretcher.o: src/faster/AudioCurveCalculator.h
src/faster/R2Stretcher.o: src/faster/HighFrequencyAudioCurve.h
src/faster/R2Stretcher.o: src/common/SampleFilter.h
src/faster/R2Stretcher.o: src/faster/SilentAudioCurve.h
src/faster/R2Stretcher.o: src/faster/StretcherChannelData.h
src/faster/R2Stretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/faster/R2Stretcher.o: src/common/Resampler.h src/common/Profiler.h
src/faster/StretcherChannelData.o: src/faster/StretcherChannelData.h
src/faster/StretcherChannelData.o: src/faster/R2Stretcher.h
src/faster/StretcherChannelData.o: rubberband/RubberBandStretcher.h
src/faster/StretcherChannelData.o: src/common/Window.h src/common/sysutils.h
src/faster/StretcherChannelData.o: src/common/VectorOps.h
src/faster/StretcherChannelData.o: src/common/Allocators.h src/common/FFT.h
src/faster/StretcherChannelData.o: src/common/RingBuffer.h
src/faster/StretcherChannelData.o: src/common/Scavenger.h src/common/Thread.h
src/faster/StretcherChannelData.o: src/common/Thread.h src/common/Log.h
src/faster/StretcherChannelData.o: src/common/sysutils.h
src/faster/StretcherChannelData.o: src/faster/SincWindow.h
src/faster/StretcherChannelData.o: src/common/VectorOps.h
src/faster/StretcherChannelData.o: src/common/Allocators.h
src/faster/StretcherChannelData.o: src/faster/CompoundAudioCurve.h
src/faster/StretcherChannelData.o: src/faster/PercussiveAudioCurve.h
src/faster/StretcherChannelData.o: src/faster/AudioCurveCalculator.h
src/faster/StretcherChannelData.o: src/faster/HighFrequencyAudioCurve.h
src/faster/StretcherChannelData.o: src/common/SampleFilter.h
src/faster/StretcherChannelData.o: src/common/Resampler.h
src/faster/StretcherProcess.o: src/faster/R2Stretcher.h
src/faster/StretcherProcess.o: rubberband/RubberBandStretcher.h
src/faster/StretcherProcess.o: src/common/Window.h src/common/sysutils.h
src/faster/StretcherProcess.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/StretcherProcess.o: src/common/FFT.h src/common/RingBuffer.h
src/faster/StretcherProcess.o: src/common/Scavenger.h src/common/Thread.h
src/faster/StretcherProcess.o: src/common/Thread.h src/common/Log.h
src/faster/StretcherProcess.o: src/common/sysutils.h src/faster/SincWindow.h
src/faster/StretcherProcess.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/StretcherProcess.o: src/faster/CompoundAudioCurve.h
src/faster/StretcherProcess.o: src/faster/PercussiveAudioCurve.h
src/faster/StretcherProcess.o: src/faster/AudioCurveCalculator.h
src/faster/StretcherProcess.o: src/faster/HighFrequencyAudioCurve.h
src/faster/StretcherProcess.o: src/common/SampleFilter.h
src/faster/StretcherProcess.o: src/faster/StretcherChannelData.h
src/faster/StretcherProcess.o: src/common/StretchCalculator.h
src/faster/StretcherProcess.o: src/common/Log.h src/common/Resampler.h
src/faster/StretcherProcess.o: src/common/Profiler.h src/common/mathmisc.h
src/common/Allocators.o: src/common/Allocators.h src/common/VectorOps.h
src/common/Allocators.o: src/common/sysutils.h
src/common/BQResampler.o: src/common/BQResampler.h src/common/Allocators.h
src/common/BQResampler.o: src/common/VectorOps.h src/common/sysutils.h
src/common/FFT.o: src/common/FFT.h src/common/sysutils.h src/common/Thread.h
src/common/FFT.o: src/common/Profiler.h src/common/Allocators.h
src/common/FFT.o: src/common/VectorOps.h src/common/VectorOpsComplex.h
src/common/Log.o: src/common/Log.h
src/common/Profiler.o: src/common/Profiler.h src/common/sysutils.h
src/common/Profiler.o: src/common/Thread.h
src/common/Resampler.o: src/common/Resampler.h src/common/sysutils.h
src/common/Resampler.o: src/common/Allocators.h src/common/VectorOps.h
src/common/StretchCalculator.o: src/common/StretchCalculator.h
src/common/StretchCalculator.o: src/common/Log.h src/common/sysutils.h
src/common/sysutils.o: src/common/sysutils.h
src/common/Thread.o: src/common/Thread.h
src/finer/R3Stretcher.o: src/finer/R3Stretcher.h src/finer/BinSegmenter.h
src/finer/R3Stretcher.o: src/finer/BinClassifier.h src/common/Allocators.h
src/finer/R3Stretcher.o: src/common/MovingMedian.h src/common/SampleFilter.h
src/finer/R3Stretcher.o: src/common/FixedVector.h src/common/Allocators.h
src/finer/R3Stretcher.o: src/common/VectorOps.h src/common/sysutils.h
src/finer/R3Stretcher.o: src/common/SingleThreadRingBuffer.h
src/finer/R3Stretcher.o: src/common/RingBuffer.h src/common/HistogramFilter.h
src/finer/R3Stretcher.o: src/common/mathmisc.h src/finer/Guide.h
src/finer/R3Stretcher.o: src/common/Log.h src/finer/Peak.h
src/finer/R3Stretcher.o: src/finer/PhaseAdvance.h
src/finer/R3Stretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/finer/R3Stretcher.o: src/common/Resampler.h src/common/FFT.h
src/finer/R3Stretcher.o: src/common/FixedVector.h src/common/Window.h
src/finer/R3Stretcher.o: src/common/VectorOpsComplex.h
src/finer/R3Stretcher.o: rubberband/RubberBandStretcher.h

View File

@@ -1,12 +1,12 @@
CXX := clang++ -stdlib=libc++
CXX := clang++ -stdlib=libc++ -std=c++11
CC := clang
OPTFLAGS := -DNDEBUG -ffast-math -O3 -ftree-vectorize
ARCHFLAGS := -arch arm64 -arch x86_64 -mmacosx-version-min=10.7
CXXFLAGS := $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -I/usr/local/include -DUSE_PTHREADS -DMALLOC_IS_ALIGNED -DHAVE_VDSP -DUSE_SPEEX -DNO_THREAD_CHECKS -DNO_TIMING
CXXFLAGS := $(ARCHFLAGS) $(OPTFLAGS) -I. -Isrc -Irubberband -DUSE_BQRESAMPLER -DHAVE_VDSP -DNO_THREAD_CHECKS -DUSE_PTHREADS -DNO_TIMING -DMALLOC_IS_ALIGNED -DNDEBUG
CFLAGS := $(ARCHFLAGS) $(OPTFLAGS)
@@ -18,68 +18,34 @@ LIBNAME := librubberband
STATIC_TARGET := lib/$(LIBNAME).a
default: $(STATIC_TARGET)
all: $(STATIC_TARGET)
static: $(STATIC_TARGET)
PUBLIC_INCLUDES := \
rubberband/rubberband-c.h \
rubberband/RubberBandStretcher.h
LIBRARY_INCLUDES := \
src/StretcherChannelData.h \
src/float_cast/float_cast.h \
src/StretcherImpl.h \
src/StretchCalculator.h \
src/base/Profiler.h \
src/base/RingBuffer.h \
src/base/Scavenger.h \
src/dsp/AudioCurveCalculator.h \
src/audiocurves/CompoundAudioCurve.h \
src/audiocurves/ConstantAudioCurve.h \
src/audiocurves/HighFrequencyAudioCurve.h \
src/audiocurves/PercussiveAudioCurve.h \
src/audiocurves/SilentAudioCurve.h \
src/audiocurves/SpectralDifferenceAudioCurve.h \
src/dsp/Resampler.h \
src/dsp/FFT.h \
src/dsp/MovingMedian.h \
src/dsp/SincWindow.h \
src/dsp/Window.h \
src/system/Allocators.h \
src/system/Thread.h \
src/system/VectorOps.h \
src/system/VectorOpsComplex.h \
src/system/sysutils.h
LIBRARY_SOURCES := \
src/rubberband-c.cpp \
src/RubberBandStretcher.cpp \
src/StretcherProcess.cpp \
src/StretchCalculator.cpp \
src/base/Profiler.cpp \
src/dsp/AudioCurveCalculator.cpp \
src/audiocurves/CompoundAudioCurve.cpp \
src/audiocurves/SpectralDifferenceAudioCurve.cpp \
src/audiocurves/HighFrequencyAudioCurve.cpp \
src/audiocurves/SilentAudioCurve.cpp \
src/audiocurves/ConstantAudioCurve.cpp \
src/audiocurves/PercussiveAudioCurve.cpp \
src/dsp/Resampler.cpp \
src/dsp/FFT.cpp \
src/system/Allocators.cpp \
src/system/sysutils.cpp \
src/system/Thread.cpp \
src/system/VectorOpsComplex.cpp \
src/StretcherChannelData.cpp \
src/StretcherImpl.cpp
# For Speex resampler -- comment these lines out if not specifying USE_SPEEX
LIBRARY_INCLUDES := $(LIBRARY_INCLUDES) \
src/speex/speex_resampler.h
LIBRARY_SOURCES := $(LIBRARY_SOURCES) \
src/speex/resample.c
src/faster/AudioCurveCalculator.cpp \
src/faster/CompoundAudioCurve.cpp \
src/faster/HighFrequencyAudioCurve.cpp \
src/faster/SilentAudioCurve.cpp \
src/faster/PercussiveAudioCurve.cpp \
src/faster/R2Stretcher.cpp \
src/faster/StretcherChannelData.cpp \
src/faster/StretcherProcess.cpp \
src/common/Allocators.cpp \
src/common/BQResampler.cpp \
src/common/FFT.cpp \
src/common/Log.cpp \
src/common/Profiler.cpp \
src/common/Resampler.cpp \
src/common/StretchCalculator.cpp \
src/common/sysutils.cpp \
src/common/Thread.cpp \
src/finer/R3Stretcher.cpp
LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o)
LIBRARY_OBJECTS := $(LIBRARY_OBJECTS:.c=.o)
@@ -105,71 +71,138 @@ depend:
src/rubberband-c.o: rubberband/rubberband-c.h
src/rubberband-c.o: rubberband/RubberBandStretcher.h
src/RubberBandStretcher.o: src/StretcherImpl.h
src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h src/dsp/Window.h
src/RubberBandStretcher.o: src/dsp/FFT.h src/base/RingBuffer.h
src/RubberBandStretcher.o: src/base/Scavenger.h src/system/Thread.h
src/RubberBandStretcher.o: src/system/Thread.h src/system/sysutils.h
src/StretcherProcess.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherProcess.o: src/dsp/Window.h src/dsp/FFT.h src/base/RingBuffer.h
src/StretcherProcess.o: src/base/Scavenger.h src/system/Thread.h
src/StretcherProcess.o: src/system/Thread.h src/system/sysutils.h
src/StretcherProcess.o: src/audiocurves/PercussiveAudioCurve.h
src/StretcherProcess.o: src/dsp/AudioCurveCalculator.h
src/StretcherProcess.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherProcess.o: src/audiocurves/ConstantAudioCurve.h src/StretchCalculator.h
src/StretcherProcess.o: src/StretcherChannelData.h src/dsp/Resampler.h
src/StretcherProcess.o: src/base/Profiler.h src/system/VectorOps.h
src/StretcherProcess.o: src/system/sysutils.h
src/StretchCalculator.o: src/StretchCalculator.h src/system/sysutils.h
src/system/Thread.o: src/system/Thread.h
src/base/Profiler.o: src/base/Profiler.h src/system/sysutils.h
src/dsp/AudioCurveCalculator.o: src/dsp/AudioCurveCalculator.h
src/dsp/AudioCurveCalculator.o: src/system/sysutils.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/audiocurves/SpectralDifferenceAudioCurve.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/sysutils.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/dsp/Window.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/VectorOps.h
src/audiocurves/SpectralDifferenceAudioCurve.o: src/system/sysutils.h
src/audiocurves/HighFrequencyAudioCurve.o: src/audiocurves/HighFrequencyAudioCurve.h
src/audiocurves/HighFrequencyAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/HighFrequencyAudioCurve.o: src/system/sysutils.h
src/audiocurves/SilentAudioCurve.o: src/audiocurves/SilentAudioCurve.h
src/audiocurves/SilentAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/SilentAudioCurve.o: src/system/sysutils.h
src/audiocurves/ConstantAudioCurve.o: src/audiocurves/ConstantAudioCurve.h
src/audiocurves/ConstantAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/ConstantAudioCurve.o: src/system/sysutils.h
src/audiocurves/PercussiveAudioCurve.o: src/audiocurves/PercussiveAudioCurve.h
src/audiocurves/PercussiveAudioCurve.o: src/dsp/AudioCurveCalculator.h
src/audiocurves/PercussiveAudioCurve.o: src/system/sysutils.h src/system/VectorOps.h
src/audiocurves/PercussiveAudioCurve.o: src/system/sysutils.h
src/dsp/Resampler.o: src/dsp/Resampler.h src/system/sysutils.h
src/dsp/Resampler.o: src/base/Profiler.h
src/dsp/FFT.o: src/dsp/FFT.h src/system/sysutils.h src/system/Thread.h
src/dsp/FFT.o: src/base/Profiler.h src/system/VectorOps.h
src/dsp/FFT.o: src/system/sysutils.h
src/system/Allocators.o: src/system/Allocators.h src/system/VectorOps.h
src/system/Allocators.o: src/system/sysutils.h
src/system/sysutils.o: src/system/sysutils.h
src/StretcherChannelData.o: src/StretcherChannelData.h src/StretcherImpl.h
src/StretcherChannelData.o: rubberband/RubberBandStretcher.h src/dsp/Window.h
src/StretcherChannelData.o: src/dsp/FFT.h src/base/RingBuffer.h
src/StretcherChannelData.o: src/base/Scavenger.h src/system/Thread.h
src/StretcherChannelData.o: src/system/Thread.h src/system/sysutils.h
src/StretcherChannelData.o: src/dsp/Resampler.h src/system/Allocators.h
src/StretcherChannelData.o: src/system/VectorOps.h src/system/sysutils.h
src/StretcherImpl.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherImpl.o: src/dsp/Window.h src/dsp/FFT.h src/base/RingBuffer.h
src/StretcherImpl.o: src/base/Scavenger.h src/system/Thread.h src/system/Thread.h
src/StretcherImpl.o: src/system/sysutils.h src/audiocurves/PercussiveAudioCurve.h
src/StretcherImpl.o: src/dsp/AudioCurveCalculator.h
src/StretcherImpl.o: src/audiocurves/HighFrequencyAudioCurve.h
src/StretcherImpl.o: src/audiocurves/SpectralDifferenceAudioCurve.h src/dsp/Window.h
src/StretcherImpl.o: src/system/VectorOps.h src/system/sysutils.h
src/StretcherImpl.o: src/audiocurves/SilentAudioCurve.h src/audiocurves/ConstantAudioCurve.h
src/StretcherImpl.o: src/dsp/Resampler.h src/StretchCalculator.h
src/StretcherImpl.o: src/StretcherChannelData.h src/base/Profiler.h
main/main.o: rubberband/RubberBandStretcher.h src/system/sysutils.h
main/main.o: src/base/Profiler.h
src/RubberBandStretcher.o: src/faster/R2Stretcher.h
src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h
src/RubberBandStretcher.o: src/common/Window.h src/common/sysutils.h
src/RubberBandStretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/RubberBandStretcher.o: src/common/FFT.h src/common/RingBuffer.h
src/RubberBandStretcher.o: src/common/Scavenger.h src/common/Thread.h
src/RubberBandStretcher.o: src/common/Thread.h src/common/Log.h
src/RubberBandStretcher.o: src/common/sysutils.h src/faster/SincWindow.h
src/RubberBandStretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/RubberBandStretcher.o: src/faster/CompoundAudioCurve.h
src/RubberBandStretcher.o: src/faster/PercussiveAudioCurve.h
src/RubberBandStretcher.o: src/faster/AudioCurveCalculator.h
src/RubberBandStretcher.o: src/faster/HighFrequencyAudioCurve.h
src/RubberBandStretcher.o: src/common/SampleFilter.h src/finer/R3Stretcher.h
src/RubberBandStretcher.o: src/finer/BinSegmenter.h src/finer/BinClassifier.h
src/RubberBandStretcher.o: src/common/MovingMedian.h
src/RubberBandStretcher.o: src/common/SampleFilter.h src/common/FixedVector.h
src/RubberBandStretcher.o: src/common/SingleThreadRingBuffer.h
src/RubberBandStretcher.o: src/common/HistogramFilter.h src/common/mathmisc.h
src/RubberBandStretcher.o: src/finer/Guide.h src/finer/Peak.h
src/RubberBandStretcher.o: src/finer/PhaseAdvance.h
src/RubberBandStretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/RubberBandStretcher.o: src/common/Resampler.h src/common/FixedVector.h
src/RubberBandStretcher.o: src/common/VectorOpsComplex.h
src/faster/AudioCurveCalculator.o: src/faster/AudioCurveCalculator.h
src/faster/AudioCurveCalculator.o: src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/faster/CompoundAudioCurve.h
src/faster/CompoundAudioCurve.o: src/faster/PercussiveAudioCurve.h
src/faster/CompoundAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/CompoundAudioCurve.o: src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/faster/HighFrequencyAudioCurve.h
src/faster/CompoundAudioCurve.o: src/common/SampleFilter.h
src/faster/CompoundAudioCurve.o: src/common/MovingMedian.h
src/faster/CompoundAudioCurve.o: src/common/SampleFilter.h
src/faster/CompoundAudioCurve.o: src/common/FixedVector.h
src/faster/CompoundAudioCurve.o: src/common/Allocators.h
src/faster/CompoundAudioCurve.o: src/common/VectorOps.h src/common/sysutils.h
src/faster/CompoundAudioCurve.o: src/common/SingleThreadRingBuffer.h
src/faster/HighFrequencyAudioCurve.o: src/faster/HighFrequencyAudioCurve.h
src/faster/HighFrequencyAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/HighFrequencyAudioCurve.o: src/common/sysutils.h
src/faster/SilentAudioCurve.o: src/faster/SilentAudioCurve.h
src/faster/SilentAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/SilentAudioCurve.o: src/common/sysutils.h
src/faster/PercussiveAudioCurve.o: src/faster/PercussiveAudioCurve.h
src/faster/PercussiveAudioCurve.o: src/faster/AudioCurveCalculator.h
src/faster/PercussiveAudioCurve.o: src/common/sysutils.h
src/faster/PercussiveAudioCurve.o: src/common/Allocators.h
src/faster/PercussiveAudioCurve.o: src/common/VectorOps.h
src/faster/R2Stretcher.o: src/faster/R2Stretcher.h
src/faster/R2Stretcher.o: rubberband/RubberBandStretcher.h
src/faster/R2Stretcher.o: src/common/Window.h src/common/sysutils.h
src/faster/R2Stretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/R2Stretcher.o: src/common/FFT.h src/common/RingBuffer.h
src/faster/R2Stretcher.o: src/common/Scavenger.h src/common/Thread.h
src/faster/R2Stretcher.o: src/common/Thread.h src/common/Log.h
src/faster/R2Stretcher.o: src/common/sysutils.h src/faster/SincWindow.h
src/faster/R2Stretcher.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/R2Stretcher.o: src/faster/CompoundAudioCurve.h
src/faster/R2Stretcher.o: src/faster/PercussiveAudioCurve.h
src/faster/R2Stretcher.o: src/faster/AudioCurveCalculator.h
src/faster/R2Stretcher.o: src/faster/HighFrequencyAudioCurve.h
src/faster/R2Stretcher.o: src/common/SampleFilter.h
src/faster/R2Stretcher.o: src/faster/SilentAudioCurve.h
src/faster/R2Stretcher.o: src/faster/StretcherChannelData.h
src/faster/R2Stretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/faster/R2Stretcher.o: src/common/Resampler.h src/common/Profiler.h
src/faster/StretcherChannelData.o: src/faster/StretcherChannelData.h
src/faster/StretcherChannelData.o: src/faster/R2Stretcher.h
src/faster/StretcherChannelData.o: rubberband/RubberBandStretcher.h
src/faster/StretcherChannelData.o: src/common/Window.h src/common/sysutils.h
src/faster/StretcherChannelData.o: src/common/VectorOps.h
src/faster/StretcherChannelData.o: src/common/Allocators.h src/common/FFT.h
src/faster/StretcherChannelData.o: src/common/RingBuffer.h
src/faster/StretcherChannelData.o: src/common/Scavenger.h src/common/Thread.h
src/faster/StretcherChannelData.o: src/common/Thread.h src/common/Log.h
src/faster/StretcherChannelData.o: src/common/sysutils.h
src/faster/StretcherChannelData.o: src/faster/SincWindow.h
src/faster/StretcherChannelData.o: src/common/VectorOps.h
src/faster/StretcherChannelData.o: src/common/Allocators.h
src/faster/StretcherChannelData.o: src/faster/CompoundAudioCurve.h
src/faster/StretcherChannelData.o: src/faster/PercussiveAudioCurve.h
src/faster/StretcherChannelData.o: src/faster/AudioCurveCalculator.h
src/faster/StretcherChannelData.o: src/faster/HighFrequencyAudioCurve.h
src/faster/StretcherChannelData.o: src/common/SampleFilter.h
src/faster/StretcherChannelData.o: src/common/Resampler.h
src/faster/StretcherProcess.o: src/faster/R2Stretcher.h
src/faster/StretcherProcess.o: rubberband/RubberBandStretcher.h
src/faster/StretcherProcess.o: src/common/Window.h src/common/sysutils.h
src/faster/StretcherProcess.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/StretcherProcess.o: src/common/FFT.h src/common/RingBuffer.h
src/faster/StretcherProcess.o: src/common/Scavenger.h src/common/Thread.h
src/faster/StretcherProcess.o: src/common/Thread.h src/common/Log.h
src/faster/StretcherProcess.o: src/common/sysutils.h src/faster/SincWindow.h
src/faster/StretcherProcess.o: src/common/VectorOps.h src/common/Allocators.h
src/faster/StretcherProcess.o: src/faster/CompoundAudioCurve.h
src/faster/StretcherProcess.o: src/faster/PercussiveAudioCurve.h
src/faster/StretcherProcess.o: src/faster/AudioCurveCalculator.h
src/faster/StretcherProcess.o: src/faster/HighFrequencyAudioCurve.h
src/faster/StretcherProcess.o: src/common/SampleFilter.h
src/faster/StretcherProcess.o: src/faster/StretcherChannelData.h
src/faster/StretcherProcess.o: src/common/StretchCalculator.h
src/faster/StretcherProcess.o: src/common/Log.h src/common/Resampler.h
src/faster/StretcherProcess.o: src/common/Profiler.h src/common/mathmisc.h
src/common/Allocators.o: src/common/Allocators.h src/common/VectorOps.h
src/common/Allocators.o: src/common/sysutils.h
src/common/BQResampler.o: src/common/BQResampler.h src/common/Allocators.h
src/common/BQResampler.o: src/common/VectorOps.h src/common/sysutils.h
src/common/FFT.o: src/common/FFT.h src/common/sysutils.h src/common/Thread.h
src/common/FFT.o: src/common/Profiler.h src/common/Allocators.h
src/common/FFT.o: src/common/VectorOps.h src/common/VectorOpsComplex.h
src/common/Log.o: src/common/Log.h
src/common/Profiler.o: src/common/Profiler.h src/common/sysutils.h
src/common/Profiler.o: src/common/Thread.h
src/common/Resampler.o: src/common/Resampler.h src/common/sysutils.h
src/common/Resampler.o: src/common/Allocators.h src/common/VectorOps.h
src/common/StretchCalculator.o: src/common/StretchCalculator.h
src/common/StretchCalculator.o: src/common/Log.h src/common/sysutils.h
src/common/sysutils.o: src/common/sysutils.h
src/common/Thread.o: src/common/Thread.h
src/finer/R3Stretcher.o: src/finer/R3Stretcher.h src/finer/BinSegmenter.h
src/finer/R3Stretcher.o: src/finer/BinClassifier.h src/common/Allocators.h
src/finer/R3Stretcher.o: src/common/MovingMedian.h src/common/SampleFilter.h
src/finer/R3Stretcher.o: src/common/FixedVector.h src/common/Allocators.h
src/finer/R3Stretcher.o: src/common/VectorOps.h src/common/sysutils.h
src/finer/R3Stretcher.o: src/common/SingleThreadRingBuffer.h
src/finer/R3Stretcher.o: src/common/RingBuffer.h src/common/HistogramFilter.h
src/finer/R3Stretcher.o: src/common/mathmisc.h src/finer/Guide.h
src/finer/R3Stretcher.o: src/common/Log.h src/finer/Peak.h
src/finer/R3Stretcher.o: src/finer/PhaseAdvance.h
src/finer/R3Stretcher.o: src/common/StretchCalculator.h src/common/Log.h
src/finer/R3Stretcher.o: src/common/Resampler.h src/common/FFT.h
src/finer/R3Stretcher.o: src/common/FixedVector.h src/common/Window.h
src/finer/R3Stretcher.o: src/common/VectorOpsComplex.h
src/finer/R3Stretcher.o: rubberband/RubberBandStretcher.h

View File

@@ -5,17 +5,17 @@ if [ ! -d /Applications ]; then
# Assumed to be Linux
echo " *** Building static library using Linux-specific Makefile"
# make -f otherbuilds/Makefile.linux clean
make -f otherbuilds/Makefile.linux clean
make -f otherbuilds/Makefile.linux
echo " *** Linking against static library"
g++ main/main.cpp lib/librubberband.a -I. -Isrc -o test -lsndfile -lsamplerate -lpthread
g++ -std=c++11 main/main.cpp lib/librubberband.a -I. -Isrc -o test -lsndfile -lpthread
echo " *** Running build from Linux-specific Makefile"
./test -V
echo " *** Building with single-file source"
g++ main/main.cpp single/RubberBandSingle.cpp -o test_single -lsndfile
g++ -O3 -std=c++11 main/main.cpp single/RubberBandSingle.cpp -o test_single -lsndfile
echo " *** Running build from single-file source"
./test_single -V
@@ -29,13 +29,13 @@ else
make -f otherbuilds/Makefile.macos
echo " *** Linking against static library"
c++ main/main.cpp lib/librubberband.a -I. -Isrc -o test -lsndfile -lsamplerate -framework Accelerate
c++ -std=c++11 main/main.cpp lib/librubberband.a -I. -Isrc -o test -lsndfile -framework Accelerate
echo " *** Running build from macOS-specific Makefile"
./test -V
echo " *** Building with single-file source"
c++ main/main.cpp single/RubberBandSingle.cpp -o test_single -lsndfile -framework Accelerate
c++ -O3 -std=c++11 main/main.cpp single/RubberBandSingle.cpp -o test_single -lsndfile -framework Accelerate
echo " *** Running build from single-file source"
./test_single -V

View File

@@ -1,6 +1,6 @@
#!/bin/bash
set -eu
version=$(grep '^ *version:' meson.build | head -1 | sed "s/^.*'\([0-9][0-9.]*\)'.*$/\1/")
version=$(meson introspect --projectinfo meson.build -i | grep '"version"' | sed -e 's/^.*: "//' -e 's/".*$//')
check() {
text="$1"
echo -n "$text [yN] "
@@ -45,6 +45,15 @@ echo "The CHANGELOG should start with a list of changes for this release."
head -3 CHANGELOG
check "The first three lines of the CHANGELOG are above. Are they correct?"
hgid=$(hg id | awk '{ print $1; }')
case "$hgid" in
*+) echo "ERROR: Working copy has been modified, please review and commit"
echo "as appropriate before continuing"
exit 1
;;
*);;
esac
echo
check "All version checks passed. Continue?"

View File

@@ -34,6 +34,7 @@ if errorlevel 1 exit /b %errorlevel%
cd build
ren rubberband-program.exe rubberband.exe
ren rubberband-program-r3.exe rubberband-r3.exe
set NAME=Christopher Cannam
signtool sign /v /n "%NAME%" /t http://time.certum.pl /fd sha1 /a rubberband.exe
if errorlevel 1 exit /b %errorlevel%
@@ -43,6 +44,7 @@ set DIR=rubberband-%VERSION%-gpl-executable-windows
del /q /s %DIR%
mkdir %DIR%
copy build\rubberband.exe %DIR%
copy build\rubberband-r3.exe %DIR%
copy "c:\Program Files\libsndfile\bin\sndfile.dll" %DIR%
copy COPYING %DIR%\COPYING.txt
copy README.md %DIR%\README.txt

View File

@@ -77,7 +77,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_BQRESAMPLER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>true</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -91,7 +91,7 @@
<ClCompile>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_SPEEX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;_DEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;USE_BQRESAMPLER;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
<PrecompiledHeader>
@@ -109,7 +109,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_BQRESAMPLER;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -127,7 +127,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers>
<AdditionalIncludeDirectories>..;..\src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_SPEEX;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>__MSVC__;WIN32;NDEBUG;_LIB;NOMINMAX;_USE_MATH_DEFINES;USE_BUILTIN_FFT;NO_TIMING;USE_BQRESAMPLER;NO_THREAD_CHECKS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
<BufferSecurityCheck>false</BufferSecurityCheck>
<EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
@@ -139,55 +139,26 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\rubberband\rubberband-c.h" />
<ClInclude Include="..\rubberband\RubberBandStretcher.h" />
<ClInclude Include="..\src\audiocurves\CompoundAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\ConstantAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\HighFrequencyAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\PercussiveAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\SilentAudioCurve.h" />
<ClInclude Include="..\src\audiocurves\SpectralDifferenceAudioCurve.h" />
<ClInclude Include="..\src\base\Profiler.h" />
<ClInclude Include="..\src\base\RingBuffer.h" />
<ClInclude Include="..\src\base\Scavenger.h" />
<ClInclude Include="..\src\dsp\AudioCurveCalculator.h" />
<ClInclude Include="..\src\dsp\FFT.h" />
<ClInclude Include="..\src\dsp\MovingMedian.h" />
<ClInclude Include="..\src\dsp\Resampler.h" />
<ClInclude Include="..\src\dsp\SampleFilter.h" />
<ClInclude Include="..\src\dsp\SincWindow.h" />
<ClInclude Include="..\src\dsp\Window.h" />
<ClInclude Include="..\src\float_cast\float_cast.h" />
<ClInclude Include="..\src\speex\speex_resampler.h" />
<ClInclude Include="..\src\StretchCalculator.h" />
<ClInclude Include="..\src\StretcherChannelData.h" />
<ClInclude Include="..\src\StretcherImpl.h" />
<ClInclude Include="..\src\system\Allocators.h" />
<ClInclude Include="..\src\system\sysutils.h" />
<ClInclude Include="..\src\system\Thread.h" />
<ClInclude Include="..\src\system\VectorOps.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\audiocurves\CompoundAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\ConstantAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\HighFrequencyAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\PercussiveAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\SilentAudioCurve.cpp" />
<ClCompile Include="..\src\audiocurves\SpectralDifferenceAudioCurve.cpp" />
<ClCompile Include="..\src\base\Profiler.cpp" />
<ClCompile Include="..\src\dsp\AudioCurveCalculator.cpp" />
<ClCompile Include="..\src\dsp\FFT.cpp" />
<ClCompile Include="..\src\dsp\Resampler.cpp" />
<ClCompile Include="..\src\rubberband-c.cpp" />
<ClCompile Include="..\src\RubberBandStretcher.cpp" />
<ClCompile Include="..\src\speex\resample.c" />
<ClCompile Include="..\src\StretchCalculator.cpp" />
<ClCompile Include="..\src\StretcherChannelData.cpp" />
<ClCompile Include="..\src\StretcherImpl.cpp" />
<ClCompile Include="..\src\StretcherProcess.cpp" />
<ClCompile Include="..\src\system\Allocators.cpp" />
<ClCompile Include="..\src\system\sysutils.cpp" />
<ClCompile Include="..\src\system\Thread.cpp" />
<ClCompile Include="..\src\faster\AudioCurveCalculator.cpp" />
<ClCompile Include="..\src\faster\CompoundAudioCurve.cpp" />
<ClCompile Include="..\src\faster\HighFrequencyAudioCurve.cpp" />
<ClCompile Include="..\src\faster\SilentAudioCurve.cpp" />
<ClCompile Include="..\src\faster\PercussiveAudioCurve.cpp" />
<ClCompile Include="..\src\faster\StretcherChannelData.cpp" />
<ClCompile Include="..\src\faster\R2Stretcher.cpp" />
<ClCompile Include="..\src\faster\StretcherProcess.cpp" />
<ClCompile Include="..\src\common\BQResampler.cpp" />
<ClCompile Include="..\src\common\Profiler.cpp" />
<ClCompile Include="..\src\common\Resampler.cpp" />
<ClCompile Include="..\src\common\FFT.cpp" />
<ClCompile Include="..\src\common\Log.cpp" />
<ClCompile Include="..\src\common\Allocators.cpp" />
<ClCompile Include="..\src\common\StretchCalculator.cpp" />
<ClCompile Include="..\src\common\sysutils.cpp" />
<ClCompile Include="..\src\common\Thread.cpp" />
<ClCompile Include="..\src\finer\R3Stretcher.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -24,9 +24,9 @@
#ifndef RUBBERBAND_STRETCHER_H
#define RUBBERBAND_STRETCHER_H
#define RUBBERBAND_VERSION "2.0.2"
#define RUBBERBAND_VERSION "3.0.0"
#define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 6
#define RUBBERBAND_API_MINOR_VERSION 7
#undef RUBBERBAND_DLLEXPORT
#ifdef _MSC_VER
@@ -37,51 +37,89 @@
#include <vector>
#include <map>
#include <string>
#include <memory>
#include <cstddef>
/**
* @mainpage RubberBand
*
* The Rubber Band API is contained in the single class
* RubberBand::RubberBandStretcher.
*
* The Rubber Band stretcher supports two processing modes, offline
* and real-time. The choice of mode is fixed on construction. In
* offline mode, you must provide the audio block-by-block in two
* passes: in the first pass calling study(), in the second pass
* calling process() and receiving the output via retrieve(). In
* real-time mode, there is no study pass, just a single streaming
* pass in which the audio is passed to process() and output received
* via retrieve().
*
* In real-time mode you can change the time and pitch ratios at any
* time, but in offline mode they are fixed and cannot be changed
* after the study pass has begun. (However, see setKeyFrameMap() for
* a way to do pre-planned variable time stretching in offline mode.)
* Offline mode typically produces slightly more precise results.
*
* Threading notes for real-time applications:
*
* Multiple instances of RubberBandStretcher may be created and used
* in separate threads concurrently. However, for any single instance
* of RubberBandStretcher, you may not call process() more than once
* concurrently, and you may not change the time or pitch ratio while
* a process() call is being executed (if the stretcher was created in
* "real-time mode"; in "offline mode" you can't change the ratios
* during use anyway).
*
* So you can run process() in its own thread if you like, but if you
* want to change ratios dynamically from a different thread, you will
* need some form of mutex in your code. Changing the time or pitch
* ratio is real-time safe except in extreme circumstances, so for
* most applications that may change these dynamically it probably
* makes most sense to do so from the same thread as calls process(),
* even if that is a real-time thread.
*/
namespace RubberBand
{
/**
* @mainpage RubberBand
*
* ### Summary
*
* The Rubber Band Library API is contained in the single class
* RubberBand::RubberBandStretcher.
*
* The Rubber Band stretcher supports two processing modes, offline
* and real-time, and two processing "engines", known as the R2 or
* Faster engine and the R3 or Finer engine. The choices of processing
* mode and engine are fixed on construction: see
* RubberBandStretcher::RubberBandStretcher. The two engines work
* identically in API terms, and both of them support both offline and
* real-time modes as described below.
*
* ### Offline mode
*
* In offline mode, you must provide the audio block-by-block in
* two passes. In the first pass, call RubberBandStretcher::study() on
* each block; in the second pass, call RubberBandStretcher::process()
* on each block and receive the output via
* RubberBandStretcher::retrieve().
*
* In offline mode, the time and pitch ratios are fixed as soon as the
* study pass has begun and cannot be changed afterwards. (But see
* RubberBandStretcher::setKeyFrameMap() for a way to do pre-planned
* variable time stretching in offline mode.) Offline mode also
* performs latency compensation so that the stretched result has an
* exact start and duration.
*
* ### Real-time mode
*
* In \b real-time mode, there is no study pass, just a single
* streaming pass in which the audio is passed to
* RubberBandStretcher::process() and output received via
* RubberBandStretcher::retrieve().
*
* In real-time mode you can change the time and pitch ratios at any
* time.
*
* You may need to perform latency compensation in real-time mode; see
* RubberBandStretcher::getLatency() for details.
*
* Rubber Band Library is RT-safe when used in real-time mode with
* "normal" processing parameters. That is, it performs no allocation,
* locking, or blocking operations after initialisation during normal
* use, even when the time and pitch ratios change. There are certain
* exceptions that include error states and extremely rapid changes
* between extreme ratios, as well as the case in which more frames
* are passed to RubberBandStretcher::process() than the values
* returned by RubberBandStretcher::getSamplesRequired() or set using
* RubberBandStretcher::setMaxProcessSize(), when buffer reallocation
* may occur. See the latter function's documentation for
* details. Note that offline mode is never RT-safe.
*
* ### Thread safety
*
* Multiple instances of RubberBandStretcher may be created and used
* in separate threads concurrently. However, for any single instance
* of RubberBandStretcher, you may not call
* RubberBandStretcher::process() more than once concurrently, and you
* may not change the time or pitch ratio while a
* RubberBandStretcher::process() call is being executed (if the
* stretcher was created in "real-time mode"; in "offline mode" you
* can't change the ratios during use anyway).
*
* So you can run RubberBandStretcher::process() in its own thread if
* you like, but if you want to change ratios dynamically from a
* different thread, you will need some form of mutex in your code.
* Changing the time or pitch ratio is real-time safe except in
* extreme circumstances, so for most applications that may change
* these dynamically it probably makes most sense to do so from the
* same thread as calls RubberBandStretcher::process(), even if that
* is a real-time thread.
*/
class RUBBERBAND_DLLEXPORT
RubberBandStretcher
{
@@ -109,33 +147,43 @@ public:
* non-real-time operation on seekable files: Offline; real-time
* or streaming operation: RealTime.
*
* 2. Flags prefixed \c OptionStretch control the profile used for
* variable timestretching. Rubber Band always adjusts the
* stretch profile to minimise stretching of busy broadband
* transient sounds, but the degree to which it does so is
* adjustable. These options may not be changed after
* construction.
* 2. Flags prefixed \c OptionEngine select the core Rubber Band
* processing engine to be used. These options may not be changed
* after construction.
*
* \li \c OptionStretchElastic - Only meaningful in offline
* mode, and the default in that mode. The audio will be
* stretched at a variable rate, aimed at preserving the quality
* of transient sounds as much as possible. The timings of low
* activity regions between transients may be less exact than
* when the precise flag is set.
* \li \c OptionEngineFaster - Use the Rubber Band Library R2
* (Faster) engine. This is the engine implemented in Rubber
* Band Library v1.x and v2.x, and it remains the default in
* newer versions. It uses substantially less CPU than the R3
* engine and there are still many situations in which it is
* likely to be the more appropriate choice.
*
* \li \c OptionStretchPrecise - Although still using a variable
* stretch rate, the audio will be stretched so as to maintain
* as close as possible to a linear stretch ratio throughout.
* Timing may be better than when using \c OptionStretchElastic, at
* slight cost to the sound quality of transients. This setting
* is always used when running in real-time mode.
* \li \c OptionEngineFiner - Use the Rubber Band Library R3
* (Finer) engine. This engine was introduced in Rubber Band
* Library v3.0. It produces higher-quality results than the R2
* engine for most material, especially complex mixes, vocals
* and other sounds that have soft onsets and smooth pitch
* changes, and music with substantial bass content. However, it
* uses much more CPU power than the R2 engine.
*
* Important note: Consider calling getEngineVersion() after
* construction to make sure the engine you requested is
* active. That's not because engine selection can fail, but
* because Rubber Band Library ignores any unknown options
* supplied on construction - so a program that requests the R3
* engine but ends up linked against an older version of the
* library (prior to v3.0) will silently use the R2 engine
* instead. Calling the v3.0 function getEngineVersion() will
* ensure a link failure in this situation instead, and supply a
* reassuring run-time check.
*
* 3. Flags prefixed \c OptionTransients control the component
* frequency phase-reset mechanism that may be used at transient
* points to provide clarity and realism to percussion and other
* significant transient sounds. These options may be changed
* after construction when running in real-time mode, but not when
* running in offline mode.
* frequency phase-reset mechanism in the R2 engine, that may be
* used at transient points to provide clarity and realism to
* percussion and other significant transient sounds. These
* options have no effect when using the R3 engine. These options
* may be changed after construction when running in real-time
* mode, but not when running in offline mode.
*
* \li \c OptionTransientsCrisp - Reset component phases at the
* peak of each transient (the start of a significant note or
@@ -160,9 +208,10 @@ public:
* transients flags.
*
* 4. Flags prefixed \c OptionDetector control the type of
* transient detector used. These options may be changed
* after construction when running in real-time mode, but not when
* running in offline mode.
* transient detector used in the R2 engine. These options have
* no effect when using the R3 engine. These options may be
* changed after construction when running in real-time mode, but
* not when running in offline mode.
*
* \li \c OptionDetectorCompound - Use a general-purpose
* transient detector which is likely to be good for most
@@ -178,9 +227,10 @@ public:
* piano music).
*
* 5. Flags prefixed \c OptionPhase control the adjustment of
* component frequency phases from one analysis window to the next
* during non-transient segments. These options may be changed at
* any time.
* component frequency phases in the R2 engine from one analysis
* window to the next during non-transient segments. These
* options have no effect when using the R3 engine. These options
* may be changed at any time.
*
* \li \c OptionPhaseLaminar - Adjust phases when stretching in
* such a way as to try to retain the continuity of phase
@@ -197,11 +247,13 @@ public:
* construction.
*
* \li \c OptionThreadingAuto - Permit the stretcher to
* determine its own threading model. Usually this means using
* one processing thread per audio channel in offline mode if
* the stretcher is able to determine that more than one CPU is
* available, and one thread only in realtime mode. This is the
* default.
* determine its own threading model. In the R2 engine this
* means using one processing thread per audio channel in
* offline mode if the stretcher is able to determine that more
* than one CPU is available, and one thread only in realtime
* mode. The R3 engine does not currently have a multi-threaded
* mode, but if one is introduced in future, this option may use
* it. This is the default.
*
* \li \c OptionThreadingNever - Never use more than one thread.
*
@@ -210,9 +262,10 @@ public:
* the check for multiple CPUs and instead assume it to be true.
*
* 7. Flags prefixed \c OptionWindow control the window size for
* FFT processing. The window size actually used will depend on
* many factors, but it can be influenced. These options may not
* be changed after construction.
* FFT processing in the R2 engine. (The window size actually
* used will depend on many factors, but it can be influenced.)
* These options have no effect when using the R3 engine. These
* options may not be changed after construction.
*
* \li \c OptionWindowStandard - Use the default window size.
* The actual size will vary depending on other parameters.
@@ -228,8 +281,9 @@ public:
* clarity and timing.
*
* 8. Flags prefixed \c OptionSmoothing control the use of
* window-presum FFT and time-domain smoothing. These options may
* not be changed after construction.
* window-presum FFT and time-domain smoothing in the R2
* engine. These options have no effect when using the R3 engine.
* These options may not be changed after construction.
*
* \li \c OptionSmoothingOff - Do not use time-domain smoothing.
* This is the default.
@@ -242,7 +296,8 @@ public:
*
* 9. Flags prefixed \c OptionFormant control the handling of
* formant shape (spectral envelope) when pitch-shifting. These
* options may be changed at any time.
* options affect both the R2 and R3 engines. These options may
* be changed at any time.
*
* \li \c OptionFormantShifted - Apply no special formant
* processing. The spectral envelope will be pitch shifted as
@@ -254,9 +309,10 @@ public:
* perceived pitch profile of the voice or instrument.
*
* 10. Flags prefixed \c OptionPitch control the method used for
* pitch shifting. These options may be changed at any time.
* They are only effective in realtime mode; in offline mode, the
* pitch-shift method is fixed.
* pitch shifting in the R2 engine. These options have no effect
* when using the R3 engine. These options may be changed at any
* time. They are only effective in realtime mode; in offline
* mode, the pitch-shift method is fixed.
*
* \li \c OptionPitchHighSpeed - Use a method with a CPU cost
* that is relatively moderate and predictable. This may
@@ -274,9 +330,10 @@ public:
* 1.0 pitch scale in real-time; it also consumes more CPU than
* the others in the case where the pitch scale is exactly 1.0.
*
* 11. Flags prefixed \c OptionChannels control the method used for
* processing two-channel audio. These options may not be changed
* after construction.
* 11. Flags prefixed \c OptionChannels control the method used
* for processing two-channel audio in the R2 engine. These
* options have no effect when using the R3 engine. These options
* may not be changed after construction.
*
* \li \c OptionChannelsApart - Each channel is processed
* individually, though timing is synchronised and phases are
@@ -293,15 +350,18 @@ public:
* setting). This usually leads to better focus in the centre
* but a loss of stereo space and width. Any channels beyond
* the first two are processed individually.
*
* Finally, flags prefixed \c OptionStretch are obsolete flags
* provided for backward compatibility only. They are ignored by
* the stretcher.
*/
enum Option {
OptionProcessOffline = 0x00000000,
OptionProcessRealTime = 0x00000001,
OptionStretchElastic = 0x00000000,
OptionStretchPrecise = 0x00000010,
OptionStretchElastic = 0x00000000, // obsolete
OptionStretchPrecise = 0x00000010, // obsolete
OptionTransientsCrisp = 0x00000000,
OptionTransientsMixed = 0x00000100,
@@ -333,11 +393,18 @@ public:
OptionPitchHighConsistency = 0x04000000,
OptionChannelsApart = 0x00000000,
OptionChannelsTogether = 0x10000000
OptionChannelsTogether = 0x10000000,
OptionEngineFaster = 0x00000000,
OptionEngineFiner = 0x20000000
// n.b. Options is int, so we must stop before 0x80000000
};
/**
* A bitwise OR of values from the RubberBandStretcher::Option
* enum.
*/
typedef int Options;
enum PresetOption {
@@ -345,6 +412,37 @@ public:
PercussiveOptions = 0x00102000
};
/**
* Interface for log callbacks that may optionally be provided to
* the stretcher on construction.
*
* If a Logger is provided, the stretcher will call one of these
* functions instead of sending output to \c cerr when there is
* something to report. This allows debug output to be diverted to
* an application's logging facilities, and/or handled in an
* RT-safe way. See setDebugLevel() for details about how and when
* RubberBandStretcher reports something in this way.
*
* The message text passed to each of these log functions is a
* C-style string with no particular guaranteed lifespan. If you
* need to retain it, copy it before returning. Do not free it.
*
* @see setDebugLevel
* @see setDefaultDebugLevel
*/
struct Logger {
/// Receive a log message with no numeric values.
virtual void log(const char *) = 0;
/// Receive a log message and one accompanying numeric value.
virtual void log(const char *, double) = 0;
/// Receive a log message and two accompanying numeric values.
virtual void log(const char *, double, double) = 0;
virtual ~Logger() { }
};
/**
* Construct a time and pitch stretcher object to run at the given
* sample rate, with the given number of channels.
@@ -375,6 +473,30 @@ public:
Options options = DefaultOptions,
double initialTimeRatio = 1.0,
double initialPitchScale = 1.0);
/**
* Construct a time and pitch stretcher object with a custom debug
* logger. This may be useful for debugging if the default logger
* output (which simply goes to \c cerr) is not visible in the
* runtime environment, or if the application has a standard or
* more realtime-appropriate logging mechanism.
*
* See the documentation for the other constructor above for
* details of the arguments other than the logger.
*
* Note that although the supplied logger gets to decide what to
* do with log messages, the separately-set debug level (see
* setDebugLevel() and setDefaultDebugLevel()) still determines
* whether any given debug message is sent to the logger in the
* first place.
*/
RubberBandStretcher(size_t sampleRate,
size_t channels,
std::shared_ptr<Logger> logger,
Options options = DefaultOptions,
double initialTimeRatio = 1.0,
double initialPitchScale = 1.0);
~RubberBandStretcher();
/**
@@ -384,6 +506,15 @@ public:
*/
void reset();
/**
* Return the active internal engine version, according to the \c
* OptionEngine flag supplied on construction. This will return 2
* for the R2 (Faster) engine or 3 for the R3 (Finer) engine.
*
* This function was added in Rubber Band Library v3.0.
*/
int getEngineVersion() const;
/**
* Set the time ratio for the stretcher. This is the ratio of
* stretched to unstretched duration -- not tempo. For example, a
@@ -434,6 +565,36 @@ public:
*/
void setPitchScale(double scale);
/**
* Set a pitch scale for the vocal formant envelope separately
* from the overall pitch scale. This is a ratio of target
* frequency to source frequency. For example, a ratio of 2.0
* would shift the formant envelope up by one octave; 0.5 down by
* one octave; or 1.0 leave the formant unaffected.
*
* By default this is set to the special value of 0.0, which
* causes the scale to be calculated automatically. It will be
* treated as 1.0 / the pitch scale if OptionFormantPreserved is
* specified, or 1.0 for OptionFormantShifted.
*
* Conversely, if this is set to a value other than the default
* 0.0, formant shifting will happen regardless of the state of
* the OptionFormantPreserved/OptionFormantShifted option.
*
* This function is provided for special effects only. You do not
* need to call it for ordinary pitch shifting, with or without
* formant preservation - just specify or omit the
* OptionFormantPreserved option as appropriate. Use this function
* only if you want to shift formants by a distance other than
* that of the overall pitch shift.
*
* This function is supported only in the R3 (OptionEngineFiner)
* engine. It has no effect in R2 (OptionEngineFaster).
*
* This function was added in Rubber Band Library v3.0.
*/
void setFormantScale(double scale);
/**
* Return the last time ratio value that was set (either on
* construction or with setTimeRatio()).
@@ -446,6 +607,18 @@ public:
*/
double getPitchScale() const;
/**
* Return the last formant scaling ratio that was set with
* setFormantScale, or 0.0 if the default automatic scaling is in
* effect.
*
* This function is supported only in the R3 (OptionEngineFiner)
* engine. It always returns 0.0 in R2 (OptionEngineFaster).
*
* This function was added in Rubber Band Library v3.0.
*/
double getFormantScale() const;
/**
* Return the output delay or latency of the stretcher. This is
* the number of audio samples that one would have to discard at
@@ -466,11 +639,17 @@ public:
*/
size_t getLatency() const;
/**
* Return the number of channels this stretcher was constructed
* with.
*/
size_t getChannelCount() const;
/**
* Change an OptionTransients configuration setting. This may be
* called at any time in RealTime mode. It may not be called in
* Offline mode (for which the transients option is fixed on
* construction).
* construction). This has no effect when using the R3 engine.
*/
void setTransientsOption(Options options);
@@ -478,13 +657,14 @@ public:
* Change an OptionDetector configuration setting. This may be
* called at any time in RealTime mode. It may not be called in
* Offline mode (for which the detector option is fixed on
* construction).
* construction). This has no effect when using the R3 engine.
*/
void setDetectorOption(Options options);
/**
* Change an OptionPhase configuration setting. This may be
* called at any time in any mode.
* called at any time in any mode. This has no effect when using
* the R3 engine.
*
* Note that if running multi-threaded in Offline mode, the change
* may not take effect immediately if processing is already under
@@ -506,7 +686,7 @@ public:
* Change an OptionPitch configuration setting. This may be
* called at any time in RealTime mode. It may not be called in
* Offline mode (for which the pitch option is fixed on
* construction).
* construction). This has no effect when using the R3 engine.
*/
void setPitchOption(Options options);
@@ -711,7 +891,8 @@ public:
/**
* Retrieve the value of the internal input block increment value.
*
* This function is provided for diagnostic purposes only.
* This function is provided for diagnostic purposes only and
* supported only with the R2 engine.
*/
size_t getInputIncrement() const;
@@ -722,7 +903,8 @@ public:
* retrieve any output increments that have accumulated since the
* last call to getOutputIncrements, to a limit of 16.
*
* This function is provided for diagnostic purposes only.
* This function is provided for diagnostic purposes only and
* supported only with the R2 engine.
*/
std::vector<int> getOutputIncrements() const;
@@ -733,7 +915,8 @@ public:
* retrieve any phase reset points that have accumulated since the
* last call to getPhaseResetCurve, to a limit of 16.
*
* This function is provided for diagnostic purposes only.
* This function is provided for diagnostic purposes only and
* supported only with the R2 engine.
*/
std::vector<float> getPhaseResetCurve() const;
@@ -743,31 +926,52 @@ public:
* provided the stretch profile has been calculated. In realtime
* mode, return an empty sequence.
*
* This function is provided for diagnostic purposes only.
* This function is provided for diagnostic purposes only and
* supported only with the R2 engine.
*/
std::vector<int> getExactTimePoints() const;
/**
* Return the number of channels this stretcher was constructed
* with.
*/
size_t getChannelCount() const;
/**
* Force the stretcher to calculate a stretch profile. Normally
* this happens automatically for the first process() call in
* offline mode.
*
* This function is provided for diagnostic purposes only.
* This function is provided for diagnostic purposes only and
* supported only with the R2 engine.
*/
void calculateStretch();
/**
* Set the level of debug output. The value may be from 0 (errors
* only) to 3 (very verbose, with audible ticks in the output at
* phase reset points). The default is whatever has been set
* using setDefaultDebugLevel, or 0 if that function has not been
* Set the level of debug output. The supported values are:
*
* 0. Report errors only.
*
* 1. Report some information on construction and ratio
* change. Nothing is reported during normal processing unless
* something changes.
*
* 2. Report a significant amount of information about ongoing
* stretch calculations during normal processing.
*
* 3. Report a large amount of information and also (in the R2
* engine) add audible ticks to the output at phase reset
* points. This is seldom useful.
*
* The default is whatever has been set using
* setDefaultDebugLevel(), or 0 if that function has not been
* called.
*
* All output goes to \c cerr unless a custom
* RubberBandStretcher::Logger has been provided on
* construction. Because writing to \c cerr is not RT-safe, only
* debug level 0 is RT-safe in normal use by default. Debug levels
* 0 and 1 use only C-string constants as debug messages, so they
* are RT-safe if your custom logger is RT-safe. Levels 2 and 3
* are not guaranteed to be RT-safe in any conditions as they may
* construct messages by allocation.
*
* @see Logger
* @see setDefaultDebugLevel
*/
void setDebugLevel(int level);
@@ -782,6 +986,9 @@ public:
protected:
class Impl;
Impl *m_d;
RubberBandStretcher(const RubberBandStretcher &) =delete;
RubberBandStretcher &operator=(const RubberBandStretcher &) =delete;
};
}

View File

@@ -28,9 +28,9 @@
extern "C" {
#endif
#define RUBBERBAND_VERSION "2.0.2"
#define RUBBERBAND_VERSION "3.0.0"
#define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 6
#define RUBBERBAND_API_MINOR_VERSION 7
#undef RB_EXTERN
#ifdef _MSC_VER
@@ -57,8 +57,8 @@ enum RubberBandOption {
RubberBandOptionProcessOffline = 0x00000000,
RubberBandOptionProcessRealTime = 0x00000001,
RubberBandOptionStretchElastic = 0x00000000,
RubberBandOptionStretchPrecise = 0x00000010,
RubberBandOptionStretchElastic = 0x00000000, // obsolete
RubberBandOptionStretchPrecise = 0x00000010, // obsolete
RubberBandOptionTransientsCrisp = 0x00000000,
RubberBandOptionTransientsMixed = 0x00000100,
@@ -90,7 +90,10 @@ enum RubberBandOption {
RubberBandOptionPitchHighConsistency = 0x04000000,
RubberBandOptionChannelsApart = 0x00000000,
RubberBandOptionChannelsTogether = 0x10000000
RubberBandOptionChannelsTogether = 0x10000000,
RubberBandOptionEngineFaster = 0x00000000,
RubberBandOptionEngineFiner = 0x20000000
};
typedef int RubberBandOptions;
@@ -108,12 +111,17 @@ RB_EXTERN void rubberband_delete(RubberBandState);
RB_EXTERN void rubberband_reset(RubberBandState);
RB_EXTERN int rubberband_get_engine_version(RubberBandState);
RB_EXTERN void rubberband_set_time_ratio(RubberBandState, double ratio);
RB_EXTERN void rubberband_set_pitch_scale(RubberBandState, double scale);
RB_EXTERN double rubberband_get_time_ratio(const RubberBandState);
RB_EXTERN double rubberband_get_pitch_scale(const RubberBandState);
RB_EXTERN void rubberband_set_formant_scale(RubberBandState, double scale);
RB_EXTERN double rubberband_get_formant_scale(const RubberBandState);
RB_EXTERN unsigned int rubberband_get_latency(const RubberBandState);
RB_EXTERN void rubberband_set_transients_option(RubberBandState, RubberBandOptions options);

View File

@@ -56,25 +56,25 @@
#define USE_BUILTIN_FFT 1
#endif
#include "../src/audiocurves/CompoundAudioCurve.cpp"
#include "../src/audiocurves/SpectralDifferenceAudioCurve.cpp"
#include "../src/audiocurves/HighFrequencyAudioCurve.cpp"
#include "../src/audiocurves/SilentAudioCurve.cpp"
#include "../src/audiocurves/ConstantAudioCurve.cpp"
#include "../src/audiocurves/PercussiveAudioCurve.cpp"
#include "../src/base/Profiler.cpp"
#include "../src/dsp/AudioCurveCalculator.cpp"
#include "../src/dsp/FFT.cpp"
#include "../src/dsp/Resampler.cpp"
#include "../src/dsp/BQResampler.cpp"
#include "../src/system/Allocators.cpp"
#include "../src/system/sysutils.cpp"
#include "../src/system/Thread.cpp"
#include "../src/RubberBandStretcher.cpp"
#include "../src/StretchCalculator.cpp"
#include "../src/StretcherChannelData.cpp"
#include "../src/StretcherImpl.cpp"
#include "../src/StretcherProcess.cpp"
#include "../src/faster/AudioCurveCalculator.cpp"
#include "../src/faster/CompoundAudioCurve.cpp"
#include "../src/faster/HighFrequencyAudioCurve.cpp"
#include "../src/faster/SilentAudioCurve.cpp"
#include "../src/faster/PercussiveAudioCurve.cpp"
#include "../src/common/Log.cpp"
#include "../src/common/Profiler.cpp"
#include "../src/common/FFT.cpp"
#include "../src/common/Resampler.cpp"
#include "../src/common/BQResampler.cpp"
#include "../src/common/Allocators.cpp"
#include "../src/common/StretchCalculator.cpp"
#include "../src/common/sysutils.cpp"
#include "../src/common/Thread.cpp"
#include "../src/faster/StretcherChannelData.cpp"
#include "../src/faster/R2Stretcher.cpp"
#include "../src/faster/StretcherProcess.cpp"
#include "../src/finer/R3Stretcher.cpp"
#include "../src/RubberBandStretcher.cpp"
#include "../src/rubberband-c.cpp"

View File

@@ -21,18 +21,336 @@
you must obtain a valid commercial licence before doing so.
*/
#include "StretcherImpl.h"
#include "faster/R2Stretcher.h"
#include "finer/R3Stretcher.h"
#include <iostream>
namespace RubberBand {
class RubberBandStretcher::Impl
{
R2Stretcher *m_r2;
R3Stretcher *m_r3;
class CerrLogger : public RubberBandStretcher::Logger {
public:
void log(const char *message) override {
std::cerr << "RubberBand: " << message << "\n";
}
void log(const char *message, double arg0) override {
auto prec = std::cerr.precision();
std::cerr.precision(10);
std::cerr << "RubberBand: " << message << ": " << arg0 << "\n";
std::cerr.precision(prec);
}
void log(const char *message, double arg0, double arg1) override {
auto prec = std::cerr.precision();
std::cerr.precision(10);
std::cerr << "RubberBand: " << message
<< ": (" << arg0 << ", " << arg1 << ")" << "\n";
std::cerr.precision(prec);
}
};
Log makeRBLog(std::shared_ptr<RubberBandStretcher::Logger> logger) {
if (logger) {
return Log(
[=](const char *message) {
logger->log(message);
},
[=](const char *message, double arg0) {
logger->log(message, arg0);
},
[=](const char *message, double arg0, double arg1) {
logger->log(message, arg0, arg1);
}
);
} else {
return makeRBLog(std::shared_ptr<RubberBandStretcher::Logger>
(new CerrLogger()));
}
}
public:
Impl(size_t sampleRate, size_t channels, Options options,
std::shared_ptr<RubberBandStretcher::Logger> logger,
double initialTimeRatio, double initialPitchScale) :
m_r2 (!(options & OptionEngineFiner) ?
new R2Stretcher(sampleRate, channels, options,
initialTimeRatio, initialPitchScale,
makeRBLog(logger))
: nullptr),
m_r3 ((options & OptionEngineFiner) ?
new R3Stretcher(R3Stretcher::Parameters
(double(sampleRate), channels, options),
initialTimeRatio, initialPitchScale,
makeRBLog(logger))
: nullptr)
{
}
~Impl()
{
delete m_r2;
delete m_r3;
}
int getEngineVersion() const
{
if (m_r3) return 3;
else return 2;
}
void reset()
{
if (m_r2) m_r2->reset();
else m_r3->reset();
}
RTENTRY__
void
setTimeRatio(double ratio)
{
if (m_r2) m_r2->setTimeRatio(ratio);
else m_r3->setTimeRatio(ratio);
}
RTENTRY__
void
setPitchScale(double scale)
{
if (m_r2) m_r2->setPitchScale(scale);
else m_r3->setPitchScale(scale);
}
RTENTRY__
void
setFormantScale(double scale)
{
//!!!
if (m_r3) m_r3->setFormantScale(scale);
}
RTENTRY__
double
getTimeRatio() const
{
if (m_r2) return m_r2->getTimeRatio();
else return m_r3->getTimeRatio();
}
RTENTRY__
double
getPitchScale() const
{
if (m_r2) return m_r2->getPitchScale();
else return m_r3->getPitchScale();
}
RTENTRY__
double
getFormantScale() const
{
//!!!
if (m_r2) return 0.0;
else return m_r3->getFormantScale();
}
RTENTRY__
size_t
getLatency() const
{
if (m_r2) return m_r2->getLatency();
else return m_r3->getLatency();
}
//!!! review all these
RTENTRY__
void
setTransientsOption(Options options)
{
if (m_r2) m_r2->setTransientsOption(options);
}
RTENTRY__
void
setDetectorOption(Options options)
{
if (m_r2) m_r2->setDetectorOption(options);
}
RTENTRY__
void
setPhaseOption(Options options)
{
if (m_r2) m_r2->setPhaseOption(options);
}
RTENTRY__
void
setFormantOption(Options options)
{
if (m_r2) m_r2->setFormantOption(options);
else if (m_r3) m_r3->setFormantOption(options);
}
RTENTRY__
void
setPitchOption(Options options)
{
if (m_r2) m_r2->setPitchOption(options);
}
void
setExpectedInputDuration(size_t samples)
{
if (m_r2) m_r2->setExpectedInputDuration(samples);
//!!! perhaps also for R3
}
void
setMaxProcessSize(size_t samples)
{
if (m_r2) m_r2->setMaxProcessSize(samples);
else m_r3->setMaxProcessSize(samples);
}
void
setKeyFrameMap(const std::map<size_t, size_t> &mapping)
{
if (m_r2) m_r2->setKeyFrameMap(mapping);
else m_r3->setKeyFrameMap(mapping);
}
RTENTRY__
size_t
getSamplesRequired() const
{
if (m_r2) return m_r2->getSamplesRequired();
else return m_r3->getSamplesRequired();
}
void
study(const float *const *input, size_t samples,
bool final)
{
if (m_r2) m_r2->study(input, samples, final);
else m_r3->study(input, samples, final);
}
RTENTRY__
void
process(const float *const *input, size_t samples,
bool final)
{
if (m_r2) m_r2->process(input, samples, final);
else m_r3->process(input, samples, final);
}
RTENTRY__
int
available() const
{
if (m_r2) return m_r2->available();
else return m_r3->available();
}
RTENTRY__
size_t
retrieve(float *const *output, size_t samples) const
{
if (m_r2) return m_r2->retrieve(output, samples);
else return m_r3->retrieve(output, samples);
}
float
getFrequencyCutoff(int n) const
{
if (m_r2) return m_r2->getFrequencyCutoff(n);
else return {};
}
void
setFrequencyCutoff(int n, float f)
{
if (m_r2) m_r2->setFrequencyCutoff(n, f);
}
size_t
getInputIncrement() const
{
if (m_r2) return m_r2->getInputIncrement();
else return {};
}
std::vector<int>
getOutputIncrements() const
{
if (m_r2) return m_r2->getOutputIncrements();
else return {};
}
std::vector<float>
getPhaseResetCurve() const
{
if (m_r2) return m_r2->getPhaseResetCurve();
else return {};
}
std::vector<int>
getExactTimePoints() const
{
if (m_r2) return m_r2->getExactTimePoints();
else return {};
}
RTENTRY__
size_t
getChannelCount() const
{
if (m_r2) return m_r2->getChannelCount();
else return m_r3->getChannelCount();
}
void
calculateStretch()
{
if (m_r2) m_r2->calculateStretch();
}
void
setDebugLevel(int level)
{
if (m_r2) m_r2->setDebugLevel(level);
else m_r3->setDebugLevel(level);
}
static void
setDefaultDebugLevel(int level)
{
Log::setDefaultDebugLevel(level);
}
};
RubberBandStretcher::RubberBandStretcher(size_t sampleRate,
size_t channels,
Options options,
double initialTimeRatio,
double initialPitchScale) :
m_d(new Impl(sampleRate, channels, options,
m_d(new Impl(sampleRate, channels, options, nullptr,
initialTimeRatio, initialPitchScale))
{
}
RubberBandStretcher::RubberBandStretcher(size_t sampleRate,
size_t channels,
std::shared_ptr<Logger> logger,
Options options,
double initialTimeRatio,
double initialPitchScale) :
m_d(new Impl(sampleRate, channels, options, logger,
initialTimeRatio, initialPitchScale))
{
}
@@ -48,60 +366,90 @@ RubberBandStretcher::reset()
m_d->reset();
}
int
RubberBandStretcher::getEngineVersion() const
{
return m_d->getEngineVersion();
}
RTENTRY__
void
RubberBandStretcher::setTimeRatio(double ratio)
{
m_d->setTimeRatio(ratio);
}
RTENTRY__
void
RubberBandStretcher::setPitchScale(double scale)
{
m_d->setPitchScale(scale);
}
RTENTRY__
void
RubberBandStretcher::setFormantScale(double scale)
{
m_d->setFormantScale(scale);
}
RTENTRY__
double
RubberBandStretcher::getTimeRatio() const
{
return m_d->getTimeRatio();
}
RTENTRY__
double
RubberBandStretcher::getPitchScale() const
{
return m_d->getPitchScale();
}
RTENTRY__
double
RubberBandStretcher::getFormantScale() const
{
return m_d->getFormantScale();
}
RTENTRY__
size_t
RubberBandStretcher::getLatency() const
{
return m_d->getLatency();
}
RTENTRY__
void
RubberBandStretcher::setTransientsOption(Options options)
{
m_d->setTransientsOption(options);
}
RTENTRY__
void
RubberBandStretcher::setDetectorOption(Options options)
{
m_d->setDetectorOption(options);
}
RTENTRY__
void
RubberBandStretcher::setPhaseOption(Options options)
{
m_d->setPhaseOption(options);
}
RTENTRY__
void
RubberBandStretcher::setFormantOption(Options options)
{
m_d->setFormantOption(options);
}
RTENTRY__
void
RubberBandStretcher::setPitchOption(Options options)
{
@@ -126,6 +474,7 @@ RubberBandStretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
m_d->setKeyFrameMap(mapping);
}
RTENTRY__
size_t
RubberBandStretcher::getSamplesRequired() const
{
@@ -139,6 +488,7 @@ RubberBandStretcher::study(const float *const *input, size_t samples,
m_d->study(input, samples, final);
}
RTENTRY__
void
RubberBandStretcher::process(const float *const *input, size_t samples,
bool final)
@@ -146,12 +496,14 @@ RubberBandStretcher::process(const float *const *input, size_t samples,
m_d->process(input, samples, final);
}
RTENTRY__
int
RubberBandStretcher::available() const
{
return m_d->available();
}
RTENTRY__
size_t
RubberBandStretcher::retrieve(float *const *output, size_t samples) const
{
@@ -194,6 +546,7 @@ RubberBandStretcher::getExactTimePoints() const
return m_d->getExactTimePoints();
}
RTENTRY__
size_t
RubberBandStretcher::getChannelCount() const
{

File diff suppressed because it is too large Load Diff

View File

@@ -1,107 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#include "SpectralDifferenceAudioCurve.h"
#include "../system/Allocators.h"
#include "../system/VectorOps.h"
namespace RubberBand
{
SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters)
{
m_mag = allocate<double>(m_lastPerceivedBin + 1);
m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
v_zero(m_mag, m_lastPerceivedBin + 1);
}
SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
{
deallocate(m_mag);
deallocate(m_tmpbuf);
}
void
SpectralDifferenceAudioCurve::reset()
{
v_zero(m_mag, m_lastPerceivedBin + 1);
}
void
SpectralDifferenceAudioCurve::setFftSize(int newSize)
{
deallocate(m_tmpbuf);
deallocate(m_mag);
AudioCurveCalculator::setFftSize(newSize);
m_mag = allocate<double>(m_lastPerceivedBin + 1);
m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
reset();
}
float
SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, int)
{
double result = 0.0;
const int hs1 = m_lastPerceivedBin + 1;
v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1);
v_subtract(m_mag, m_tmpbuf, hs1);
v_abs(m_mag, hs1);
v_sqrt(m_mag, hs1);
for (int i = 0; i < hs1; ++i) {
result += m_mag[i];
}
v_copy(m_mag, m_tmpbuf, hs1);
return result;
}
double
SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, int)
{
double result = 0.0;
const int hs1 = m_lastPerceivedBin + 1;
v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1);
v_subtract(m_mag, m_tmpbuf, hs1);
v_abs(m_mag, hs1);
v_sqrt(m_mag, hs1);
for (int i = 0; i < hs1; ++i) {
result += m_mag[i];
}
v_copy(m_mag, m_tmpbuf, hs1);
return result;
}
}

View File

@@ -28,8 +28,8 @@
#include <iostream>
#include <algorithm>
#include "../system/Allocators.h"
#include "../system/VectorOps.h"
#include "Allocators.h"
#include "VectorOps.h"
#define BQ_R__ R__

View File

@@ -26,8 +26,8 @@
#include <vector>
#include "../system/Allocators.h"
#include "../system/VectorOps.h"
#include "Allocators.h"
#include "VectorOps.h"
namespace RubberBand {

View File

@@ -22,11 +22,11 @@
*/
#include "FFT.h"
#include "../system/Thread.h"
#include "../base/Profiler.h"
#include "../system/Allocators.h"
#include "../system/VectorOps.h"
#include "../system/VectorOpsComplex.h"
#include "Thread.h"
#include "Profiler.h"
#include "Allocators.h"
#include "VectorOps.h"
#include "VectorOpsComplex.h"
// Define USE_FFTW_WISDOM if you are defining HAVE_FFTW3 and you want
// to use FFTW_MEASURE mode with persistent wisdom files. This will

View File

@@ -24,7 +24,7 @@
#ifndef RUBBERBAND_FFT_H
#define RUBBERBAND_FFT_H
#include "../system/sysutils.h"
#include "sysutils.h"
#include <string>
#include <set>

View File

@@ -21,23 +21,26 @@
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_CONSTANT_AUDIO_CURVE_H
#define RUBBERBAND_CONSTANT_AUDIO_CURVE_H
#ifndef RUBBERBAND_FIXED_VECTOR_H
#define RUBBERBAND_FIXED_VECTOR_H
#include "../dsp/AudioCurveCalculator.h"
#include "Allocators.h"
#include <vector>
namespace RubberBand
{
class ConstantAudioCurve : public AudioCurveCalculator
template <typename T>
class FixedVector : public std::vector<T, StlAllocator<T>>
{
public:
ConstantAudioCurve(Parameters parameters);
virtual ~ConstantAudioCurve();
using std::vector<T, StlAllocator<T>>::vector;
virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual void reset();
private:
FixedVector(const FixedVector &) =delete;
FixedVector(FixedVector &&) =delete;
FixedVector &operator=(const FixedVector &) =delete;
FixedVector &operator=(FixedVector &&) =delete;
};
}

View File

@@ -0,0 +1,194 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_HISTOGRAM_FILTER_H
#define RUBBERBAND_HISTOGRAM_FILTER_H
#include "SingleThreadRingBuffer.h"
#include <vector>
#include <iostream>
namespace RubberBand {
/**
* A median or modal filter implemented using a histogram. The values
* must come from a compact set of integers within [0,n) where n is
* specified in the constructor. Pushing a value updates the
* histogram, after which you can get either the median or the mode.
* You can call drop() to drop the oldest value without pushing a new
* one, for example to drain the filter at the tail of the sequence.
*/
class HistogramFilter
{
public:
HistogramFilter(int nValues, int filterLength) :
m_buffer(filterLength),
m_histogram(nValues, 0),
m_mode(-1) { }
~HistogramFilter() { }
int getFilterLength() const {
return m_buffer.getSize();
}
int getNValues() const {
return int(m_histogram.size());
}
void reset() {
m_buffer.reset();
for (int i = 0; i < getNValues(); ++i) {
m_histogram[i] = 0;
}
}
void push(int value) {
if (m_buffer.getWriteSpace() == 0) {
int toDrop = m_buffer.readOne();
--m_histogram[toDrop];
}
m_buffer.writeOne(value);
int height = ++m_histogram[value];
if (m_mode >= 0 && height >= m_histogram[m_mode]) {
if (height > m_histogram[m_mode] || value < m_mode) {
m_mode = value;
}
}
}
void drop() {
if (m_buffer.getReadSpace() > 0) {
int toDrop = m_buffer.readOne();
--m_histogram[toDrop];
if (toDrop == m_mode) {
m_mode = -1;
}
}
}
/** Return the median of the values in the filter currently. If
* the median lies between two values, return the first of them.
*/
int getMedian() const {
int half = (m_buffer.getReadSpace() + 1) / 2;
int acc = 0;
int nvalues = getNValues();
for (int i = 0; i < nvalues; ++i) {
acc += m_histogram[i];
if (acc >= half) {
return i;
}
}
return 0;
}
/** Return the modal value, that is, the value that occurs the
* most often in the filter currently. If multiple values occur
* an equal number of times, return the smallest of them.
*/
int getMode() const {
if (m_mode >= 0) {
return m_mode;
}
int max = 0;
int mode = 0;
int nvalues = getNValues();
for (int i = 0; i < nvalues; ++i) {
int h = m_histogram[i];
if (i == 0 || h > max) {
max = h;
mode = i;
}
}
m_mode = mode;
return mode;
}
// Convenience function that filters an array in-place. Filter is
// a median filter unless modal is true. Array has length n.
// Modifies both the filter and the array.
//
static void filter(HistogramFilter &f, int *v, int n, bool modal = false) {
f.reset();
int flen = f.getFilterLength();
int i = -(flen / 2);
int j = 0;
while (i != n) {
if (j < n) {
f.push(v[j]);
} else if (j >= flen) {
f.drop();
}
if (i >= 0) {
int m = modal ? f.getMode() : f.getMedian();
v[i] = m;
}
++i;
++j;
}
}
// As above but with a vector argument
//
static void filter(HistogramFilter &f, std::vector<int> &v, bool modal = false) {
filter(f, v.data(), v.size(), modal);
}
// Convenience function that median-filters an array
// in-place. Array has length n. Modifies both the filter and the
// array.
//
static void medianFilter(HistogramFilter &f, int *v, int n) {
filter(f, v, n, false);
}
// As above but with a vector argument
//
static void medianFilter(HistogramFilter &f, std::vector<int> &v) {
medianFilter(f, v.data(), v.size());
}
// Convenience function that modal-filters an array
// in-place. Array has length n. Modifies both the filter and the
// array.
//
static void modalFilter(HistogramFilter &f, int *v, int n) {
filter(f, v, n, true);
}
// As above but with a vector argument
//
static void modalFilter(HistogramFilter &f, std::vector<int> &v) {
modalFilter(f, v.data(), v.size());
}
private:
SingleThreadRingBuffer<int> m_buffer;
std::vector<int> m_histogram;
mutable int m_mode;
};
}
#endif

View File

@@ -21,37 +21,11 @@
you must obtain a valid commercial licence before doing so.
*/
#include "ConstantAudioCurve.h"
#include "Log.h"
namespace RubberBand
{
ConstantAudioCurve::ConstantAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters)
{
}
ConstantAudioCurve::~ConstantAudioCurve()
{
}
void
ConstantAudioCurve::reset()
{
}
float
ConstantAudioCurve::processFloat(const float *R__, int)
{
return 1.f;
}
double
ConstantAudioCurve::processDouble(const double *R__, int)
{
return 1.0;
}
int Log::m_defaultDebugLevel = 0;
}

72
src/common/Log.h Normal file
View File

@@ -0,0 +1,72 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_LOG_H
#define RUBBERBAND_LOG_H
#include <functional>
#include <iostream>
namespace RubberBand {
class Log {
public:
Log(std::function<void(const char *)> _log0,
std::function<void(const char *, double)> _log1,
std::function<void(const char *, double, double)> _log2) :
m_log0(_log0),
m_log1(_log1),
m_log2(_log2),
m_debugLevel(m_defaultDebugLevel) { }
Log(const Log &other) =default;
Log(Log &&other) =default;
Log &operator=(const Log &other) =default;
Log &operator=(Log &&other) =default;
void setDebugLevel(int level) { m_debugLevel = level; }
int getDebugLevel() const { return m_debugLevel; }
static void setDefaultDebugLevel(int level) { m_defaultDebugLevel = level; }
void log(int level, const char *message) const {
if (level <= m_debugLevel) m_log0(message);
}
void log(int level, const char *message, double arg0) const {
if (level <= m_debugLevel) m_log1(message, arg0);
}
void log(int level, const char *message, double arg0, double arg1) const {
if (level <= m_debugLevel) m_log2(message, arg0, arg1);
}
private:
std::function<void(const char *)> m_log0;
std::function<void(const char *, double)> m_log1;
std::function<void(const char *, double, double)> m_log2;
int m_debugLevel;
static int m_defaultDebugLevel;
};
}
#endif

256
src/common/MovingMedian.h Normal file
View File

@@ -0,0 +1,256 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_MOVING_MEDIAN_H
#define RUBBERBAND_MOVING_MEDIAN_H
#include "SampleFilter.h"
#include "FixedVector.h"
#include "Allocators.h"
#include "SingleThreadRingBuffer.h"
#include <algorithm>
#include <iostream>
namespace RubberBand
{
/**
* A median or modal filter implemented using sorting, for continuous
* values. Pushing a value updates the sorted record, after which you
* can get() the median. You can call drop() to drop the oldest value
* without pushing a new one, for example to drain the filter at the
* tail of the sequence.
*/
template <typename T>
class MovingMedian : public SampleFilter<T>
{
static constexpr float fifty = 50.f;
public:
MovingMedian(int filterLength, float percentile = fifty) :
m_buffer(filterLength),
m_sortspace(filterLength, {}),
m_fill(0),
m_percentile(percentile)
{ }
~MovingMedian() { }
MovingMedian(const MovingMedian &) =default;
MovingMedian &operator=(const MovingMedian &) =default;
int getSize() const {
return m_buffer.getSize();
}
void setPercentile(float p) {
m_percentile = p;
}
void push(T value) {
if (value != value) {
std::cerr << "WARNING: MovingMedian: NaN encountered" << std::endl;
value = T();
}
if (m_fill == getSize()) {
T toDrop = m_buffer.readOne();
dropAndPut(toDrop, value);
} else {
put(value);
}
m_buffer.writeOne(value);
}
void drop() {
if (m_fill > 0) {
T toDrop = m_buffer.readOne();
drop(toDrop);
}
}
/** Return the median of the values in the filter currently. If
* the median lies between two values, return the first of them.
*/
T get() const {
int n = m_fill - 1;
if (m_percentile == fifty) { // exact default value
return m_sortspace[n / 2];
} else {
int index = int(floorf(float(n) * m_percentile / 100.f));
if (index >= m_fill) index = m_fill - 1;
return m_sortspace[index];
}
}
void reset() {
m_buffer.reset();
v_zero(m_sortspace.data(), m_sortspace.size());
m_fill = 0;
}
// Convenience function that applies a given filter to an array
// in-place. Array has length n. Modifies both the filter and the
// array.
//
static void filter(MovingMedian<T> &f, T *v, int n) {
f.reset();
int flen = f.getSize();
int i = -(flen / 2);
int j = 0;
while (i != n) {
if (j < n) {
f.push(v[j]);
} else if (j >= flen) {
f.drop();
}
if (i >= 0) {
v[i] = f.get();
}
++i;
++j;
}
}
// As above but with a vector argument
//
static void filter(MovingMedian<T> &mm, std::vector<T> &v) {
filter(mm, v.data(), v.size());
}
private:
SingleThreadRingBuffer<T> m_buffer;
std::vector<T> m_sortspace;
int m_fill;
float m_percentile;
void dropAndPut(const T &toDrop, const T &toPut) {
// precondition: sorted contains getSize values, one of which is toDrop
// postcondition: sorted contains getSize values, one of which is toPut
// (and one instance of toDrop has been removed)
// This implementation was timed for rather short filters (no
// longer than maybe 16 items). Two binary searches plus a
// memmove should be faster for longer ones.
const int n = m_fill;
T *sorted = m_sortspace.data();
int dropIx;
if (toDrop <= *sorted) {
// this is quite a common short-circuit in situations
// where many values can be (the equivalent of) 0
dropIx = 0;
} else {
dropIx = std::lower_bound(sorted, sorted + n, toDrop) - sorted;
}
if (toPut > toDrop) {
int i = dropIx;
while (i+1 < n) {
if (sorted[i+1] > toPut) {
break;
}
sorted[i] = sorted[i+1];
++i;
}
sorted[i] = toPut;
} else if (toPut < toDrop) {
int i = dropIx;
while (true) {
if (--i < 0 || sorted[i] < toPut) {
break;
}
sorted[i+1] = sorted[i];
}
sorted[i+1] = toPut;
}
}
void put(const T &toPut) {
// precondition: sorted contains m_fill values, m_fill < m_length,
// packed at the start
// postcondition: m_fill is incremented, sorted contains m_fill values,
// packed at the start, one of which is toPut
int n = m_fill;
T *sorted = m_sortspace.data();
int putIx = std::lower_bound(sorted, sorted + n, toPut) - sorted;
if (putIx < n) {
v_move(sorted + putIx + 1, sorted + putIx, n - putIx);
}
sorted[putIx] = toPut;
++m_fill;
}
void drop(const T &toDrop) {
// precondition: sorted contains m_fill values, m_fill > 0, <= m_length,
// packed at the start, one of which is toDrop
// postcondition: m_fill decremented, sorted contains m_fill values,
// packed at the start, none of which is toDrop
int n = m_fill;
T *sorted = m_sortspace.data();
int dropIx = std::lower_bound(sorted, sorted + n, toDrop) - sorted;
if (dropIx < n - 1) {
v_move(sorted + dropIx, sorted + dropIx + 1, n - dropIx - 1);
}
--m_fill;
}
};
template <typename T>
class MovingMedianStack
{
public:
MovingMedianStack(int nfilters, int size) :
m_stack(nfilters, { size })
{
}
~MovingMedianStack() {
}
int getSize() const {
return m_stack[0].getSize();
}
void push(int filter, T value) {
m_stack[filter].push(value);
}
T get(int filter) const {
return m_stack[filter].get();
}
void reset() {
for (auto &f: m_stack) {
f.reset();
}
}
private:
std::vector<MovingMedian<T>> m_stack;
};
}
#endif

View File

@@ -23,7 +23,7 @@
#include "Profiler.h"
#include "../system/Thread.h"
#include "Thread.h"
#include <algorithm>
#include <set>

View File

@@ -42,7 +42,7 @@
#ifdef PROFILE_CLOCKS
#include <time.h>
#else
#include "../system/sysutils.h"
#include "sysutils.h"
#ifndef _WIN32
#include <sys/time.h>
#endif

View File

@@ -23,8 +23,8 @@
#include "Resampler.h"
#include "../system/Allocators.h"
#include "../system/VectorOps.h"
#include "Allocators.h"
#include "VectorOps.h"
#include <cstdlib>
#include <cmath>
@@ -54,7 +54,7 @@
#endif
#ifdef USE_SPEEX
#include "../speex/speex_resampler.h"
#include "../ext/speex/speex_resampler.h"
#endif
#ifdef USE_BQRESAMPLER

View File

@@ -24,7 +24,7 @@
#ifndef RUBBERBAND_RESAMPLER_H
#define RUBBERBAND_RESAMPLER_H
#include "../system/sysutils.h"
#include "sysutils.h"
namespace RubberBand {
@@ -172,6 +172,9 @@ public:
protected:
Impl *d;
int m_method;
Resampler(const Resampler &) =delete;
Resampler &operator=(const Resampler &) =delete;
};
}

View File

@@ -28,8 +28,8 @@
//#define DEBUG_RINGBUFFER 1
#include "../system/sysutils.h"
#include "../system/Allocators.h"
#include "sysutils.h"
#include "Allocators.h"
#include <iostream>
@@ -44,7 +44,6 @@ namespace RubberBand {
* RingBuffer is thread-safe provided only one thread writes and only
* one thread reads.
*/
template <typename T>
class RingBuffer
{
@@ -138,8 +137,13 @@ public:
* necessary to empty the buffer. If fewer than n are available,
* the remainder will be zeroed out. Returns the number of
* samples actually read.
*
* This is a template function, taking an argument S for the target
* sample type, which is permitted to differ from T if the two
* types are compatible for arithmetic operations.
*/
int peek(T *const R__ destination, int n) const;
template <typename S>
int peek(S *const R__ destination, int n) const;
/**
* Read one sample from the buffer, if available, without
@@ -384,8 +388,9 @@ RingBuffer<T>::readOne()
}
template <typename T>
template <typename S>
int
RingBuffer<T>::peek(T *const R__ destination, int n) const
RingBuffer<T>::peek(S *const R__ destination, int n) const
{
int w = m_writer;
int r = m_reader;
@@ -394,7 +399,6 @@ RingBuffer<T>::peek(T *const R__ destination, int n) const
if (n > available) {
std::cerr << "WARNING: RingBuffer::peek: " << n << " requested, only "
<< available << " available" << std::endl;
memset(destination + available, 0, (n - available) * sizeof(T));
n = available;
}
if (n == 0) return n;
@@ -403,10 +407,10 @@ RingBuffer<T>::peek(T *const R__ destination, int n) const
const T *const R__ bufbase = m_buffer + r;
if (here >= n) {
v_copy(destination, bufbase, n);
v_convert(destination, bufbase, n);
} else {
v_copy(destination, bufbase, here);
v_copy(destination + here, m_buffer, n - here);
v_convert(destination, bufbase, here);
v_convert(destination + here, m_buffer, n - here);
}
return n;

View File

@@ -33,24 +33,11 @@ template <typename T>
class SampleFilter
{
public:
SampleFilter(int size) : m_size(size) {
assert(m_size > 0);
}
virtual ~SampleFilter() { }
int getSize() const { return m_size; }
virtual int getSize() const = 0;
virtual void push(T) = 0;
virtual T get() const = 0;
virtual void reset() = 0;
protected:
const int m_size;
private:
SampleFilter(const SampleFilter &);
SampleFilter &operator=(const SampleFilter &);
};
}

View File

@@ -33,9 +33,9 @@
#include <sys/time.h>
#endif
#include "../system/Thread.h"
#include "../system/sysutils.h"
#include "../system/Allocators.h"
#include "Thread.h"
#include "sysutils.h"
#include "Allocators.h"
//#define DEBUG_SCAVENGER 1

View File

@@ -0,0 +1,149 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_SINGLE_THREAD_RINGBUFFER_H
#define RUBBERBAND_SINGLE_THREAD_RINGBUFFER_H
#include <sys/types.h>
namespace RubberBand {
/**
* SingleThreadRingBuffer implements a ring buffer to be used to store
* a sample type T, for reading and writing within a single
* thread. SingleThreadRingBuffer is a simple container, not a
* thread-safe lock-free structure: use RingBuffer for the situation
* with reader and writer in separate threads. Currently this
* implementation only supports reading and writing a single sample at
* a time.
*/
template <typename T>
class SingleThreadRingBuffer
{
public:
/**
* Create a ring buffer with room to write n samples.
*
* Note that the internal storage size will actually be n+1
* samples, as one element is unavailable for administrative
* reasons. Since the ring buffer performs best if its size is a
* power of two, this means n should ideally be some power of two
* minus one.
*/
SingleThreadRingBuffer(int n) :
m_buffer(n + 1, T()),
m_writer(0),
m_reader(0),
m_size(n + 1) { }
SingleThreadRingBuffer() :
m_buffer(1, T()),
m_writer(0),
m_reader(0),
m_size(1) { }
SingleThreadRingBuffer (const SingleThreadRingBuffer &other) =default;
SingleThreadRingBuffer &operator=(const SingleThreadRingBuffer &other) =default;
virtual ~SingleThreadRingBuffer() { }
/**
* Return the total capacity of the ring buffer in samples.
* (This is the argument n passed to the constructor.)
*/
int getSize() const {
return m_size - 1;
}
/**
* Reset read and write pointers, thus emptying the buffer.
*/
void reset() {
m_writer = m_reader;
}
/**
* Return the amount of data available for reading, in samples.
*/
int getReadSpace() const {
if (m_writer > m_reader) return m_writer - m_reader;
else if (m_writer < m_reader) return (m_writer + m_size) - m_reader;
else return 0;
}
/**
* Return the amount of space available for writing, in samples.
*/
int getWriteSpace() const {
int space = (m_reader + m_size - m_writer - 1);
if (space >= m_size) space -= m_size;
return space;
}
/**
* Read one sample from the buffer. If no sample is available,
* silently return zero.
*/
T readOne() {
if (m_writer == m_reader) {
return {};
}
auto value = m_buffer[m_reader];
if (++m_reader == m_size) m_reader = 0;
return value;
}
/**
* Pretend to read one sample from the buffer, without actually
* returning it (i.e. discard the next sample).
*/
void skipOne() {
if (m_writer == m_reader) {
return;
}
if (++m_reader == m_size) m_reader = 0;
}
/**
* Write one sample to the buffer. If insufficient space is
* available, the sample will not be written. Returns the number
* of samples actually written, i.e. 0 or 1.
*/
int writeOne(const T &value) {
if (getWriteSpace() == 0) return 0;
m_buffer[m_writer] = value;
if (++m_writer == m_size) m_writer = 0;
return 1;
}
protected:
std::vector<T> m_buffer;
int m_writer;
int m_reader;
int m_size;
};
}
#endif

View File

@@ -0,0 +1,791 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#include "StretchCalculator.h"
#include <math.h>
#include <iostream>
#include <deque>
#include <set>
#include <cassert>
#include <algorithm>
#include <sstream>
#include "sysutils.h"
namespace RubberBand
{
StretchCalculator::StretchCalculator(size_t sampleRate,
size_t inputIncrement,
bool useHardPeaks,
Log log) :
m_sampleRate(sampleRate),
m_increment(inputIncrement),
m_prevDf(0),
m_prevRatio(1.0),
m_prevTimeRatio(1.0),
m_justReset(true),
m_transientAmnesty(0),
m_debugLevel(0),
m_useHardPeaks(useHardPeaks),
m_inFrameCounter(0),
m_frameCheckpoint(0, 0),
m_outFrameCounter(0),
m_log(log)
{
m_log.log(2, "StretchCalculator: useHardPeaks", useHardPeaks);
}
StretchCalculator::~StretchCalculator()
{
}
void
StretchCalculator::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
{
m_keyFrameMap = mapping;
// Ensure we always have a 0 -> 0 mapping. If there's nothing in
// the map at all, don't need to worry about this (empty map is
// handled separately anyway)
if (!m_keyFrameMap.empty()) {
if (m_keyFrameMap.find(0) == m_keyFrameMap.end()) {
m_keyFrameMap[0] = 0;
}
}
}
std::vector<int>
StretchCalculator::calculate(double ratio, size_t inputDuration,
const std::vector<float> &phaseResetDf)
{
m_peaks = findPeaks(phaseResetDf);
size_t totalCount = phaseResetDf.size();
size_t outputDuration = lrint(inputDuration * ratio);
m_log.log(1, "StretchCalculator::calculate: inputDuration and ratio", inputDuration, ratio);
outputDuration = lrint((phaseResetDf.size() * m_increment) * ratio);
m_log.log(1, "StretchCalculator::calculate: outputDuration rounds up from and to", inputDuration * ratio, outputDuration);
m_log.log(1, "StretchCalculator::calculate: df size and increment", phaseResetDf.size(), m_increment);
std::vector<Peak> peaks; // peak position (in chunks) and hardness
std::vector<size_t> targets; // targets for mapping peaks (in samples)
mapPeaks(peaks, targets, outputDuration, totalCount);
m_log.log(2, "have fixed positions", peaks.size());
size_t totalInput = 0, totalOutput = 0;
std::vector<int> increments;
for (size_t i = 0; i <= peaks.size(); ++i) {
size_t regionStart, regionStartChunk, regionEnd, regionEndChunk;
bool phaseReset = false;
if (i == 0) {
regionStartChunk = 0;
regionStart = 0;
} else {
regionStartChunk = peaks[i-1].chunk;
regionStart = targets[i-1];
phaseReset = peaks[i-1].hard;
}
if (i == peaks.size()) {
regionEndChunk = totalCount;
regionEnd = outputDuration;
} else {
regionEndChunk = peaks[i].chunk;
regionEnd = targets[i];
}
if (regionStartChunk > totalCount) regionStartChunk = totalCount;
if (regionStart > outputDuration) regionStart = outputDuration;
if (regionEndChunk > totalCount) regionEndChunk = totalCount;
if (regionEnd > outputDuration) regionEnd = outputDuration;
if (regionEndChunk < regionStartChunk) regionEndChunk = regionStartChunk;
if (regionEnd < regionStart) regionEnd = regionStart;
size_t regionDuration = regionEnd - regionStart;
size_t nchunks = regionEndChunk - regionStartChunk;
m_log.log(2, "region from and to (chunks)", regionStartChunk, regionEndChunk);
m_log.log(2, "region from and to (samples)", regionStart, regionEnd);
if (nchunks == 0) {
m_log.log(2, "note: nchunks == 0");
continue;
}
double per = double(regionDuration) / double(nchunks);
double acc = 0.0;
size_t nremaining = nchunks;
size_t totalForRegion = 0;
if (phaseReset) {
size_t incr;
if (nchunks > 1) {
incr = m_increment;
if (incr > regionDuration) {
incr = regionDuration;
}
} else {
incr = regionDuration;
}
increments.push_back(- int64_t(incr));
per = double(regionDuration - incr) / double(nchunks - 1);
acc += incr;
totalForRegion += incr;
totalInput += m_increment;
nremaining = nremaining - 1;
}
if (nremaining > 0) {
for (size_t j = 0; j+1 < nremaining; ++j) {
acc += per;
size_t incr = size_t(round(acc - totalForRegion));
increments.push_back(incr);
totalForRegion += incr;
totalInput += m_increment;
}
if (regionDuration > totalForRegion) {
size_t final = regionDuration - totalForRegion;
increments.push_back(final);
totalForRegion += final;
totalInput += m_increment;
}
}
totalOutput += totalForRegion;
}
m_log.log(1, "total input (frames, chunks)", totalInput, totalInput / m_increment);
m_log.log(1, "total output and achieved ratio", totalOutput, double(totalOutput)/double(totalInput));
m_log.log(1, "ideal output", totalInput * ratio);
return increments;
}
void
StretchCalculator::mapPeaks(std::vector<Peak> &peaks,
std::vector<size_t> &targets,
size_t outputDuration,
size_t totalCount)
{
// outputDuration is in audio samples; totalCount is in chunks
if (m_keyFrameMap.empty()) {
// "normal" behaviour -- fixed points are strictly in
// proportion
peaks = m_peaks;
for (size_t i = 0; i < peaks.size(); ++i) {
targets.push_back
(lrint((double(peaks[i].chunk) * outputDuration) / totalCount));
}
return;
}
// We have been given a set of source -> target sample frames in
// m_keyFrameMap. We want to ensure that (to the nearest chunk) these
// are followed exactly, and any fixed points that we calculated
// ourselves are interpolated in linear proportion in between.
size_t peakidx = 0;
std::map<size_t, size_t>::const_iterator mi = m_keyFrameMap.begin();
// NB we know for certain we have a mapping from 0 -> 0 (or at
// least, some mapping for source sample 0) because that is
// enforced in setKeyFrameMap above. However, we aren't guaranteed
// to have a mapping for the total duration -- we will usually
// need to assume it maps to the normal duration * ratio sample
while (mi != m_keyFrameMap.end()) {
// The map we've been given is from sample to sample, but
// we can only map from chunk to sample. We should perhaps
// adjust the target sample to compensate for the discrepancy
// between the chunk position and the exact requested source
// sample. But we aren't doing that yet.
size_t sourceStartChunk = mi->first / m_increment;
size_t sourceEndChunk = totalCount;
size_t targetStartSample = mi->second;
size_t targetEndSample = outputDuration;
++mi;
if (mi != m_keyFrameMap.end()) {
sourceEndChunk = mi->first / m_increment;
targetEndSample = mi->second;
}
if (sourceStartChunk >= totalCount ||
sourceStartChunk >= sourceEndChunk ||
targetStartSample >= outputDuration ||
targetStartSample >= targetEndSample) {
m_log.log(0, "NOTE: ignoring key-frame mapping from chunk to sample", sourceStartChunk, targetStartSample);
m_log.log(0, "(source or target chunk exceeds total count, or end is not later than start)");
continue;
}
// one peak and target for the mapping, then one for each of
// the computed peaks that appear before the following mapping
Peak p;
p.chunk = sourceStartChunk;
p.hard = false; // mappings are in time only, not phase reset points
peaks.push_back(p);
targets.push_back(targetStartSample);
m_log.log(2, "mapped key-frame chunk to frame", sourceStartChunk, targetStartSample);
while (peakidx < m_peaks.size()) {
size_t pchunk = m_peaks[peakidx].chunk;
if (pchunk < sourceStartChunk) {
// shouldn't happen, should have been dealt with
// already -- but no harm in ignoring it explicitly
++peakidx;
continue;
}
if (pchunk == sourceStartChunk) {
// convert that last peak to a hard one, after all
peaks[peaks.size()-1].hard = true;
++peakidx;
continue;
}
if (pchunk >= sourceEndChunk) {
// leave the rest for after the next mapping
break;
}
p.chunk = pchunk;
p.hard = m_peaks[peakidx].hard;
double proportion =
double(pchunk - sourceStartChunk) /
double(sourceEndChunk - sourceStartChunk);
size_t target =
targetStartSample +
lrint(proportion *
(targetEndSample - targetStartSample));
if (target <= targets[targets.size()-1] + m_increment) {
// peaks will become too close together afterwards, ignore
++peakidx;
continue;
}
m_log.log(2, "mapped peak chunk to frame", pchunk, target);
peaks.push_back(p);
targets.push_back(target);
++peakidx;
}
}
}
int64_t
StretchCalculator::expectedOutFrame(int64_t inFrame, double timeRatio)
{
int64_t checkpointedAt = m_frameCheckpoint.first;
int64_t checkpointed = m_frameCheckpoint.second;
return int64_t(round(checkpointed + (inFrame - checkpointedAt) * timeRatio));
}
int
StretchCalculator::calculateSingle(double timeRatio,
double effectivePitchRatio,
float df,
size_t inIncrement,
size_t analysisWindowSize,
size_t synthesisWindowSize,
bool alignFrameStarts)
{
double ratio = timeRatio / effectivePitchRatio;
int increment = int(inIncrement);
if (increment == 0) increment = m_increment;
int outIncrement = lrint(increment * ratio); // the normal case
bool isTransient = false;
// We want to ensure, as close as possible, that the phase reset
// points appear at the right audio frame numbers. To this end we
// track the incoming frame number, its corresponding expected
// output frame number, and the actual output frame number
// projected based on the ratios provided.
//
// There are two subtleties:
//
// (1) on a ratio change, we need to checkpoint the expected
// output frame number reached so far and start counting again
// with the new ratio. We could do this with a reset to zero, but
// it's easier to reason about absolute input/output frame
// matches, so for the moment at least we're doing this by
// explicitly checkpointing the current numbers (hence the use of
// the above expectedOutFrame() function which refers to the
// last checkpointed values).
//
// (2) in the case of a pitch shift in a configuration where
// resampling occurs after stretching, all of our output
// increments will be effectively modified by resampling after we
// return. This is why we separate out timeRatio and
// effectivePitchRatio arguments - the former is the ratio that
// has already been applied and the latter is the ratio that will
// be applied by any subsequent resampling step (which will be 1.0
// / pitchScale if resampling is happening after stretching). So
// the overall ratio is timeRatio / effectivePitchRatio.
bool ratioChanged = (!m_justReset) && (ratio != m_prevRatio);
m_justReset = false;
if (ratioChanged) {
// Reset our frame counters from the ratio change.
// m_outFrameCounter tracks the frames counted at output from
// this function, which normally precedes resampling - hence
// the use of timeRatio rather than ratio here
m_log.log(2, "StretchCalculator: ratio changed from and to", m_prevRatio, ratio);
int64_t toCheckpoint = expectedOutFrame
(m_inFrameCounter, m_prevTimeRatio);
m_frameCheckpoint =
std::pair<int64_t, int64_t>(m_inFrameCounter, toCheckpoint);
}
m_prevRatio = ratio;
m_prevTimeRatio = timeRatio;
if (m_log.getDebugLevel() > 2) {
std::ostringstream os;
os << "StretchCalculator::calculateSingle: timeRatio = "
<< timeRatio << ", effectivePitchRatio = "
<< effectivePitchRatio << " (that's 1.0 / "
<< (1.0 / effectivePitchRatio)
<< "), ratio = " << ratio << ", df = " << df
<< ", inIncrement = " << inIncrement
<< ", default outIncrement = " << outIncrement
<< ", analysisWindowSize = " << analysisWindowSize
<< ", synthesisWindowSize = " << synthesisWindowSize
<< "\n";
os << "inFrameCounter = " << m_inFrameCounter
<< ", outFrameCounter = " << m_outFrameCounter
<< "\n";
os << "The next sample out is input sample " << m_inFrameCounter << "\n";
m_log.log(3, os.str().c_str());
}
int64_t intended, projected;
if (alignFrameStarts) { // R3
intended = expectedOutFrame(m_inFrameCounter, timeRatio);
projected =
int64_t(round(m_outFrameCounter));
} else { // R2
intended = expectedOutFrame
(m_inFrameCounter + analysisWindowSize/4, timeRatio);
projected =
int64_t(round(m_outFrameCounter +
(synthesisWindowSize/4 * effectivePitchRatio)));
}
int64_t divergence = projected - intended;
m_log.log(3, "for current frame + quarter frame: intended vs projected", intended, projected);
m_log.log(3, "divergence", divergence);
// In principle, the threshold depends on chunk size: larger chunk
// sizes need higher thresholds. Since chunk size depends on
// ratio, I suppose we could in theory calculate the threshold
// from the ratio directly. For the moment we're happy if it
// works well in common situations.
float transientThreshold = 0.35f;
// if (ratio > 1) transientThreshold = 0.25f;
if (m_useHardPeaks && df > m_prevDf * 1.1f && df > transientThreshold) {
if (divergence > 1000 || divergence < -1000) {
m_log.log(2, "StretchCalculator::calculateSingle: transient, but we're not permitting it because the divergence is too great", divergence);
} else {
isTransient = true;
}
}
m_log.log(3, "df and prevDf", df, m_prevDf);
m_prevDf = df;
if (m_transientAmnesty > 0) {
if (isTransient) {
m_log.log(2, "StretchCalculator::calculateSingle: transient, but we have an amnesty: df and threshold", df, transientThreshold);
isTransient = false;
}
--m_transientAmnesty;
}
if (isTransient) {
m_log.log(2, "StretchCalculator::calculateSingle: transient: df and threshold", df, transientThreshold);
// as in offline mode, 0.05 sec approx min between transients
m_transientAmnesty =
lrint(ceil(double(m_sampleRate) / (20 * double(increment))));
outIncrement = increment;
} else {
double recovery = 0.0;
if (divergence > 1000 || divergence < -1000) {
recovery = divergence / ((m_sampleRate / 10.0) / increment);
} else if (divergence > 100 || divergence < -100) {
recovery = divergence / ((m_sampleRate / 20.0) / increment);
} else {
recovery = divergence / 4.0;
}
int incr = lrint(outIncrement - recovery);
int level = (divergence != 0 ? 2 : 3);
m_log.log(level, "divergence and recovery", divergence, recovery);
m_log.log(level, "outIncrement and adjusted incr", outIncrement, incr);
int minIncr = lrint(increment * ratio * 0.3);
int maxIncr = lrint(increment * ratio * 2);
if (incr < minIncr) {
incr = minIncr;
} else if (incr > maxIncr) {
incr = maxIncr;
}
m_log.log(level, "clamped into", minIncr, maxIncr);
m_log.log(level, "giving incr", incr);
if (incr < 0) {
m_log.log(0, "WARNING: internal error: incr < 0 in calculateSingle");
outIncrement = 0;
} else {
outIncrement = incr;
}
}
m_log.log(2, "StretchCalculator::calculateSingle: returning isTransient and outIncrement", isTransient, outIncrement);
m_inFrameCounter += inIncrement;
m_outFrameCounter += outIncrement * effectivePitchRatio;
if (isTransient) {
return -outIncrement;
} else {
return outIncrement;
}
}
void
StretchCalculator::reset()
{
m_prevDf = 0;
m_prevRatio = 1.0;
m_prevTimeRatio = 1.0;
m_inFrameCounter = 0;
m_frameCheckpoint = std::pair<int64_t, int64_t>(0, 0);
m_outFrameCounter = 0.0;
m_transientAmnesty = 0;
m_keyFrameMap.clear();
m_justReset = true;
}
std::vector<StretchCalculator::Peak>
StretchCalculator::findPeaks(const std::vector<float> &rawDf)
{
std::vector<float> df = smoothDF(rawDf);
// We distinguish between "soft" and "hard" peaks. A soft peak is
// simply the result of peak-picking on the smoothed onset
// detection function, and it represents any (strong-ish) onset.
// We aim to ensure always that soft peaks are placed at the
// correct position in time. A hard peak is where there is a very
// rapid rise in detection function, and it presumably represents
// a more broadband, noisy transient. For these we perform a
// phase reset (if in the appropriate mode), and we locate the
// reset at the first point where we notice enough of a rapid
// rise, rather than necessarily at the peak itself, in order to
// preserve the shape of the transient.
std::set<size_t> hardPeakCandidates;
std::set<size_t> softPeakCandidates;
if (m_useHardPeaks) {
// 0.05 sec approx min between hard peaks
size_t hardPeakAmnesty = lrint(ceil(double(m_sampleRate) /
(20 * double(m_increment))));
size_t prevHardPeak = 0;
m_log.log(2, "hardPeakAmnesty", hardPeakAmnesty);
for (size_t i = 1; i + 1 < df.size(); ++i) {
if (df[i] < 0.1) continue;
if (df[i] <= df[i-1] * 1.1) continue;
if (df[i] < 0.22) continue;
if (!hardPeakCandidates.empty() &&
i < prevHardPeak + hardPeakAmnesty) {
continue;
}
bool hard = (df[i] > 0.4);
if (hard) {
m_log.log(2, "hard peak, df > absolute 0.4: chunk and df", i, df[i]);
}
if (!hard) {
hard = (df[i] > df[i-1] * 1.4);
if (hard) {
m_log.log(2, "hard peak, single rise of 40%: chunk and df", i, df[i]);
}
}
if (!hard && i > 1) {
hard = (df[i] > df[i-1] * 1.2 &&
df[i-1] > df[i-2] * 1.2);
if (hard) {
m_log.log(2, "hard peak, two rises of 20%: chunk and df", i, df[i]);
}
}
if (!hard && i > 2) {
// have already established that df[i] > df[i-1] * 1.1
hard = (df[i] > 0.3 &&
df[i-1] > df[i-2] * 1.1 &&
df[i-2] > df[i-3] * 1.1);
if (hard) {
m_log.log(2, "hard peak, three rises of 10%: chunk and df", i, df[i]);
}
}
if (!hard) continue;
size_t peakLocation = i;
if (i + 1 < rawDf.size() &&
rawDf[i + 1] > rawDf[i] * 1.4) {
++peakLocation;
m_log.log(2, "big rise next, pushing hard peak forward to", peakLocation);
}
hardPeakCandidates.insert(peakLocation);
prevHardPeak = peakLocation;
}
}
size_t medianmaxsize = lrint(ceil(double(m_sampleRate) /
double(m_increment))); // 1 sec ish
m_log.log(2, "mediansize", medianmaxsize);
if (medianmaxsize < 7) {
medianmaxsize = 7;
m_log.log(2, "adjusted mediansize", medianmaxsize);
}
int minspacing = lrint(ceil(double(m_sampleRate) /
(20 * double(m_increment)))); // 0.05 sec ish
std::deque<float> medianwin;
std::vector<float> sorted;
int softPeakAmnesty = 0;
for (size_t i = 0; i < medianmaxsize/2; ++i) {
medianwin.push_back(0);
}
for (size_t i = 0; i < medianmaxsize/2 && i < df.size(); ++i) {
medianwin.push_back(df[i]);
}
size_t lastSoftPeak = 0;
for (size_t i = 0; i < df.size(); ++i) {
size_t mediansize = medianmaxsize;
if (medianwin.size() < mediansize) {
mediansize = medianwin.size();
}
size_t middle = medianmaxsize / 2;
if (middle >= mediansize) middle = mediansize-1;
size_t nextDf = i + mediansize - middle;
if (mediansize < 2) {
if (mediansize > medianmaxsize) { // absurd, but never mind that
medianwin.pop_front();
}
if (nextDf < df.size()) {
medianwin.push_back(df[nextDf]);
} else {
medianwin.push_back(0);
}
continue;
}
sorted.clear();
for (size_t j = 0; j < mediansize; ++j) {
sorted.push_back(medianwin[j]);
}
std::sort(sorted.begin(), sorted.end());
size_t n = 90; // percentile above which we pick peaks
size_t index = (sorted.size() * n) / 100;
if (index >= sorted.size()) index = sorted.size()-1;
if (index == sorted.size()-1 && index > 0) --index;
float thresh = sorted[index];
if (medianwin[middle] > thresh &&
medianwin[middle] > medianwin[middle-1] &&
medianwin[middle] > medianwin[middle+1] &&
softPeakAmnesty == 0) {
size_t maxindex = middle;
float maxval = medianwin[middle];
for (size_t j = middle+1; j < mediansize; ++j) {
if (medianwin[j] > maxval) {
maxval = medianwin[j];
maxindex = j;
} else if (medianwin[j] < medianwin[middle]) {
break;
}
}
size_t peak = i + maxindex - middle;
if (softPeakCandidates.empty() || lastSoftPeak != peak) {
m_log.log(2, "soft peak: chunk and median df", peak, medianwin[middle]);
if (peak >= df.size()) {
m_log.log(2, "peak is beyond end");
} else {
softPeakCandidates.insert(peak);
lastSoftPeak = peak;
}
}
softPeakAmnesty = minspacing + maxindex - middle;
m_log.log(3, "amnesty", softPeakAmnesty);
} else if (softPeakAmnesty > 0) --softPeakAmnesty;
if (mediansize >= medianmaxsize) {
medianwin.pop_front();
}
if (nextDf < df.size()) {
medianwin.push_back(df[nextDf]);
} else {
medianwin.push_back(0);
}
}
std::vector<Peak> peaks;
while (!hardPeakCandidates.empty() || !softPeakCandidates.empty()) {
bool haveHardPeak = !hardPeakCandidates.empty();
bool haveSoftPeak = !softPeakCandidates.empty();
size_t hardPeak = (haveHardPeak ? *hardPeakCandidates.begin() : 0);
size_t softPeak = (haveSoftPeak ? *softPeakCandidates.begin() : 0);
Peak peak;
peak.hard = false;
peak.chunk = softPeak;
bool ignore = false;
if (haveHardPeak &&
(!haveSoftPeak || hardPeak <= softPeak)) {
m_log.log(3, "hard peak", hardPeak);
peak.hard = true;
peak.chunk = hardPeak;
hardPeakCandidates.erase(hardPeakCandidates.begin());
} else {
m_log.log(3, "soft peak", softPeak);
if (!peaks.empty() &&
peaks[peaks.size()-1].hard &&
peaks[peaks.size()-1].chunk + 3 >= softPeak) {
m_log.log(3, "ignoring, as we just had a hard peak");
ignore = true;
}
}
if (haveSoftPeak && peak.chunk == softPeak) {
softPeakCandidates.erase(softPeakCandidates.begin());
}
if (!ignore) {
peaks.push_back(peak);
}
}
return peaks;
}
std::vector<float>
StretchCalculator::smoothDF(const std::vector<float> &df)
{
std::vector<float> smoothedDF;
for (size_t i = 0; i < df.size(); ++i) {
// three-value moving mean window for simple smoothing
float total = 0.f, count = 0;
if (i > 0) { total += df[i-1]; ++count; }
total += df[i]; ++count;
if (i+1 < df.size()) { total += df[i+1]; ++count; }
float mean = total / count;
smoothedDF.push_back(mean);
}
return smoothedDF;
}
}

View File

@@ -30,13 +30,18 @@
#include <map>
#include <cstdint>
#include "Log.h"
namespace RubberBand
{
class StretchCalculator
{
public:
StretchCalculator(size_t sampleRate, size_t inputIncrement, bool useHardPeaks);
StretchCalculator(size_t sampleRate,
size_t inputIncrement,
bool useHardPeaks,
Log log);
virtual ~StretchCalculator();
/**
@@ -51,13 +56,10 @@ public:
/**
* Calculate phase increments for a region of audio, given the
* overall target stretch ratio, input duration in audio samples,
* and the audio curves to use for identifying phase lock points
* (lockAudioCurve) and for allocating stretches to relatively
* less prominent points (stretchAudioCurve).
* and the audio curves to use for identifying phase lock points.
*/
std::vector<int> calculate(double ratio, size_t inputDuration,
const std::vector<float> &lockAudioCurve,
const std::vector<float> &stretchAudioCurve);
const std::vector<float> &lockAudioCurve);
/**
* Calculate the phase increment for a single audio block, given
@@ -74,7 +76,8 @@ public:
float curveValue,
size_t increment,
size_t analysisWindowSize,
size_t synthesisWindowSize);
size_t synthesisWindowSize,
bool alignFrameStarts);
void setUseHardPeaks(bool use) { m_useHardPeaks = use; }
@@ -96,21 +99,12 @@ protected:
void mapPeaks(std::vector<Peak> &peaks, std::vector<size_t> &targets,
size_t outputDuration, size_t totalCount);
std::vector<int> distributeRegion(const std::vector<float> &regionCurve,
size_t outputDuration, float ratio,
bool phaseReset);
void calculateDisplacements(const std::vector<float> &df,
float &maxDf,
double &totalDisplacement,
double &maxDisplacement,
float adj) const;
size_t m_sampleRate;
size_t m_increment;
float m_prevDf;
double m_prevRatio;
double m_prevTimeRatio;
bool m_justReset;
int m_transientAmnesty; // only in RT mode; handled differently offline
int m_debugLevel;
bool m_useHardPeaks;
@@ -118,6 +112,7 @@ protected:
std::pair<int64_t, int64_t> m_frameCheckpoint;
int64_t expectedOutFrame(int64_t inFrame, double timeRatio);
double m_outFrameCounter;
Log m_log;
std::map<size_t, size_t> m_keyFrameMap;
std::vector<Peak> m_peaks;

View File

@@ -33,8 +33,6 @@ namespace RubberBand {
template<typename T>
inline void c_phasor(T *real, T *imag, T phase)
{
//!!! IPP contains ippsSinCos_xxx in ippvm.h -- these are
//!!! fixed-accuracy, test and compare
#if defined HAVE_VDSP
int one = 1;
if (sizeof(T) == sizeof(float)) {

View File

@@ -28,9 +28,9 @@
#include <cstdlib>
#include <map>
#include "../system/sysutils.h"
#include "../system/VectorOps.h"
#include "../system/Allocators.h"
#include "sysutils.h"
#include "VectorOps.h"
#include "Allocators.h"
namespace RubberBand {
@@ -38,12 +38,14 @@ enum WindowType {
RectangularWindow,
BartlettWindow,
HammingWindow,
HanningWindow,
HannWindow,
BlackmanWindow,
GaussianWindow,
ParzenWindow,
NuttallWindow,
BlackmanHarrisWindow
BlackmanHarrisWindow,
NiemitaloForwardWindow,
NiemitaloReverseWindow
};
template <typename T>
@@ -79,6 +81,10 @@ public:
v_multiply(dst, src, m_cache, m_size);
}
inline void cutAndAdd(const T *const R__ src, T *const R__ dst) const {
v_multiply_and_add(dst, src, m_cache, m_size);
}
inline void add(T *const R__ dst, T scale) const {
v_add_with_gain(dst, m_cache, scale, m_size);
}
@@ -105,7 +111,7 @@ protected:
T m_area;
void encache();
void cosinewin(T *, T, T, T, T);
void cosinewin(T *, double, double, double, double);
};
template <typename T>
@@ -136,7 +142,7 @@ void Window<T>::encache()
cosinewin(m_cache, 0.54, 0.46, 0.0, 0.0);
break;
case HanningWindow:
case HannWindow:
cosinewin(m_cache, 0.50, 0.50, 0.0, 0.0);
break;
@@ -174,6 +180,64 @@ void Window<T>::encache()
case BlackmanHarrisWindow:
cosinewin(m_cache, 0.35875, 0.48829, 0.14128, 0.01168);
break;
case NiemitaloForwardWindow:
case NiemitaloReverseWindow:
{
/* Interesting asymmetric window proposed by Olli Niemitalo.
https://dsp.stackexchange.com/questions/2337/fft-with-asymmetric-windowing
(Olli also writes "I cross-license all of my code and
images in Stack Exchange under CC0 1.0" -
https://dsp.stackexchange.com/users/15347/olli-niemitalo)
*/
int quarter = n/4;
int eighth = n/8;
int k = 0;
for (int i = 0; i < n - eighth - quarter; ++i) {
T x = 2.0 * M_PI *
(((T(k + quarter) + 0.5) / T(n)) - 1.75);
m_cache[k++] =
2.57392230162633461887
- 1.58661480271141974718 * cos(x)
+ 3.80257516644523141380 * sin(x)
- 1.93437090055110760822 * cos(2.0 * x)
- 3.27163999159752183488 * sin(2.0 * x)
+ 3.26617449847621266201 * cos(3.0 * x)
- 0.30335261753524439543 * sin(3.0 * x)
- 0.92126091064427817479 * cos(4.0 * x)
+ 2.33100177294084742741 * sin(4.0 * x)
- 1.19953922321306438725 * cos(5.0 * x)
- 1.25098147932225423062 * sin(5.0 * x)
+ 0.99132076607048635886 * cos(6.0 * x)
- 0.34506787787355830410 * sin(6.0 * x)
- 0.04028033685700077582 * cos(7.0 * x)
+ 0.55461815542612269425 * sin(7.0 * x)
- 0.21882110175036428856 * cos(8.0 * x)
- 0.10756484378756643594 * sin(8.0 * x)
+ 0.06025986430527170007 * cos(9.0 * x)
- 0.05777077835678736534 * sin(9.0 * x)
+ 0.00920984524892982936 * cos(10.0 * x)
+ 0.01501989089735343216 * sin(10.0 * x);
}
for (int i = 0; i < eighth; ++i) {
int j = eighth - 1 - i;
m_cache[k++] =
(1.0 - m_cache[n/2 - 1 - j] * m_cache[n/2 + j]) /
m_cache[n/4 + j];
}
for (int i = 0; i < quarter; ++i) {
m_cache[k++] = 0.0;
}
if (m_type == NiemitaloReverseWindow) {
for (int i = 0; i < n/2; ++i) {
T tmp = m_cache[i];
m_cache[i] = m_cache[n - i - 1];
m_cache[n - i - 1] = tmp;
}
}
}
}
m_area = 0;
@@ -184,14 +248,14 @@ void Window<T>::encache()
}
template <typename T>
void Window<T>::cosinewin(T *mult, T a0, T a1, T a2, T a3)
void Window<T>::cosinewin(T *mult, double a0, double a1, double a2, double a3)
{
int n = int(m_size);
for (int i = 0; i < n; ++i) {
mult[i] *= (a0
mult[i] = T(mult[i] * (a0
- a1 * cos(2 * M_PI * i / n)
+ a2 * cos(4 * M_PI * i / n)
- a3 * cos(6 * M_PI * i / n));
- a3 * cos(6 * M_PI * i / n)));
}
}

56
src/common/mathmisc.h Normal file
View File

@@ -0,0 +1,56 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_MATHMISC_H
#define RUBBERBAND_MATHMISC_H
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif // M_PI
namespace RubberBand {
inline double mod(double x, double y) {
return x - (y * floor(x / y));
}
inline float modf(float x, float y) {
return x - (y * float(floor(x / y)));
}
inline double princarg(double a) {
return mod(a + M_PI, -2.0 * M_PI) + M_PI;
}
inline float princargf(float a) {
return modf(a + (float)M_PI, -2.f * (float)M_PI) + (float)M_PI;
}
inline int binForFrequency(double f, int fftSize, double sampleRate) {
return int(round(f * double(fftSize) / sampleRate));
}
inline double frequencyForBin(int b, int fftSize, double sampleRate) {
return (double(b) * sampleRate) / double(fftSize);
}
}
#endif

View File

@@ -28,7 +28,6 @@
#include <fcntl.h>
#include <io.h>
#else /* !_WIN32 */
#include <signal.h>
#include <unistd.h>
#ifdef __APPLE__
#include <sys/sysctl.h>
@@ -165,11 +164,6 @@ void gettimeofday(struct timeval *tv, void *tz)
tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL);
}
void usleep(unsigned long usec)
{
::Sleep(usec == 0 ? 0 : usec < 1000 ? 1 : usec / 1000);
}
#endif
void system_specific_initialise()
@@ -209,31 +203,6 @@ void system_specific_application_initialise()
{
}
ProcessStatus
system_get_process_status(int pid)
{
#ifdef _WIN32
HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!handle) {
return ProcessNotRunning;
} else {
CloseHandle(handle);
return ProcessRunning;
}
#else
if (kill(getpid(), 0) == 0) {
if (kill(pid, 0) == 0) {
return ProcessRunning;
} else {
return ProcessNotRunning;
}
} else {
return UnknownProcessStatus;
}
#endif
}
#ifdef _WIN32
void system_memorybarrier()
{

View File

@@ -45,6 +45,12 @@
# define R__
#endif
#ifdef __clang__
# define RTENTRY__ __attribute__((annotate("realtime")))
#else
# define RTENTRY__
#endif
#if defined(_MSC_VER)
# include <malloc.h>
# include <process.h>
@@ -82,33 +88,22 @@
namespace RubberBand {
#ifdef PROCESS_SAMPLE_TYPE
typedef PROCESS_SAMPLE_TYPE process_t;
#else
typedef double process_t;
#endif
extern const char *system_get_platform_tag();
extern bool system_is_multiprocessor();
extern void system_specific_initialise();
extern void system_specific_application_initialise();
enum ProcessStatus { ProcessRunning, ProcessNotRunning, UnknownProcessStatus };
extern ProcessStatus system_get_process_status(int pid);
#ifdef _WIN32
struct timeval { long tv_sec; long tv_usec; };
void gettimeofday(struct timeval *p, void *tz);
#endif // _WIN32
#ifdef _MSC_VER
void usleep(unsigned long);
#endif // _MSC_VER
inline double mod(double x, double y) { return x - (y * floor(x / y)); }
inline float modf(float x, float y) { return x - (y * float(floor(x / y))); }
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif // M_PI
inline double princarg(double a) { return mod(a + M_PI, -2.0 * M_PI) + M_PI; }
inline float princargf(float a) { return modf(a + (float)M_PI, -2.f * (float)M_PI) + (float)M_PI; }
} // end namespace
// The following should be functions in the RubberBand namespace, really
@@ -124,11 +119,6 @@ extern void system_memorybarrier();
}
#define MBARRIER() RubberBand::system_memorybarrier()
#define DLOPEN(a,b) LoadLibrary((a).toStdWString().c_str())
#define DLSYM(a,b) GetProcAddress((HINSTANCE)(a),(b))
#define DLCLOSE(a) FreeLibrary((HINSTANCE)(a))
#define DLERROR() ""
#else // !_WIN32
#include <sys/mman.h>
@@ -157,11 +147,6 @@ extern void system_memorybarrier();
# endif
#endif
#define DLOPEN(a,b) dlopen((a).toStdString().c_str(),(b))
#define DLSYM(a,b) dlsym((a),(b))
#define DLCLOSE(a) dlclose((a))
#define DLERROR() dlerror()
#endif // !_WIN32
#ifdef NO_THREADING

View File

@@ -1,110 +0,0 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_MOVING_MEDIAN_H
#define RUBBERBAND_MOVING_MEDIAN_H
#include "SampleFilter.h"
#include "../system/Allocators.h"
#include <algorithm>
#include <iostream>
namespace RubberBand
{
template <typename T>
class MovingMedian : public SampleFilter<T>
{
typedef SampleFilter<T> P;
public:
MovingMedian(int size, float percentile = 50.f) :
SampleFilter<T>(size),
m_frame(allocate_and_zero<T>(size)),
m_sorted(allocate_and_zero<T>(size)),
m_sortend(m_sorted + P::m_size - 1) {
setPercentile(percentile);
}
~MovingMedian() {
deallocate(m_frame);
deallocate(m_sorted);
}
void setPercentile(float p) {
m_index = int((P::m_size * p) / 100.f);
if (m_index >= P::m_size) m_index = P::m_size-1;
if (m_index < 0) m_index = 0;
}
void push(T value) {
if (value != value) {
std::cerr << "WARNING: MovingMedian: NaN encountered" << std::endl;
value = T();
}
drop(m_frame[0]);
v_move(m_frame, m_frame+1, P::m_size-1);
m_frame[P::m_size-1] = value;
put(value);
}
T get() const {
return m_sorted[m_index];
}
void reset() {
v_zero(m_frame, P::m_size);
v_zero(m_sorted, P::m_size);
}
private:
T *const m_frame;
T *const m_sorted;
T *const m_sortend;
int m_index;
void put(T value) {
// precondition: m_sorted contains m_size-1 values, packed at start
// postcondition: m_sorted contains m_size values, one of which is value
T *index = std::lower_bound(m_sorted, m_sortend, value);
v_move(index + 1, index, m_sortend - index);
*index = value;
}
void drop(T value) {
// precondition: m_sorted contains m_size values, one of which is value
// postcondition: m_sorted contains m_size-1 values, packed at start
T *index = std::lower_bound(m_sorted, m_sortend + 1, value);
assert(*index == value);
v_move(index, index + 1, m_sortend - index);
*m_sortend = T(0);
}
};
}
#endif

View File

@@ -26,7 +26,7 @@
#include <sys/types.h>
#include "../system/sysutils.h"
#include "../common/sysutils.h"
namespace RubberBand
{

View File

@@ -23,7 +23,7 @@
#include "CompoundAudioCurve.h"
#include "../dsp/MovingMedian.h"
#include "../common/MovingMedian.h"
#include <iostream>

View File

@@ -26,7 +26,7 @@
#include "PercussiveAudioCurve.h"
#include "HighFrequencyAudioCurve.h"
#include "../dsp/SampleFilter.h"
#include "../common/SampleFilter.h"
namespace RubberBand
{

View File

@@ -24,7 +24,7 @@
#ifndef RUBBERBAND_HIGHFREQUENCY_AUDIO_CURVE_H
#define RUBBERBAND_HIGHFREQUENCY_AUDIO_CURVE_H
#include "../dsp/AudioCurveCalculator.h"
#include "AudioCurveCalculator.h"
namespace RubberBand
{

View File

@@ -23,8 +23,8 @@
#include "PercussiveAudioCurve.h"
#include "../system/Allocators.h"
#include "../system/VectorOps.h"
#include "../common/Allocators.h"
#include "../common/VectorOps.h"
#include <cmath>
#include <iostream>

View File

@@ -24,7 +24,7 @@
#ifndef RUBBERBAND_PERCUSSIVE_AUDIO_CURVE_H
#define RUBBERBAND_PERCUSSIVE_AUDIO_CURVE_H
#include "../dsp/AudioCurveCalculator.h"
#include "AudioCurveCalculator.h"
namespace RubberBand
{

View File

@@ -21,23 +21,18 @@
you must obtain a valid commercial licence before doing so.
*/
#include "StretcherImpl.h"
#include "R2Stretcher.h"
#include "audiocurves/PercussiveAudioCurve.h"
#include "audiocurves/HighFrequencyAudioCurve.h"
#include "audiocurves/SpectralDifferenceAudioCurve.h"
#include "audiocurves/SilentAudioCurve.h"
#include "audiocurves/ConstantAudioCurve.h"
#include "audiocurves/CompoundAudioCurve.h"
#include "dsp/Resampler.h"
#include "StretchCalculator.h"
#include "PercussiveAudioCurve.h"
#include "HighFrequencyAudioCurve.h"
#include "SilentAudioCurve.h"
#include "CompoundAudioCurve.h"
#include "StretcherChannelData.h"
#include "base/Profiler.h"
#include "system/sysutils.h"
#include "../common/StretchCalculator.h"
#include "../common/Resampler.h"
#include "../common/Profiler.h"
#include "../common/sysutils.h"
#include <cassert>
#include <cmath>
@@ -45,10 +40,6 @@
#include <map>
#include <algorithm>
using namespace RubberBand;
using std::cerr;
using std::endl;
using std::vector;
using std::map;
using std::set;
@@ -58,21 +49,19 @@ using std::min;
namespace RubberBand {
const size_t
RubberBandStretcher::Impl::m_defaultIncrement = 256;
R2Stretcher::m_defaultIncrement = 256;
const size_t
RubberBandStretcher::Impl::m_defaultFftSize = 2048;
int
RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
R2Stretcher::m_defaultFftSize = 2048;
static bool _initialised = false;
RubberBandStretcher::Impl::Impl(size_t sampleRate,
R2Stretcher::R2Stretcher(size_t sampleRate,
size_t channels,
Options options,
RubberBandStretcher::Options options,
double initialTimeRatio,
double initialPitchScale) :
double initialPitchScale,
Log log) :
m_sampleRate(sampleRate),
m_channels(channels),
m_timeRatio(initialTimeRatio),
@@ -89,7 +78,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
#endif
m_realtime(false),
m_options(options),
m_debugLevel(m_defaultDebugLevel),
m_log(log),
m_mode(JustCreated),
m_awindow(0),
m_afilter(0),
@@ -105,7 +94,6 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_lastProcessPhaseResetDf(16),
m_emergencyScavenger(10, 4),
m_phaseResetAudioCurve(0),
m_stretchAudioCurve(0),
m_silentAudioCurve(0),
m_stretchCalculator(0),
m_freq0(600),
@@ -118,9 +106,10 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
_initialised = true;
}
if (m_debugLevel > 0) {
cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_sampleRate << ", options = " << options << endl;
}
m_log.log(1, "R2Stretcher::R2Stretcher: rate, options",
m_sampleRate, options);
m_log.log(1, "R2Stretcher::R2Stretcher: initial time ratio and pitch scale",
m_timeRatio, m_pitchScale);
// Window size will vary according to the audio sample rate, but
// we don't let it drop below the 48k default
@@ -128,19 +117,17 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
// if (m_rateMultiple < 1.f) m_rateMultiple = 1.f;
m_baseFftSize = roundUp(int(m_defaultFftSize * m_rateMultiple));
if ((options & OptionWindowShort) || (options & OptionWindowLong)) {
if ((options & OptionWindowShort) && (options & OptionWindowLong)) {
cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl;
} else if (options & OptionWindowShort) {
if ((options & RubberBandStretcher::OptionWindowShort) ||
(options & RubberBandStretcher::OptionWindowLong)) {
if ((options & RubberBandStretcher::OptionWindowShort) &&
(options & RubberBandStretcher::OptionWindowLong)) {
m_log.log(0, "R2Stretcher::R2Stretcher: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard");
} else if (options & RubberBandStretcher::OptionWindowShort) {
m_baseFftSize = m_baseFftSize / 2;
if (m_debugLevel > 0) {
cerr << "setting baseFftSize to " << m_baseFftSize << endl;
}
} else if (options & OptionWindowLong) {
m_log.log(1, "setting baseFftSize", m_baseFftSize);
} else if (options & RubberBandStretcher::OptionWindowLong) {
m_baseFftSize = m_baseFftSize * 2;
if (m_debugLevel > 0) {
cerr << "setting baseFftSize to " << m_baseFftSize << endl;
}
m_log.log(1, "setting baseFftSize", m_baseFftSize);
}
m_fftSize = m_baseFftSize;
m_aWindowSize = m_baseFftSize;
@@ -149,13 +136,8 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_maxProcessSize = m_aWindowSize;
}
if (m_options & OptionProcessRealTime) {
if (m_options & RubberBandStretcher::OptionProcessRealTime) {
m_realtime = true;
if (!(m_options & OptionStretchPrecise)) {
m_options |= OptionStretchPrecise;
}
}
#ifndef NO_THREADING
@@ -165,15 +147,15 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
if (m_realtime) {
m_threaded = false;
} else if (m_options & OptionThreadingNever) {
} else if (m_options & RubberBandStretcher::OptionThreadingNever) {
m_threaded = false;
} else if (!(m_options & OptionThreadingAlways) &&
} else if (!(m_options & RubberBandStretcher::OptionThreadingAlways) &&
!system_is_multiprocessor()) {
m_threaded = false;
}
if (m_threaded && m_debugLevel > 0) {
cerr << "Going multithreaded..." << endl;
if (m_threaded) {
m_log.log(1, "Going multithreaded...");
}
}
#endif
@@ -181,16 +163,14 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
configure();
}
RubberBandStretcher::Impl::~Impl()
R2Stretcher::~R2Stretcher()
{
#ifndef NO_THREADING
if (m_threaded) {
MutexLocker locker(&m_threadSetMutex);
for (set<ProcessThread *>::iterator i = m_threadSet.begin();
i != m_threadSet.end(); ++i) {
if (m_debugLevel > 0) {
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
}
m_log.log(1, "RubberBandStretcher::~RubberBandStretcher: joining for channel", (*i)->channel());
(*i)->abandon();
(*i)->wait();
delete *i;
@@ -203,7 +183,6 @@ RubberBandStretcher::Impl::~Impl()
}
delete m_phaseResetAudioCurve;
delete m_stretchAudioCurve;
delete m_silentAudioCurve;
delete m_stretchCalculator;
delete m_studyFFT;
@@ -219,16 +198,14 @@ RubberBandStretcher::Impl::~Impl()
}
void
RubberBandStretcher::Impl::reset()
R2Stretcher::reset()
{
#ifndef NO_THREADING
if (m_threaded) {
m_threadSetMutex.lock();
for (set<ProcessThread *>::iterator i = m_threadSet.begin();
i != m_threadSet.end(); ++i) {
if (m_debugLevel > 0) {
cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
}
m_log.log(1, "RubberBandStretcher::~RubberBandStretcher: joining for channel", (*i)->channel());
(*i)->abandon();
(*i)->wait();
delete *i;
@@ -249,7 +226,6 @@ RubberBandStretcher::Impl::reset()
m_mode = JustCreated;
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
if (m_silentAudioCurve) m_silentAudioCurve->reset();
m_inputDuration = 0;
m_silentHistory = 0;
@@ -262,11 +238,11 @@ RubberBandStretcher::Impl::reset()
}
void
RubberBandStretcher::Impl::setTimeRatio(double ratio)
R2Stretcher::setTimeRatio(double ratio)
{
if (!m_realtime) {
if (m_mode == Studying || m_mode == Processing) {
cerr << "RubberBandStretcher::Impl::setTimeRatio: Cannot set ratio while studying or processing in non-RT mode" << endl;
m_log.log(0, "R2Stretcher::setTimeRatio: Cannot set ratio while studying or processing in non-RT mode");
return;
}
}
@@ -278,11 +254,11 @@ RubberBandStretcher::Impl::setTimeRatio(double ratio)
}
void
RubberBandStretcher::Impl::setPitchScale(double fs)
R2Stretcher::setPitchScale(double fs)
{
if (!m_realtime) {
if (m_mode == Studying || m_mode == Processing) {
cerr << "RubberBandStretcher::Impl::setPitchScale: Cannot set ratio while studying or processing in non-RT mode" << endl;
m_log.log(0, "R2Stretcher::setPitchScale: Cannot set ratio while studying or processing in non-RT mode");
return;
}
}
@@ -296,7 +272,7 @@ RubberBandStretcher::Impl::setPitchScale(double fs)
reconfigure();
if (!(m_options & OptionPitchHighConsistency) &&
if (!(m_options & RubberBandStretcher::OptionPitchHighConsistency) &&
(was1 || resampleBeforeStretching() != rbs) &&
m_pitchScale != 1.f) {
@@ -310,19 +286,19 @@ RubberBandStretcher::Impl::setPitchScale(double fs)
}
double
RubberBandStretcher::Impl::getTimeRatio() const
R2Stretcher::getTimeRatio() const
{
return m_timeRatio;
}
double
RubberBandStretcher::Impl::getPitchScale() const
R2Stretcher::getPitchScale() const
{
return m_pitchScale;
}
void
RubberBandStretcher::Impl::setExpectedInputDuration(size_t samples)
R2Stretcher::setExpectedInputDuration(size_t samples)
{
if (samples == m_expectedInputDuration) return;
m_expectedInputDuration = samples;
@@ -331,7 +307,7 @@ RubberBandStretcher::Impl::setExpectedInputDuration(size_t samples)
}
void
RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
R2Stretcher::setMaxProcessSize(size_t samples)
{
if (samples <= m_maxProcessSize) return;
m_maxProcessSize = samples;
@@ -340,15 +316,15 @@ RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
}
void
RubberBandStretcher::Impl::setKeyFrameMap(const std::map<size_t, size_t> &
R2Stretcher::setKeyFrameMap(const std::map<size_t, size_t> &
mapping)
{
if (m_realtime) {
cerr << "RubberBandStretcher::Impl::setKeyFrameMap: Cannot specify key frame map in RT mode" << endl;
m_log.log(0, "R2Stretcher::setKeyFrameMap: Cannot specify key frame map in RT mode");
return;
}
if (m_mode == Processing) {
cerr << "RubberBandStretcher::Impl::setKeyFrameMap: Cannot specify key frame map after process() has begun" << endl;
m_log.log(0, "R2Stretcher::setKeyFrameMap: Cannot specify key frame map after process() has begun");
return;
}
@@ -358,7 +334,7 @@ RubberBandStretcher::Impl::setKeyFrameMap(const std::map<size_t, size_t> &
}
float
RubberBandStretcher::Impl::getFrequencyCutoff(int n) const
R2Stretcher::getFrequencyCutoff(int n) const
{
switch (n) {
case 0: return m_freq0;
@@ -369,7 +345,7 @@ RubberBandStretcher::Impl::getFrequencyCutoff(int n) const
}
void
RubberBandStretcher::Impl::setFrequencyCutoff(int n, float f)
R2Stretcher::setFrequencyCutoff(int n, float f)
{
switch (n) {
case 0: m_freq0 = f; break;
@@ -379,7 +355,7 @@ RubberBandStretcher::Impl::setFrequencyCutoff(int n, float f)
}
double
RubberBandStretcher::Impl::getEffectiveRatio() const
R2Stretcher::getEffectiveRatio() const
{
// Returns the ratio that the internal time stretcher needs to
// achieve, not the resulting duration ratio of the output (which
@@ -396,7 +372,7 @@ RubberBandStretcher::Impl::getEffectiveRatio() const
}
size_t
RubberBandStretcher::Impl::roundUp(size_t value)
R2Stretcher::roundUp(size_t value)
{
if (!(value & (value - 1))) return value;
int bits = 0;
@@ -406,7 +382,7 @@ RubberBandStretcher::Impl::roundUp(size_t value)
}
void
RubberBandStretcher::Impl::calculateSizes()
R2Stretcher::calculateSizes()
{
size_t inputIncrement = m_defaultIncrement;
size_t windowSize = m_baseFftSize;
@@ -416,12 +392,12 @@ RubberBandStretcher::Impl::calculateSizes()
// This special case is likelier than one might hope, because
// of naive initialisations in programs that set it from a
// variable
std::cerr << "RubberBandStretcher: WARNING: Pitch scale must be greater than zero!\nResetting it from " << m_pitchScale << " to the default of 1.0: no pitch change will occur" << std::endl;
m_log.log(0, "WARNING: Pitch scale must be greater than zero! Resetting it to default, no pitch shift will happen", m_pitchScale);
m_pitchScale = 1.0;
}
if (m_timeRatio <= 0.0) {
// Likewise
std::cerr << "RubberBandStretcher: WARNING: Time ratio must be greater than zero!\nResetting it from " << m_timeRatio << " to the default of 1.0: no time stretch will occur" << std::endl;
m_log.log(0, "WARNING: Time ratio must be greater than zero! Resetting it to default, no time stretch will happen", m_timeRatio);
m_timeRatio = 1.0;
}
@@ -474,7 +450,7 @@ RubberBandStretcher::Impl::calculateSizes()
if (windowSize < minwin) windowSize = minwin;
if (rsb) {
// cerr << "adjusting window size from " << windowSize;
size_t oldWindowSize = windowSize;
size_t newWindowSize = roundUp(lrint(windowSize / m_pitchScale));
if (newWindowSize < 512) newWindowSize = 512;
size_t div = windowSize / newWindowSize;
@@ -483,7 +459,8 @@ RubberBandStretcher::Impl::calculateSizes()
outputIncrement /= div;
windowSize /= div;
}
// cerr << " to " << windowSize << " (inputIncrement = " << inputIncrement << ", outputIncrement = " << outputIncrement << ")" << endl;
m_log.log(2, "adjusting window size from/to", oldWindowSize, windowSize);
m_log.log(2, "input and output increments", inputIncrement, outputIncrement);
}
}
@@ -526,7 +503,7 @@ RubberBandStretcher::Impl::calculateSizes()
m_fftSize = windowSize;
if (m_options & OptionSmoothingOn) {
if (m_options & RubberBandStretcher::OptionSmoothingOn) {
m_aWindowSize = windowSize * 2;
m_sWindowSize = windowSize * 2;
} else {
@@ -543,10 +520,11 @@ RubberBandStretcher::Impl::calculateSizes()
// twice the basic output increment (i.e. input increment times
// ratio) for any chunk.
if (m_debugLevel > 0) {
cerr << "calculateSizes: time ratio = " << m_timeRatio << ", pitch scale = " << m_pitchScale << ", effective ratio = " << getEffectiveRatio() << endl;
cerr << "calculateSizes: analysis window size = " << m_aWindowSize << ", synthesis window size = " << m_sWindowSize << ", fft size = " << m_fftSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl;
}
m_log.log(1, "calculateSizes: time ratio and pitch scale", m_timeRatio, m_pitchScale);
m_log.log(1, "effective ratio", getEffectiveRatio());
m_log.log(1, "analysis and synthesis window sizes", m_aWindowSize, m_sWindowSize);
m_log.log(1, "fft size", m_fftSize);
m_log.log(1, "input increment and mean output increment", m_increment, m_increment * getEffectiveRatio());
if (std::max(m_aWindowSize, m_sWindowSize) > m_maxProcessSize) {
m_maxProcessSize = std::max(m_aWindowSize, m_sWindowSize);
@@ -574,17 +552,18 @@ RubberBandStretcher::Impl::calculateSizes()
#endif
}
if (m_debugLevel > 0) {
cerr << "calculateSizes: outbuf size = " << m_outbufSize << endl;
}
m_log.log(1, "calculateSizes: outbuf size", m_outbufSize);
}
void
RubberBandStretcher::Impl::configure()
R2Stretcher::configure()
{
if (m_debugLevel > 0) {
std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = "
<< m_pitchScale << ", channels = " << m_channels << std::endl;
if (m_realtime) {
m_log.log(1, "configure, realtime: pitch scale and channels",
m_pitchScale, m_channels);
} else {
m_log.log(1, "configure, offline: pitch scale and channels",
m_pitchScale, m_channels);
}
size_t prevFftSize = m_fftSize;
@@ -629,7 +608,7 @@ RubberBandStretcher::Impl::configure()
for (set<size_t>::const_iterator i = windowSizes.begin();
i != windowSizes.end(); ++i) {
if (m_windows.find(*i) == m_windows.end()) {
m_windows[*i] = new Window<float>(HanningWindow, *i);
m_windows[*i] = new Window<float>(HannWindow, *i);
}
if (m_sincs.find(*i) == m_sincs.end()) {
m_sincs[*i] = new SincWindow<float>(*i, *i);
@@ -639,9 +618,8 @@ RubberBandStretcher::Impl::configure()
m_afilter = m_sincs[m_aWindowSize];
m_swindow = m_windows[m_sWindowSize];
if (m_debugLevel > 0) {
cerr << "Window area: " << m_awindow->getArea() << "; synthesis window area: " << m_swindow->getArea() << endl;
}
m_log.log(1, "analysis and synthesis window areas",
m_awindow->getArea(), m_swindow->getArea());
}
if (windowSizeChanged || outbufSizeChanged) {
@@ -662,12 +640,12 @@ RubberBandStretcher::Impl::configure()
if (!m_realtime && fftSizeChanged) {
delete m_studyFFT;
m_studyFFT = new FFT(m_fftSize, m_debugLevel);
m_studyFFT = new FFT(m_fftSize, m_log.getDebugLevel());
m_studyFFT->initFloat();
}
if (m_pitchScale != 1.0 ||
(m_options & OptionPitchHighConsistency) ||
(m_options & RubberBandStretcher::OptionPitchHighConsistency) ||
m_realtime) {
for (size_t c = 0; c < m_channels; ++c) {
@@ -687,7 +665,8 @@ RubberBandStretcher::Impl::configure()
}
params.maxBufferSize = 4096 * 16;
params.debugLevel = (m_debugLevel > 0 ? m_debugLevel-1 : 0);
int myLevel = m_log.getDebugLevel();
params.debugLevel = (myLevel > 0 ? myLevel-1 : 0);
m_channelData[c]->resampler = new Resampler(params, 1);
@@ -701,10 +680,6 @@ RubberBandStretcher::Impl::configure()
}
}
// stretchAudioCurve is unused in RT mode; phaseResetAudioCurve,
// silentAudioCurve and stretchCalculator however are used in all
// modes
delete m_phaseResetAudioCurve;
m_phaseResetAudioCurve = new CompoundAudioCurve
(CompoundAudioCurve::Parameters(m_sampleRate, m_fftSize));
@@ -714,23 +689,13 @@ RubberBandStretcher::Impl::configure()
m_silentAudioCurve = new SilentAudioCurve
(SilentAudioCurve::Parameters(m_sampleRate, m_fftSize));
if (!m_realtime) {
delete m_stretchAudioCurve;
if (!(m_options & OptionStretchPrecise)) {
m_stretchAudioCurve = new SpectralDifferenceAudioCurve
(SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_fftSize));
} else {
m_stretchAudioCurve = new ConstantAudioCurve
(ConstantAudioCurve::Parameters(m_sampleRate, m_fftSize));
}
}
delete m_stretchCalculator;
m_stretchCalculator = new StretchCalculator
(m_sampleRate, m_increment,
!(m_options & OptionTransientsSmooth));
!(m_options & RubberBandStretcher::OptionTransientsSmooth),
m_log);
m_stretchCalculator->setDebugLevel(m_debugLevel);
m_stretchCalculator->setDebugLevel(m_log.getDebugLevel());
m_inputDuration = 0;
// Prepare the inbufs with half a chunk of emptiness. The centre
@@ -745,19 +710,18 @@ RubberBandStretcher::Impl::configure()
// want gaps when the ratio changes.
if (!m_realtime) {
if (m_debugLevel > 1) {
cerr << "Not real time mode: prefilling with " << m_aWindowSize/2 << " samples" << endl;
}
m_log.log(1, "offline mode: prefilling with", m_aWindowSize/2);
for (size_t c = 0; c < m_channels; ++c) {
m_channelData[c]->reset();
m_channelData[c]->inbuf->zero(m_aWindowSize/2);
}
} else {
m_log.log(1, "realtime mode: no prefill");
}
}
void
RubberBandStretcher::Impl::reconfigure()
R2Stretcher::reconfigure()
{
if (!m_realtime) {
if (m_mode == Studying) {
@@ -765,7 +729,6 @@ RubberBandStretcher::Impl::reconfigure()
// the df vectors
calculateStretch();
m_phaseResetDf.clear();
m_stretchDf.clear();
m_silence.clear();
m_inputDuration = 0;
}
@@ -792,17 +755,17 @@ RubberBandStretcher::Impl::reconfigure()
m_sWindowSize != prevSWindowSize) {
if (m_windows.find(m_aWindowSize) == m_windows.end()) {
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_aWindowSize << ") required in RT mode" << std::endl;
m_log.log(0, "WARNING: reconfigure(): window allocation required in realtime mode, size", m_aWindowSize);
m_windows[m_aWindowSize] = new Window<float>
(HanningWindow, m_aWindowSize);
(HannWindow, m_aWindowSize);
m_sincs[m_aWindowSize] = new SincWindow<float>
(m_aWindowSize, m_aWindowSize);
}
if (m_windows.find(m_sWindowSize) == m_windows.end()) {
std::cerr << "WARNING: reconfigure(): window allocation (size " << m_sWindowSize << ") required in RT mode" << std::endl;
m_log.log(0, "WARNING: reconfigure(): window allocation required in realtime mode, size", m_sWindowSize);
m_windows[m_sWindowSize] = new Window<float>
(HanningWindow, m_sWindowSize);
(HannWindow, m_sWindowSize);
m_sincs[m_sWindowSize] = new SincWindow<float>
(m_sWindowSize, m_sWindowSize);
}
@@ -831,14 +794,15 @@ RubberBandStretcher::Impl::reconfigure()
if (m_channelData[c]->resampler) continue;
std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
m_log.log(0, "WARNING: reconfigure(): resampler construction required in RT mode");
Resampler::Parameters params;
params.quality = Resampler::FastestTolerable;
params.dynamism = Resampler::RatioOftenChanging;
params.ratioChange = Resampler::SmoothRatioChange;
params.maxBufferSize = m_sWindowSize;
params.debugLevel = (m_debugLevel > 0 ? m_debugLevel-1 : 0);
int myLevel = m_log.getDebugLevel();
params.debugLevel = (myLevel > 0 ? myLevel-1 : 0);
m_channelData[c]->resampler = new Resampler(params, 1);
@@ -854,59 +818,61 @@ RubberBandStretcher::Impl::reconfigure()
if (m_fftSize != prevFftSize) {
m_phaseResetAudioCurve->setFftSize(m_fftSize);
m_silentAudioCurve->setFftSize(m_fftSize);
if (m_stretchAudioCurve) {
m_stretchAudioCurve->setFftSize(m_fftSize);
}
somethingChanged = true;
}
if (m_debugLevel > 0) {
if (somethingChanged) {
std::cerr << "reconfigure: at least one parameter changed" << std::endl;
m_log.log(1, "reconfigure: at least one parameter changed");
} else {
std::cerr << "reconfigure: nothing changed" << std::endl;
}
m_log.log(1, "reconfigure: nothing changed");
}
}
size_t
RubberBandStretcher::Impl::getLatency() const
R2Stretcher::getLatency() const
{
if (!m_realtime) return 0;
return lrint((m_aWindowSize/2) / m_pitchScale);
}
void
RubberBandStretcher::Impl::setTransientsOption(Options options)
R2Stretcher::setTransientsOption(RubberBandStretcher::Options options)
{
if (!m_realtime) {
cerr << "RubberBandStretcher::Impl::setTransientsOption: Not permissible in non-realtime mode" << endl;
m_log.log(0, "R2Stretcher::setTransientsOption: Not permissible in non-realtime mode");
return;
}
int mask = (OptionTransientsMixed | OptionTransientsSmooth | OptionTransientsCrisp);
int mask = (RubberBandStretcher::OptionTransientsMixed |
RubberBandStretcher::OptionTransientsSmooth |
RubberBandStretcher::OptionTransientsCrisp);
m_options &= ~mask;
options &= mask;
m_options |= options;
m_stretchCalculator->setUseHardPeaks
(!(m_options & OptionTransientsSmooth));
(!(m_options & RubberBandStretcher::OptionTransientsSmooth));
}
void
RubberBandStretcher::Impl::setDetectorOption(Options options)
R2Stretcher::setDetectorOption(RubberBandStretcher::Options options)
{
if (!m_realtime) {
cerr << "RubberBandStretcher::Impl::setDetectorOption: Not permissible in non-realtime mode" << endl;
m_log.log(0, "R2Stretcher::setDetectorOption: Not permissible in non-realtime mode");
return;
}
int mask = (OptionDetectorPercussive | OptionDetectorCompound | OptionDetectorSoft);
int mask = (RubberBandStretcher::OptionDetectorPercussive |
RubberBandStretcher::OptionDetectorCompound |
RubberBandStretcher::OptionDetectorSoft);
m_options &= ~mask;
options &= mask;
m_options |= options;
CompoundAudioCurve::Type dt = CompoundAudioCurve::CompoundDetector;
if (m_options & OptionDetectorPercussive) dt = CompoundAudioCurve::PercussiveDetector;
else if (m_options & OptionDetectorSoft) dt = CompoundAudioCurve::SoftDetector;
if (m_options & RubberBandStretcher::OptionDetectorPercussive) {
dt = CompoundAudioCurve::PercussiveDetector;
} else if (m_options & RubberBandStretcher::OptionDetectorSoft) {
dt = CompoundAudioCurve::SoftDetector;
}
if (dt == m_detectorType) return;
m_detectorType = dt;
@@ -917,36 +883,38 @@ RubberBandStretcher::Impl::setDetectorOption(Options options)
}
void
RubberBandStretcher::Impl::setPhaseOption(Options options)
R2Stretcher::setPhaseOption(RubberBandStretcher::Options options)
{
int mask = (OptionPhaseLaminar | OptionPhaseIndependent);
int mask = (RubberBandStretcher::OptionPhaseLaminar |
RubberBandStretcher::OptionPhaseIndependent);
m_options &= ~mask;
options &= mask;
m_options |= options;
}
void
RubberBandStretcher::Impl::setFormantOption(Options options)
R2Stretcher::setFormantOption(RubberBandStretcher::Options options)
{
int mask = (OptionFormantShifted | OptionFormantPreserved);
int mask = (RubberBandStretcher::OptionFormantShifted |
RubberBandStretcher::OptionFormantPreserved);
m_options &= ~mask;
options &= mask;
m_options |= options;
}
void
RubberBandStretcher::Impl::setPitchOption(Options options)
R2Stretcher::setPitchOption(RubberBandStretcher::Options options)
{
if (!m_realtime) {
cerr << "RubberBandStretcher::Impl::setPitchOption: Pitch option is not used in non-RT mode" << endl;
m_log.log(0, "R2Stretcher::setPitchOption: Pitch option is not used in non-RT mode");
return;
}
Options prior = m_options;
RubberBandStretcher::Options prior = m_options;
int mask = (OptionPitchHighQuality |
OptionPitchHighSpeed |
OptionPitchHighConsistency);
int mask = (RubberBandStretcher::OptionPitchHighQuality |
RubberBandStretcher::OptionPitchHighSpeed |
RubberBandStretcher::OptionPitchHighConsistency);
m_options &= ~mask;
options &= mask;
m_options |= options;
@@ -955,19 +923,17 @@ RubberBandStretcher::Impl::setPitchOption(Options options)
}
void
RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool final)
R2Stretcher::study(const float *const *input, size_t samples, bool final)
{
Profiler profiler("RubberBandStretcher::Impl::study");
Profiler profiler("R2Stretcher::study");
if (m_realtime) {
if (m_debugLevel > 1) {
cerr << "RubberBandStretcher::Impl::study: Not meaningful in realtime mode" << endl;
}
m_log.log(0, "R2Stretcher::study: Not meaningful in realtime mode");
return;
}
if (m_mode == Processing || m_mode == Finished) {
cerr << "RubberBandStretcher::Impl::study: Cannot study after processing" << endl;
m_log.log(0, "R2Stretcher::study: Cannot study after processing");
return;
}
m_mode = Studying;
@@ -1010,7 +976,8 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
if (writable == 0) {
// warn
cerr << "WARNING: writable == 0 (consumed = " << consumed << ", samples = " << samples << ")" << endl;
m_log.log(0, "WARNING: writable == 0: consumed, samples",
consumed, samples);
} else {
inbuf.write(mixdown + consumed, writable);
consumed += writable;
@@ -1069,13 +1036,10 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
// cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: ";
df = m_stretchAudioCurve->processFloat(cd.fltbuf, m_increment);
m_stretchDf.push_back(df);
df = m_silentAudioCurve->processFloat(cd.fltbuf, m_increment);
bool silent = (df > 0.f);
if (silent && m_debugLevel > 1) {
cerr << "silence found at " << m_inputDuration << endl;
if (silent) {
m_log.log(2, "silence at", m_inputDuration);
}
m_silence.push_back(silent);
@@ -1089,7 +1053,6 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
// extra afterwards.
m_inputDuration += m_increment;
// cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl;
inbuf.skip(m_increment);
}
}
@@ -1097,8 +1060,6 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
if (final) {
int rs = inbuf.getReadSpace();
m_inputDuration += rs;
// cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
if (m_inputDuration > m_aWindowSize/2) { // deducting the extra
m_inputDuration -= m_aWindowSize/2;
}
@@ -1108,7 +1069,7 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
}
vector<int>
RubberBandStretcher::Impl::getOutputIncrements() const
R2Stretcher::getOutputIncrements() const
{
if (!m_realtime) {
return m_outputIncrements;
@@ -1122,7 +1083,7 @@ RubberBandStretcher::Impl::getOutputIncrements() const
}
vector<float>
RubberBandStretcher::Impl::getPhaseResetCurve() const
R2Stretcher::getPhaseResetCurve() const
{
if (!m_realtime) {
return m_phaseResetDf;
@@ -1136,7 +1097,7 @@ RubberBandStretcher::Impl::getPhaseResetCurve() const
}
vector<int>
RubberBandStretcher::Impl::getExactTimePoints() const
R2Stretcher::getExactTimePoints() const
{
std::vector<int> points;
if (!m_realtime) {
@@ -1150,41 +1111,23 @@ RubberBandStretcher::Impl::getExactTimePoints() const
}
void
RubberBandStretcher::Impl::calculateStretch()
R2Stretcher::calculateStretch()
{
Profiler profiler("RubberBandStretcher::Impl::calculateStretch");
Profiler profiler("R2Stretcher::calculateStretch");
size_t inputDuration = m_inputDuration;
if (!m_realtime && m_expectedInputDuration > 0) {
if (m_expectedInputDuration != inputDuration) {
std::cerr << "RubberBandStretcher: WARNING: Actual study() duration differs from duration set by setExpectedInputDuration (" << m_inputDuration << " vs " << m_expectedInputDuration << ", diff = " << (m_expectedInputDuration - m_inputDuration) << "), using the latter for calculation" << std::endl;
m_log.log(0, "WARNING: Actual study() duration differs from duration set by setExpectedInputDuration - using the latter for calculation", m_inputDuration, m_expectedInputDuration);
inputDuration = m_expectedInputDuration;
}
}
/*
double prdm = 0, sdm = 0;
if (!m_phaseResetDf.empty()) {
for (int i = 0; i < (int)m_phaseResetDf.size(); ++i) {
prdm += m_phaseResetDf[i];
}
prdm /= m_phaseResetDf.size();
}
if (!m_stretchDf.empty()) {
for (int i = 0; i < (int)m_stretchDf.size(); ++i) {
sdm += m_stretchDf[i];
}
sdm /= m_stretchDf.size();
}
std::cerr << "phase reset df mean = " << prdm << ", stretch df mean = " << sdm << std::endl;
*/
std::vector<int> increments = m_stretchCalculator->calculate
(getEffectiveRatio(),
inputDuration,
m_phaseResetDf,
m_stretchDf);
m_phaseResetDf);
int history = 0;
for (size_t i = 0; i < increments.size(); ++i) {
@@ -1193,10 +1136,7 @@ RubberBandStretcher::Impl::calculateStretch()
else history = 0;
if (history >= int(m_aWindowSize / m_increment) && increments[i] >= 0) {
increments[i] = -increments[i];
if (m_debugLevel > 1) {
std::cerr << "phase reset on silence (silent history == "
<< history << ")" << std::endl;
}
m_log.log(2, "phase reset on silence: silent history", history);
}
}
@@ -1211,16 +1151,18 @@ RubberBandStretcher::Impl::calculateStretch()
}
void
RubberBandStretcher::Impl::setDebugLevel(int level)
R2Stretcher::setDebugLevel(int level)
{
m_debugLevel = level;
if (m_stretchCalculator) m_stretchCalculator->setDebugLevel(level);
m_log.setDebugLevel(level);
if (m_stretchCalculator) {
m_stretchCalculator->setDebugLevel(level);
}
}
size_t
RubberBandStretcher::Impl::getSamplesRequired() const
R2Stretcher::getSamplesRequired() const
{
Profiler profiler("RubberBandStretcher::Impl::getSamplesRequired");
Profiler profiler("R2Stretcher::getSamplesRequired");
size_t reqd = 0;
@@ -1235,9 +1177,7 @@ RubberBandStretcher::Impl::getSamplesRequired() const
size_t rs = inbuf.getReadSpace();
size_t ws = outbuf.getReadSpace();
if (m_debugLevel > 2) {
cerr << "getSamplesRequired: ws = " << ws << ", rs = " << rs << ", m_aWindowSize = " << m_aWindowSize << endl;
}
m_log.log(3, "getSamplesRequired: ws and rs ", ws, rs);
// We should never return zero in non-threaded modes if
// available() would also return zero, i.e. if ws == 0. If we
@@ -1269,12 +1209,12 @@ RubberBandStretcher::Impl::getSamplesRequired() const
}
void
RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final)
R2Stretcher::process(const float *const *input, size_t samples, bool final)
{
Profiler profiler("RubberBandStretcher::Impl::process");
Profiler profiler("R2Stretcher::process");
if (m_mode == Finished) {
cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl;
m_log.log(0, "R2Stretcher::process: Cannot process again after final chunk");
return;
}
@@ -1287,9 +1227,7 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
if (!m_realtime) {
// See note in configure() above. Of course, we should
// never enter Studying unless we are non-RT anyway
if (m_debugLevel > 1) {
cerr << "Not real time mode: prefilling" << endl;
}
m_log.log(1, "offline mode: prefilling with", m_aWindowSize/2);
for (size_t c = 0; c < m_channels; ++c) {
m_channelData[c]->reset();
m_channelData[c]->inbuf->zero(m_aWindowSize/2);
@@ -1307,9 +1245,7 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
thread->start();
}
if (m_debugLevel > 0) {
cerr << m_channels << " threads created" << endl;
}
m_log.log(1, "created threads", m_channels);
}
#endif
@@ -1341,12 +1277,10 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
final);
if (consumed[c] < samples) {
allConsumed = false;
// cerr << "process: waiting on input consumption for channel " << c << endl;
} else {
if (final) {
m_channelData[c]->inputSize = m_channelData[c]->inCount;
}
// cerr << "process: happy with channel " << c << endl;
}
if (
#ifndef NO_THREADING
@@ -1379,14 +1313,10 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
}
#endif
if (m_debugLevel > 1) {
if (!allConsumed) cerr << "process looping" << endl;
}
m_log.log(2, "process looping");
}
if (m_debugLevel > 1) {
cerr << "process returning" << endl;
}
m_log.log(2, "process returning");
if (final) m_mode = Finished;
}

View File

@@ -24,42 +24,36 @@
#ifndef RUBBERBAND_STRETCHERIMPL_H
#define RUBBERBAND_STRETCHERIMPL_H
#include "../rubberband/RubberBandStretcher.h"
#include "../../rubberband/RubberBandStretcher.h"
#include "dsp/Window.h"
#include "dsp/SincWindow.h"
#include "dsp/FFT.h"
#include "../common/Window.h"
#include "../common/FFT.h"
#include "../common/RingBuffer.h"
#include "../common/Scavenger.h"
#include "../common/Thread.h"
#include "../common/Log.h"
#include "../common/sysutils.h"
#include "audiocurves/CompoundAudioCurve.h"
#include "base/RingBuffer.h"
#include "base/Scavenger.h"
#include "system/Thread.h"
#include "system/sysutils.h"
#include "SincWindow.h"
#include "CompoundAudioCurve.h"
#include <set>
#include <algorithm>
using namespace RubberBand;
namespace RubberBand
{
#ifdef PROCESS_SAMPLE_TYPE
typedef PROCESS_SAMPLE_TYPE process_t;
#else
typedef double process_t;
#endif
class AudioCurveCalculator;
class StretchCalculator;
class RubberBandStretcher::Impl
class R2Stretcher
{
public:
Impl(size_t sampleRate, size_t channels, Options options,
double initialTimeRatio, double initialPitchScale);
~Impl();
R2Stretcher(size_t sampleRate, size_t channels,
RubberBandStretcher::Options options,
double initialTimeRatio, double initialPitchScale,
Log log);
~R2Stretcher();
void reset();
void setTimeRatio(double ratio);
@@ -70,11 +64,11 @@ public:
size_t getLatency() const;
void setTransientsOption(Options);
void setDetectorOption(Options);
void setPhaseOption(Options);
void setFormantOption(Options);
void setPitchOption(Options);
void setTransientsOption(RubberBandStretcher::Options);
void setDetectorOption(RubberBandStretcher::Options);
void setPhaseOption(RubberBandStretcher::Options);
void setFormantOption(RubberBandStretcher::Options);
void setPitchOption(RubberBandStretcher::Options);
void setExpectedInputDuration(size_t samples);
void setMaxProcessSize(size_t samples);
@@ -106,7 +100,6 @@ public:
void calculateStretch();
void setDebugLevel(int level);
static void setDefaultDebugLevel(int level) { m_defaultDebugLevel = level; }
protected:
size_t m_sampleRate;
@@ -181,8 +174,8 @@ protected:
#endif
bool m_realtime;
Options m_options;
int m_debugLevel;
RubberBandStretcher::Options m_options;
Log m_log;
enum ProcessMode {
JustCreated,
@@ -206,12 +199,13 @@ protected:
class ProcessThread : public Thread
{
public:
ProcessThread(Impl *s, size_t c);
ProcessThread(R2Stretcher *s, size_t c);
void run();
void signalDataAvailable();
void abandon();
size_t channel() { return m_channel; }
private:
Impl *m_s;
R2Stretcher *m_s;
size_t m_channel;
Condition m_dataAvailable;
bool m_abandoning;
@@ -221,18 +215,18 @@ protected:
typedef std::set<ProcessThread *> ThreadSet;
ThreadSet m_threadSet;
#if defined HAVE_IPP && !defined USE_SPEEX
#if defined(HAVE_IPP) && !defined(NO_THREADING) && !defined(USE_BQRESAMPLER) && !defined(USE_SPEEX) && !defined(HAVE_LIBSAMPLERATE)
// Exasperatingly, the IPP polyphase resampler does not appear to
// be thread-safe as advertised -- a good reason to prefer the
// Speex alternative
// be thread-safe as advertised -- a good reason to prefer any of
// the alternatives
#define STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED 1
Mutex m_resamplerMutex;
#endif
#endif
#endif // ! NO_THREADING
size_t m_inputDuration;
CompoundAudioCurve::Type m_detectorType;
std::vector<float> m_phaseResetDf;
std::vector<float> m_stretchDf;
std::vector<bool> m_silence;
int m_silentHistory;
@@ -246,7 +240,6 @@ protected:
Scavenger<RingBuffer<float> > m_emergencyScavenger;
CompoundAudioCurve *m_phaseResetAudioCurve;
AudioCurveCalculator *m_stretchAudioCurve;
AudioCurveCalculator *m_silentAudioCurve;
StretchCalculator *m_stretchCalculator;
@@ -260,7 +253,6 @@ protected:
void writeOutput(RingBuffer<float> &to, float *from,
size_t qty, size_t &outCount, size_t theoreticalOut);
static int m_defaultDebugLevel;
static const size_t m_defaultIncrement;
static const size_t m_defaultFftSize;
};

View File

@@ -24,7 +24,7 @@
#ifndef RUBBERBAND_SILENT_AUDIO_CURVE_H
#define RUBBERBAND_SILENT_AUDIO_CURVE_H
#include "../dsp/AudioCurveCalculator.h"
#include "AudioCurveCalculator.h"
namespace RubberBand
{

View File

@@ -29,9 +29,9 @@
#include <cstdlib>
#include <map>
#include "../system/sysutils.h"
#include "../system/VectorOps.h"
#include "../system/Allocators.h"
#include "../common/sysutils.h"
#include "../common/VectorOps.h"
#include "../common/Allocators.h"
namespace RubberBand {

View File

@@ -23,16 +23,15 @@
#include "StretcherChannelData.h"
#include "dsp/Resampler.h"
#include "system/Allocators.h"
#include "../common/Resampler.h"
#include "../common/Allocators.h"
#include <algorithm>
namespace RubberBand
{
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
R2Stretcher::ChannelData::ChannelData(size_t windowSize,
size_t fftSize,
size_t outbufSize)
{
@@ -40,7 +39,7 @@ RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
construct(s, windowSize, fftSize, outbufSize);
}
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &sizes,
R2Stretcher::ChannelData::ChannelData(const std::set<size_t> &sizes,
size_t initialWindowSize,
size_t initialFftSize,
size_t outbufSize)
@@ -49,7 +48,7 @@ RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &size
}
void
RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
R2Stretcher::ChannelData::construct(const std::set<size_t> &sizes,
size_t initialWindowSize,
size_t initialFftSize,
size_t outbufSize)
@@ -57,8 +56,6 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
size_t maxSize = initialWindowSize * 2;
if (initialFftSize > maxSize) maxSize = initialFftSize;
// std::cerr << "ChannelData::construct: initialWindowSize = " << initialWindowSize << ", initialFftSize = " << initialFftSize << ", outbufSize = " << outbufSize << std::endl;
// std::set is ordered by value
std::set<size_t>::const_iterator i = sizes.end();
if (i != sizes.begin()) {
@@ -69,8 +66,6 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
// max possible size of the real "half" of freq data
size_t realSize = maxSize / 2 + 1;
// std::cerr << "ChannelData::construct([" << sizes.size() << "], " << maxSize << ", " << realSize << ", " << outbufSize << ")" << std::endl;
if (outbufSize < maxSize) outbufSize = maxSize;
inbuf = new RingBuffer<float>(maxSize);
@@ -115,11 +110,9 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &sizes,
void
RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
R2Stretcher::ChannelData::setSizes(size_t windowSize,
size_t fftSize)
{
// std::cerr << "ChannelData::setSizes: windowSize = " << windowSize << ", fftSize = " << fftSize << std::endl;
size_t maxSize = 2 * std::max(windowSize, fftSize);
size_t realSize = maxSize / 2 + 1;
size_t oldMax = inbuf->getSize();
@@ -207,12 +200,10 @@ RubberBandStretcher::Impl::ChannelData::setSizes(size_t windowSize,
}
void
RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
R2Stretcher::ChannelData::setOutbufSize(size_t outbufSize)
{
size_t oldSize = outbuf->getSize();
// std::cerr << "ChannelData::setOutbufSize(" << outbufSize << ") [from " << oldSize << "]" << std::endl;
if (oldSize < outbufSize) {
//!!! at this point we need a lock in case a different client
@@ -225,13 +216,13 @@ RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
}
void
RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
R2Stretcher::ChannelData::setResampleBufSize(size_t sz)
{
resamplebuf = reallocate_and_zero<float>(resamplebuf, resamplebufSize, sz);
resamplebufSize = sz;
}
RubberBandStretcher::Impl::ChannelData::~ChannelData()
R2Stretcher::ChannelData::~ChannelData()
{
delete resampler;
@@ -260,7 +251,7 @@ RubberBandStretcher::Impl::ChannelData::~ChannelData()
}
void
RubberBandStretcher::Impl::ChannelData::reset()
R2Stretcher::ChannelData::reset()
{
inbuf->reset();
outbuf->reset();

View File

@@ -24,7 +24,7 @@
#ifndef RUBBERBAND_STRETCHERCHANNELDATA_H
#define RUBBERBAND_STRETCHERCHANNELDATA_H
#include "StretcherImpl.h"
#include "R2Stretcher.h"
#include <set>
#include <atomic>
@@ -34,7 +34,7 @@ namespace RubberBand
class Resampler;
class RubberBandStretcher::Impl::ChannelData
class R2Stretcher::ChannelData
{
public:
/**

View File

@@ -21,19 +21,15 @@
you must obtain a valid commercial licence before doing so.
*/
#include "StretcherImpl.h"
#include "audiocurves/PercussiveAudioCurve.h"
#include "audiocurves/HighFrequencyAudioCurve.h"
#include "audiocurves/ConstantAudioCurve.h"
#include "StretchCalculator.h"
#include "R2Stretcher.h"
#include "StretcherChannelData.h"
#include "dsp/Resampler.h"
#include "base/Profiler.h"
#include "system/VectorOps.h"
#include "system/sysutils.h"
#include "../common/StretchCalculator.h"
#include "../common/Resampler.h"
#include "../common/Profiler.h"
#include "../common/VectorOps.h"
#include "../common/sysutils.h"
#include "../common/mathmisc.h"
#include <cassert>
#include <cmath>
@@ -44,14 +40,11 @@
using namespace RubberBand;
using std::cerr;
using std::endl;
namespace RubberBand {
#ifndef NO_THREADING
RubberBandStretcher::Impl::ProcessThread::ProcessThread(Impl *s, size_t c) :
R2Stretcher::ProcessThread::ProcessThread(R2Stretcher *s, size_t c) :
m_s(s),
m_channel(c),
m_dataAvailable(std::string("data ") + char('A' + c)),
@@ -59,22 +52,15 @@ RubberBandStretcher::Impl::ProcessThread::ProcessThread(Impl *s, size_t c) :
{ }
void
RubberBandStretcher::Impl::ProcessThread::run()
R2Stretcher::ProcessThread::run()
{
if (m_s->m_debugLevel > 1) {
cerr << "thread " << m_channel << " getting going" << endl;
}
m_s->m_log.log(2, "thread getting going for channel", m_channel);
ChannelData &cd = *m_s->m_channelData[m_channel];
while (cd.inputSize == -1 ||
cd.inbuf->getReadSpace() > 0) {
// if (cd.inputSize != -1) {
// cerr << "inputSize == " << cd.inputSize
// << ", readSpace == " << cd.inbuf->getReadSpace() << endl;
// }
bool any = false, last = false;
m_s->processChunks(m_channel, any, last);
@@ -93,9 +79,7 @@ RubberBandStretcher::Impl::ProcessThread::run()
m_dataAvailable.unlock();
if (m_abandoning) {
if (m_s->m_debugLevel > 1) {
cerr << "thread " << m_channel << " abandoning" << endl;
}
m_s->m_log.log(2, "thread abandoning for channel", m_channel);
return;
}
}
@@ -106,13 +90,11 @@ RubberBandStretcher::Impl::ProcessThread::run()
m_s->m_spaceAvailable.signal();
m_s->m_spaceAvailable.unlock();
if (m_s->m_debugLevel > 1) {
cerr << "thread " << m_channel << " done" << endl;
}
m_s->m_log.log(2, "thread done for channel", m_channel);
}
void
RubberBandStretcher::Impl::ProcessThread::signalDataAvailable()
R2Stretcher::ProcessThread::signalDataAvailable()
{
m_dataAvailable.lock();
m_dataAvailable.signal();
@@ -120,7 +102,7 @@ RubberBandStretcher::Impl::ProcessThread::signalDataAvailable()
}
void
RubberBandStretcher::Impl::ProcessThread::abandon()
R2Stretcher::ProcessThread::abandon()
{
m_abandoning = true;
}
@@ -128,16 +110,16 @@ RubberBandStretcher::Impl::ProcessThread::abandon()
#endif
bool
RubberBandStretcher::Impl::resampleBeforeStretching() const
R2Stretcher::resampleBeforeStretching() const
{
// We can't resample before stretching in offline mode, because
// the stretch calculation is based on doing it the other way
// around. It would take more work (and testing) to enable this.
if (!m_realtime) return false;
if (m_options & OptionPitchHighQuality) {
if (m_options & RubberBandStretcher::OptionPitchHighQuality) {
return (m_pitchScale < 1.0); // better sound
} else if (m_options & OptionPitchHighConsistency) {
} else if (m_options & RubberBandStretcher::OptionPitchHighConsistency) {
return false;
} else {
return (m_pitchScale > 1.0); // better performance
@@ -145,7 +127,7 @@ RubberBandStretcher::Impl::resampleBeforeStretching() const
}
void
RubberBandStretcher::Impl::prepareChannelMS(size_t c,
R2Stretcher::prepareChannelMS(size_t c,
const float *const *inputs,
size_t offset,
size_t samples,
@@ -165,13 +147,13 @@ RubberBandStretcher::Impl::prepareChannelMS(size_t c,
}
size_t
RubberBandStretcher::Impl::consumeChannel(size_t c,
R2Stretcher::consumeChannel(size_t c,
const float *const *inputs,
size_t offset,
size_t samples,
bool final)
{
Profiler profiler("RubberBandStretcher::Impl::consumeChannel");
Profiler profiler("R2Stretcher::consumeChannel");
ChannelData &cd = *m_channelData[c];
RingBuffer<float> &inbuf = *cd.inbuf;
@@ -183,13 +165,14 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
const float *input = 0;
bool useMidSide = ((m_options & OptionChannelsTogether) &&
bool useMidSide =
((m_options & RubberBandStretcher::OptionChannelsTogether) &&
(m_channels >= 2) &&
(c < 2));
if (resampling) {
Profiler profiler2("RubberBandStretcher::Impl::resample");
Profiler profiler2("R2Stretcher::resample");
toWrite = int(ceil(samples / m_pitchScale));
if (writable < toWrite) {
@@ -208,17 +191,14 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
size_t reqSize = int(ceil(samples / m_pitchScale));
if (reqSize > cd.resamplebufSize) {
cerr << "WARNING: RubberBandStretcher::Impl::consumeChannel: resizing resampler buffer from "
<< cd.resamplebufSize << " to " << reqSize << endl;
m_log.log(0, "WARNING: R2Stretcher::consumeChannel: resizing resampler buffer from and to", cd.resamplebufSize, reqSize);
cd.setResampleBufSize(reqSize);
}
#ifndef NO_THREADING
#if defined HAVE_IPP && !defined USE_SPEEX
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
if (m_threaded) {
m_resamplerMutex.lock();
}
#endif
#endif
if (useMidSide) {
@@ -235,12 +215,10 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
1.0 / m_pitchScale,
final);
#ifndef NO_THREADING
#if defined HAVE_IPP && !defined USE_SPEEX
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
if (m_threaded) {
m_resamplerMutex.unlock();
}
#endif
#endif
}
@@ -273,9 +251,9 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
}
void
RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
R2Stretcher::processChunks(size_t c, bool &any, bool &last)
{
Profiler profiler("RubberBandStretcher::Impl::processChunks");
Profiler profiler("R2Stretcher::processChunks");
// Process as many chunks as there are available on the input
// buffer for channel c. This requires that the increments have
@@ -293,9 +271,7 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
while (!last) {
if (!testInbufReadSpace(c)) {
if (m_debugLevel > 1) {
cerr << "processChunks: out of input" << endl;
}
m_log.log(2, "processChunks: out of input");
break;
}
@@ -318,9 +294,7 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
(c, phaseIncrement, shiftIncrement, phaseReset);
} else {
size_t bit = m_aWindowSize/4;
if (m_debugLevel > 1) {
cerr << "channel " << c << " breaking down overlong increment " << shiftIncrement << " into " << bit << "-size bits" << endl;
}
m_log.log(2, "breaking down overlong increment into chunks from and to", shiftIncrement, bit);
if (!tmp) tmp = allocate<float>(m_aWindowSize);
analyseChunk(c);
v_copy(tmp, cd.fltbuf, m_aWindowSize);
@@ -337,18 +311,17 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
}
cd.chunkCount++;
if (m_debugLevel > 2) {
cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl;
}
m_log.log(3, "channel/last", c, last);
m_log.log(3, "channel/chunkCount", c, cd.chunkCount);
}
if (tmp) deallocate(tmp);
}
bool
RubberBandStretcher::Impl::processOneChunk()
R2Stretcher::processOneChunk()
{
Profiler profiler("RubberBandStretcher::Impl::processOneChunk");
Profiler profiler("R2Stretcher::processOneChunk");
// Process a single chunk for all channels, provided there is
// enough data on each channel for at least one chunk. This is
@@ -358,9 +331,7 @@ RubberBandStretcher::Impl::processOneChunk()
for (size_t c = 0; c < m_channels; ++c) {
if (!testInbufReadSpace(c)) {
if (m_debugLevel > 1) {
cerr << "processOneChunk: out of input" << endl;
}
m_log.log(2, "processOneChunk: out of input");
return false;
}
ChannelData &cd = *m_channelData[c];
@@ -389,9 +360,9 @@ RubberBandStretcher::Impl::processOneChunk()
}
bool
RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
R2Stretcher::testInbufReadSpace(size_t c)
{
Profiler profiler("RubberBandStretcher::Impl::testInbufReadSpace");
Profiler profiler("R2Stretcher::testInbufReadSpace");
ChannelData &cd = *m_channelData[c];
RingBuffer<float> &inbuf = *cd.inbuf;
@@ -412,11 +383,7 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
#ifndef NO_THREADING
if (!m_threaded) {
#endif
if (m_debugLevel > 1) {
cerr << "Note: RubberBandStretcher: read space < chunk size ("
<< inbuf.getReadSpace() << " < " << m_aWindowSize
<< ") when not all input written, on processChunks for channel " << c << endl;
}
m_log.log(2, "Note: read space < chunk size when not all input written", inbuf.getReadSpace(), m_aWindowSize);
#ifndef NO_THREADING
}
@@ -425,18 +392,10 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
}
if (rs == 0) {
if (m_debugLevel > 1) {
cerr << "read space = 0, giving up" << endl;
}
m_log.log(2, "read space = 0, giving up");
return false;
} else if (rs < m_aWindowSize/2) {
if (m_debugLevel > 1) {
cerr << "read space = " << rs << ", setting draining true" << endl;
}
m_log.log(2, "setting draining true with read space", rs);
cd.draining = true;
}
}
@@ -445,21 +404,21 @@ RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
}
bool
RubberBandStretcher::Impl::processChunkForChannel(size_t c,
R2Stretcher::processChunkForChannel(size_t c,
size_t phaseIncrement,
size_t shiftIncrement,
bool phaseReset)
{
Profiler profiler("RubberBandStretcher::Impl::processChunkForChannel");
Profiler profiler("R2Stretcher::processChunkForChannel");
// Process a single chunk on a single channel. This assumes
// enough input data is available; caller must have tested this
// using e.g. testInbufReadSpace first. Return true if this is
// the last chunk on the channel.
if (phaseReset && (m_debugLevel > 1)) {
cerr << "processChunkForChannel: phase reset found, incrs "
<< phaseIncrement << ":" << shiftIncrement << endl;
if (phaseReset) {
m_log.log(2, "processChunkForChannel: phase reset found, increments",
phaseIncrement, shiftIncrement);
}
ChannelData &cd = *m_channelData[c];
@@ -482,7 +441,7 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
modifyChunk(c, phaseIncrement, phaseReset);
synthesiseChunk(c, shiftIncrement); // reads from cd.mag, cd.phase
if (m_debugLevel > 2) {
if (m_log.getDebugLevel() > 2) {
if (phaseReset) {
for (int i = 0; i < 10; ++i) {
cd.accumulator[i] = 1.2f - (i % 3) * 1.2f;
@@ -494,19 +453,13 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
bool last = false;
if (cd.draining) {
if (m_debugLevel > 1) {
cerr << "draining: accumulator fill = " << cd.accumulatorFill << " (shiftIncrement = " << shiftIncrement << ")" << endl;
}
m_log.log(2, "draining: accumulator fill and shift increment", cd.accumulatorFill, shiftIncrement);
if (shiftIncrement == 0) {
cerr << "WARNING: draining: shiftIncrement == 0, can't handle that in this context: setting to " << m_increment << endl;
m_log.log(0, "WARNING: draining: shiftIncrement == 0, can't handle that in this context: setting to", m_increment);
shiftIncrement = m_increment;
}
if (cd.accumulatorFill <= shiftIncrement) {
if (m_debugLevel > 1) {
cerr << "reducing shift increment from " << shiftIncrement
<< " to " << cd.accumulatorFill
<< " and marking as last" << endl;
}
m_log.log(2, "draining: marking as last and reducing shift increment from and to", shiftIncrement, cd.accumulatorFill);
shiftIncrement = cd.accumulatorFill;
last = true;
}
@@ -520,9 +473,7 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
int ws = cd.outbuf->getWriteSpace();
if (ws < required) {
if (m_debugLevel > 0) {
cerr << "Buffer overrun on output for channel " << c << endl;
}
m_log.log(1, "Buffer overrun on output for channel", c);
// The only correct thing we can do here is resize the buffer.
// We can't wait for the client thread to read some data out
@@ -535,11 +486,9 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
RingBuffer<float> *oldbuf = cd.outbuf;
cd.outbuf = oldbuf->resized(oldbuf->getSize() * 2);
if (m_debugLevel > 1) {
cerr << "(Write space was " << ws << ", needed " << required
<< ": resized output buffer from " << oldbuf->getSize()
<< " to " << cd.outbuf->getSize() << ")" << endl;
}
m_log.log(2, "write space and space needed", ws, required);
m_log.log(2, "resized output buffer from and to", oldbuf->getSize(),
cd.outbuf->getSize());
m_emergencyScavenger.claim(oldbuf);
}
@@ -549,13 +498,11 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
}
void
RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
R2Stretcher::calculateIncrements(size_t &phaseIncrementRtn,
size_t &shiftIncrementRtn,
bool &phaseReset)
{
Profiler profiler("RubberBandStretcher::Impl::calculateIncrements");
// cerr << "calculateIncrements" << endl;
Profiler profiler("R2Stretcher::calculateIncrements");
// Calculate the next upcoming phase and shift increment, on the
// basis that both channels are in sync. This is in contrast to
@@ -579,7 +526,7 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
size_t bc = cd.chunkCount;
for (size_t c = 1; c < m_channels; ++c) {
if (m_channelData[c]->chunkCount != bc) {
cerr << "ERROR: RubberBandStretcher::Impl::calculateIncrements: Channels are not in sync" << endl;
m_log.log(0, "ERROR: R2Stretcher::calculateIncrements: Channels are not in sync");
return;
}
}
@@ -634,7 +581,7 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
int incr = m_stretchCalculator->calculateSingle
(m_timeRatio, effectivePitchRatio, df, m_increment,
m_aWindowSize, m_sWindowSize);
m_aWindowSize, m_sWindowSize, false);
if (m_lastProcessPhaseResetDf.getWriteSpace() > 0) {
m_lastProcessPhaseResetDf.write(&df, 1);
@@ -676,20 +623,17 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
if (m_silentHistory >= int(m_aWindowSize / m_increment) && !phaseReset) {
phaseReset = true;
if (m_debugLevel > 1) {
cerr << "calculateIncrements: phase reset on silence (silent history == "
<< m_silentHistory << ")" << endl;
}
m_log.log(2, "calculateIncrements: phase reset on silence: silent history", m_silentHistory);
}
}
bool
RubberBandStretcher::Impl::getIncrements(size_t channel,
R2Stretcher::getIncrements(size_t channel,
size_t &phaseIncrementRtn,
size_t &shiftIncrementRtn,
bool &phaseReset)
{
Profiler profiler("RubberBandStretcher::Impl::getIncrements");
Profiler profiler("R2Stretcher::getIncrements");
if (channel >= m_channels) {
phaseIncrementRtn = m_increment;
@@ -718,9 +662,6 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
bool gotData = true;
if (cd.chunkCount >= m_outputIncrements.size()) {
// cerr << "WARNING: RubberBandStretcher::Impl::getIncrements:"
// << " chunk count " << cd.chunkCount << " >= "
// << m_outputIncrements.size() << endl;
if (m_outputIncrements.size() == 0) {
phaseIncrementRtn = m_increment;
shiftIncrementRtn = m_increment;
@@ -747,12 +688,12 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
if (shiftIncrement < 0) {
shiftIncrement = -shiftIncrement;
}
/*
if (shiftIncrement >= int(m_windowSize)) {
cerr << "*** ERROR: RubberBandStretcher::Impl::processChunks: shiftIncrement " << shiftIncrement << " >= windowSize " << m_windowSize << " at " << cd.chunkCount << " (of " << m_outputIncrements.size() << ")" << endl;
shiftIncrement = m_windowSize;
if (shiftIncrement >= int(m_aWindowSize)) {
m_log.log(1, "WARNING: shiftIncrement >= analysis window size", shiftIncrement, m_aWindowSize);
m_log.log(1, "at chunk of total", cd.chunkCount, m_outputIncrements.size());
}
*/
phaseIncrementRtn = phaseIncrement;
shiftIncrementRtn = shiftIncrement;
if (cd.chunkCount == 0) phaseReset = true; // don't mess with the first chunk
@@ -760,9 +701,9 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
}
void
RubberBandStretcher::Impl::analyseChunk(size_t channel)
R2Stretcher::analyseChunk(size_t channel)
{
Profiler profiler("RubberBandStretcher::Impl::analyseChunk");
Profiler profiler("R2Stretcher::analyseChunk");
ChannelData &cd = *m_channelData[channel];
@@ -781,16 +722,16 @@ RubberBandStretcher::Impl::analyseChunk(size_t channel)
}
void
RubberBandStretcher::Impl::modifyChunk(size_t channel,
R2Stretcher::modifyChunk(size_t channel,
size_t outputIncrement,
bool phaseReset)
{
Profiler profiler("RubberBandStretcher::Impl::modifyChunk");
Profiler profiler("R2Stretcher::modifyChunk");
ChannelData &cd = *m_channelData[channel];
if (phaseReset && m_debugLevel > 1) {
cerr << "phase reset: leaving phases unmodified" << endl;
if (phaseReset) {
m_log.log(2, "phase reset: leaving phases unmodified");
}
const process_t rate = process_t(m_sampleRate);
@@ -798,8 +739,8 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
bool unchanged = cd.unchanged && (outputIncrement == m_increment);
bool fullReset = phaseReset;
bool laminar = !(m_options & OptionPhaseIndependent);
bool bandlimited = (m_options & OptionTransientsMixed);
bool laminar = !(m_options & RubberBandStretcher::OptionPhaseIndependent);
bool bandlimited = (m_options & RubberBandStretcher::OptionTransientsMixed);
int bandlow = lrint((150 * m_fftSize) / rate);
int bandhigh = lrint((1000 * m_fftSize) / rate);
@@ -911,23 +852,21 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
cd.unwrappedPhase[i] = outphase;
}
if (m_debugLevel > 2) {
cerr << "mean inheritance distance = " << distacc / count << endl;
}
m_log.log(3, "mean inheritance distance", distacc / count);
if (fullReset) unchanged = true;
cd.unchanged = unchanged;
if (unchanged && m_debugLevel > 1) {
cerr << "frame unchanged on channel " << channel << endl;
if (unchanged) {
m_log.log(2, "frame unchanged on channel", channel);
}
}
void
RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
R2Stretcher::formantShiftChunk(size_t channel)
{
Profiler profiler("RubberBandStretcher::Impl::formantShiftChunk");
Profiler profiler("R2Stretcher::formantShiftChunk");
ChannelData &cd = *m_channelData[channel];
@@ -943,8 +882,6 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
const int cutoff = m_sampleRate / 700;
// cerr <<"cutoff = "<< cutoff << ", m_sampleRate/cutoff = " << m_sampleRate/cutoff << endl;
dblbuf[0] /= 2;
dblbuf[cutoff-1] /= 2;
@@ -985,13 +922,12 @@ RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
}
void
RubberBandStretcher::Impl::synthesiseChunk(size_t channel,
R2Stretcher::synthesiseChunk(size_t channel,
size_t shiftIncrement)
{
Profiler profiler("RubberBandStretcher::Impl::synthesiseChunk");
Profiler profiler("R2Stretcher::synthesiseChunk");
if ((m_options & OptionFormantPreserved) &&
if ((m_options & RubberBandStretcher::OptionFormantPreserved) &&
(m_pitchScale != 1.0)) {
formantShiftChunk(channel);
}
@@ -1057,9 +993,9 @@ RubberBandStretcher::Impl::synthesiseChunk(size_t channel,
}
void
RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, bool last)
R2Stretcher::writeChunk(size_t channel, size_t shiftIncrement, bool last)
{
Profiler profiler("RubberBandStretcher::Impl::writeChunk");
Profiler profiler("R2Stretcher::writeChunk");
ChannelData &cd = *m_channelData[channel];
@@ -1069,8 +1005,10 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
const int sz = cd.accumulatorFill;
const int si = shiftIncrement;
if (m_debugLevel > 2) {
cerr << "writeChunk(" << channel << ", " << shiftIncrement << ", " << last << ")" << endl;
m_log.log(3, "writeChunk: channel and shiftIncrement",
channel, shiftIncrement);
if (last) {
m_log.log(3, "writeChunk: last true");
}
v_divide(accumulator, windowAccumulator, si);
@@ -1085,10 +1023,11 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
bool resampledAlready = resampleBeforeStretching();
if (!resampledAlready &&
(m_pitchScale != 1.0 || m_options & OptionPitchHighConsistency) &&
(m_pitchScale != 1.0 ||
(m_options & RubberBandStretcher::OptionPitchHighConsistency)) &&
cd.resampler) {
Profiler profiler2("RubberBandStretcher::Impl::resample");
Profiler profiler2("R2Stretcher::resample");
size_t reqSize = int(ceil(si / m_pitchScale));
if (reqSize > cd.resamplebufSize) {
@@ -1097,17 +1036,14 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
// first place. But we retain this check in case the
// pitch scale has changed since then, or the stretch
// calculator has gone mad, or something.
cerr << "WARNING: RubberBandStretcher::Impl::writeChunk: resizing resampler buffer from "
<< cd.resamplebufSize << " to " << reqSize << endl;
m_log.log(0, "WARNING: R2Stretcher::writeChunk: resizing resampler buffer from and to", cd.resamplebufSize, reqSize);
cd.setResampleBufSize(reqSize);
}
#ifndef NO_THREADING
#if defined HAVE_IPP && !defined USE_SPEEX
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
if (m_threaded) {
m_resamplerMutex.lock();
}
#endif
#endif
size_t outframes = cd.resampler->resample(&cd.resamplebuf,
@@ -1117,12 +1053,10 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
1.0 / m_pitchScale,
last);
#ifndef NO_THREADING
#if defined HAVE_IPP && !defined USE_SPEEX
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
if (m_threaded) {
m_resamplerMutex.unlock();
}
#endif
#endif
writeOutput(*cd.outbuf, cd.resamplebuf,
@@ -1144,18 +1078,16 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
} else {
cd.accumulatorFill = 0;
if (cd.draining) {
if (m_debugLevel > 1) {
cerr << "RubberBandStretcher::Impl::processChunks: setting outputComplete to true" << endl;
}
m_log.log(2, "processChunks: setting outputComplete to true");
cd.outputComplete = true;
}
}
}
void
RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t &outCount, size_t theoreticalOut)
R2Stretcher::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t &outCount, size_t theoreticalOut)
{
Profiler profiler("RubberBandStretcher::Impl::writeOutput");
Profiler profiler("R2Stretcher::writeOutput");
// In non-RT mode, we don't want to write the first startSkip
// samples, because the first chunk is centred on the start of the
@@ -1172,31 +1104,23 @@ RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_
// this is the normal case
if (theoreticalOut > 0) {
if (m_debugLevel > 1) {
cerr << "theoreticalOut = " << theoreticalOut
<< ", outCount = " << outCount
<< ", startSkip = " << startSkip
<< ", qty = " << qty << endl;
}
m_log.log(2, "theoreticalOut and outCount",
theoreticalOut, outCount);
m_log.log(2, "startSkip and qty",
startSkip, qty);
if (outCount - startSkip <= theoreticalOut &&
outCount - startSkip + qty > theoreticalOut) {
qty = theoreticalOut - (outCount - startSkip);
if (m_debugLevel > 1) {
cerr << "reduce qty to " << qty << endl;
}
m_log.log(2, "reducing qty to", qty);
}
}
if (m_debugLevel > 2) {
cerr << "writing " << qty << endl;
}
m_log.log(3, "writing", qty);
size_t written = to.write(from, qty);
if (written < qty) {
cerr << "WARNING: RubberBandStretcher::Impl::writeOutput: "
<< "Buffer overrun on output: wrote " << written
<< " of " << qty << " samples" << endl;
m_log.log(0, "WARNING: writeOutput: buffer overrun: wanted to write and able to write", qty, written);
}
outCount += written;
@@ -1206,30 +1130,24 @@ RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_
// the rest of this is only used during the first startSkip samples
if (outCount + qty <= startSkip) {
if (m_debugLevel > 1) {
cerr << "qty = " << qty << ", startSkip = "
<< startSkip << ", outCount = " << outCount
<< ", discarding" << endl;
}
m_log.log(2, "discarding with startSkip", startSkip);
m_log.log(2, "qty and outCount", qty, outCount);
outCount += qty;
return;
}
size_t off = startSkip - outCount;
if (m_debugLevel > 1) {
cerr << "qty = " << qty << ", startSkip = "
<< startSkip << ", outCount = " << outCount
<< ", writing " << qty - off
<< " from start offset " << off << endl;
}
m_log.log(2, "shortening with startSkip", startSkip);
m_log.log(2, "qty and outCount", qty, outCount);
m_log.log(2, "start offset and number written", off, qty - off);
to.write(from + off, qty - off);
outCount += qty;
}
int
RubberBandStretcher::Impl::available() const
R2Stretcher::available() const
{
Profiler profiler("RubberBandStretcher::Impl::available");
Profiler profiler("R2Stretcher::available");
#ifndef NO_THREADING
if (m_threaded) {
@@ -1245,15 +1163,12 @@ RubberBandStretcher::Impl::available() const
#endif
for (size_t c = 0; c < m_channels; ++c) {
if (m_channelData[c]->inputSize >= 0) {
// cerr << "available: m_done true" << endl;
if (m_channelData[c]->inbuf->getReadSpace() > 0) {
if (m_debugLevel > 1) {
cerr << "calling processChunks(" << c << ") from available" << endl;
}
m_log.log(2, "calling processChunks from available, channel" , c);
//!!! do we ever actually do this? if so, this method should not be const
// ^^^ yes, we do sometimes -- e.g. when fed a very short file
bool any = false, last = false;
((RubberBandStretcher::Impl *)this)->processChunks(c, any, last);
((R2Stretcher *)this)->processChunks(c, any, last);
}
}
}
@@ -1268,9 +1183,7 @@ RubberBandStretcher::Impl::available() const
for (size_t i = 0; i < m_channels; ++i) {
size_t availIn = m_channelData[i]->inbuf->getReadSpace();
size_t availOut = m_channelData[i]->outbuf->getReadSpace();
if (m_debugLevel > 2) {
cerr << "available on channel " << i << ": " << availOut << " (waiting: " << availIn << ")" << endl;
}
m_log.log(3, "available in and out", availIn, availOut);
if (i == 0 || availOut < min) min = availOut;
if (!m_channelData[i]->outputComplete) consumed = false;
if (m_channelData[i]->resampler) haveResamplers = true;
@@ -1284,9 +1197,9 @@ RubberBandStretcher::Impl::available() const
}
size_t
RubberBandStretcher::Impl::retrieve(float *const *output, size_t samples) const
R2Stretcher::retrieve(float *const *output, size_t samples) const
{
Profiler profiler("RubberBandStretcher::Impl::retrieve");
Profiler profiler("R2Stretcher::retrieve");
size_t got = samples;
@@ -1294,15 +1207,14 @@ RubberBandStretcher::Impl::retrieve(float *const *output, size_t samples) const
size_t gotHere = m_channelData[c]->outbuf->read(output[c], got);
if (gotHere < got) {
if (c > 0) {
if (m_debugLevel > 0) {
cerr << "RubberBandStretcher::Impl::retrieve: WARNING: channel imbalance detected" << endl;
}
m_log.log(0, "R2Stretcher::retrieve: WARNING: channel imbalance detected");
}
got = gotHere;
}
}
if ((m_options & OptionChannelsTogether) && (m_channels >= 2)) {
if ((m_options & RubberBandStretcher::OptionChannelsTogether) &&
(m_channels >= 2)) {
for (size_t i = 0; i < got; ++i) {
float mid = output[0][i];
float side = output[1][i];

149
src/finer/BinClassifier.h Normal file
View File

@@ -0,0 +1,149 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band Library
An audio time-stretching and pitch-shifting library.
Copyright 2007-2022 Particular Programs Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
Alternatively, if you have a valid commercial licence for the
Rubber Band Library obtained by agreement with the copyright
holders, you may redistribute and/or modify it under the terms
described in that licence.
If you wish to distribute code using the Rubber Band Library
under terms other than those of the GNU General Public License,
you must obtain a valid commercial licence before doing so.
*/
#ifndef RUBBERBAND_BIN_CLASSIFIER_H
#define RUBBERBAND_BIN_CLASSIFIER_H
#include "../common/Allocators.h"
#include "../common/MovingMedian.h"
#include "../common/RingBuffer.h"
#include <vector>
#include <memory>
namespace RubberBand {
class BinClassifier
{
public:
enum class Classification {
Harmonic = 0,
Percussive = 1,
Residual = 2
};
struct Parameters {
int binCount;
int horizontalFilterLength;
int horizontalFilterLag;
int verticalFilterLength;
double harmonicThreshold;
double percussiveThreshold;
Parameters(int _binCount, int _horizontalFilterLength,
int _horizontalFilterLag, int _verticalFilterLength,
double _harmonicThreshold, double _percussiveThreshold) :
binCount(_binCount),
horizontalFilterLength(_horizontalFilterLength),
horizontalFilterLag(_horizontalFilterLag),
verticalFilterLength(_verticalFilterLength),
harmonicThreshold(_harmonicThreshold),
percussiveThreshold(_percussiveThreshold) { }
};
BinClassifier(Parameters parameters) :
m_parameters(parameters),
m_hFilters(new MovingMedianStack<double>(m_parameters.binCount,
m_parameters.horizontalFilterLength)),
m_vFilter(new MovingMedian<double>(m_parameters.verticalFilterLength)),
m_vfQueue(parameters.horizontalFilterLag)
{
int n = m_parameters.binCount;
m_hf = allocate_and_zero<double>(n);
m_vf = allocate_and_zero<double>(n);
for (int i = 0; i < m_parameters.horizontalFilterLag; ++i) {
double *entry = allocate_and_zero<double>(n);
m_vfQueue.write(&entry, 1);
}
}
~BinClassifier()
{
while (m_vfQueue.getReadSpace() > 0) {
double *entry = m_vfQueue.readOne();
deallocate(entry);
}
deallocate(m_hf);
deallocate(m_vf);
}
void reset()
{
m_hFilters->reset();
}
void classify(const double *const mag, // input, of at least binCount bins
Classification *classification) // output, of binCount bins
{
const int n = m_parameters.binCount;
for (int i = 0; i < n; ++i) {
m_hFilters->push(i, mag[i]);
m_hf[i] = m_hFilters->get(i);
}
v_copy(m_vf, mag, n);
MovingMedian<double>::filter(*m_vFilter, m_vf, n);
if (m_parameters.horizontalFilterLag > 0) {
double *lagged = m_vfQueue.readOne();
m_vfQueue.write(&m_vf, 1);
m_vf = lagged;
}
double eps = 1.0e-7;
for (int i = 0; i < n; ++i) {
Classification c;
if (double(m_hf[i]) / (double(m_vf[i]) + eps) >
m_parameters.harmonicThreshold) {
c = Classification::Harmonic;
} else if (double(m_vf[i]) / (double(m_hf[i]) + eps) >
m_parameters.percussiveThreshold) {
c = Classification::Percussive;
} else {
c = Classification::Residual;
}
classification[i] = c;
}
}
protected:
Parameters m_parameters;
std::unique_ptr<MovingMedianStack<double>> m_hFilters;
std::unique_ptr<MovingMedian<double>> m_vFilter;
// We manage the queued frames through pointer swapping, hence
// bare pointers here
double *m_hf;
double *m_vf;
RingBuffer<double *> m_vfQueue;
BinClassifier(const BinClassifier &) =delete;
BinClassifier &operator=(const BinClassifier &) =delete;
};
}
#endif

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