Update from personal repository.

* Added an initial "formant preservation" option when pitch shifting
 * Real-time pitch shifting now uses a faster method by default, with
   less variation in CPU usage
 * The code is more amenable to compiler auto-vectorization (through
   e.g. gcc --ftree-vectorize).
This commit is contained in:
Chris Cannam
2008-05-22 16:54:27 +00:00
parent 52a10829ef
commit 1d41c952e8
51 changed files with 3157 additions and 676 deletions

9
CHANGELOG Normal file
View File

@@ -0,0 +1,9 @@
Changes since Rubber Band v1.0.1
* Added an initial "formant preservation" option when pitch shifting
* Real-time pitch shifting now uses a faster method by default, with
less variation in CPU usage
* The code is more amenable to compiler auto-vectorization (through
e.g. gcc --ftree-vectorize).

View File

@@ -1,6 +1,7 @@
CXX := @CXX@ CXX := @CXX@
CXXFLAGS := -DFFTW_DOUBLE_ONLY @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS) CXXFLAGS := -DHAVE_FFTW3 -DFFTW_DOUBLE_ONLY -DNO_THREAD_CHECKS @CXXFLAGS@ @SRC_CFLAGS@ @SNDFILE_CFLAGS@ @FFTW_CFLAGS@ @Vamp_CFLAGS@ -Irubberband -Isrc $(OPTFLAGS)
CFLAGS := @CFLAGS@ $(OPTFLAGS)
LDFLAGS := @LDFLAGS@ -lpthread $(LDFLAGS) LDFLAGS := @LDFLAGS@ -lpthread $(LDFLAGS)
LIBRARY_LIBS := @SRC_LIBS@ @FFTW_LIBS@ LIBRARY_LIBS := @SRC_LIBS@ @FFTW_LIBS@
@@ -29,6 +30,13 @@ INSTALL_PKGDIR := @prefix@/lib/pkgconfig
all: bin lib $(PROGRAM_TARGET) $(STATIC_TARGET) $(DYNAMIC_TARGET) $(VAMP_TARGET) $(LADSPA_TARGET) all: bin lib $(PROGRAM_TARGET) $(STATIC_TARGET) $(DYNAMIC_TARGET) $(VAMP_TARGET) $(LADSPA_TARGET)
static: $(STATIC_TARGET)
dynamic: $(DYNAMIC_TARGET)
library: $(STATIC_TARGET) $(DYNAMIC_TARGET)
program: $(PROGRAM_TARGET)
vamp: $(VAMP_TARGET)
ladspa: $(LADSPA_TARGET)
PUBLIC_INCLUDES := \ PUBLIC_INCLUDES := \
rubberband/TimeStretcher.h \ rubberband/TimeStretcher.h \
rubberband/RubberBandStretcher.h rubberband/RubberBandStretcher.h
@@ -39,6 +47,7 @@ LIBRARY_INCLUDES := \
src/FFT.h \ src/FFT.h \
src/HighFrequencyAudioCurve.h \ src/HighFrequencyAudioCurve.h \
src/PercussiveAudioCurve.h \ src/PercussiveAudioCurve.h \
src/Profiler.h \
src/Resampler.h \ src/Resampler.h \
src/RingBuffer.h \ src/RingBuffer.h \
src/Scavenger.h \ src/Scavenger.h \
@@ -51,19 +60,21 @@ LIBRARY_INCLUDES := \
src/sysutils.h src/sysutils.h
LIBRARY_SOURCES := \ LIBRARY_SOURCES := \
src/RubberBandStretcher.cpp \ src/AudioCurve.cpp \
src/ConstantAudioCurve.cpp \ src/ConstantAudioCurve.cpp \
src/FFT.cpp \
src/HighFrequencyAudioCurve.cpp \ src/HighFrequencyAudioCurve.cpp \
src/PercussiveAudioCurve.cpp \ src/PercussiveAudioCurve.cpp \
src/AudioCurve.cpp \ src/Profiler.cpp \
src/Resampler.cpp \ src/Resampler.cpp \
src/RubberBandStretcher.cpp \
src/SpectralDifferenceAudioCurve.cpp \ src/SpectralDifferenceAudioCurve.cpp \
src/StretchCalculator.cpp \ src/StretchCalculator.cpp \
src/StretcherImpl.cpp \ src/StretcherImpl.cpp \
src/StretcherProcess.cpp \ src/StretcherProcess.cpp \
src/StretcherChannelData.cpp \ src/StretcherChannelData.cpp \
src/FFT.cpp \
src/Thread.cpp \ src/Thread.cpp \
src/Window.cpp \
src/sysutils.cpp src/sysutils.cpp
PROGRAM_SOURCES := \ PROGRAM_SOURCES := \
@@ -84,6 +95,8 @@ LADSPA_SOURCES := \
src/ladspa/libmain.cpp src/ladspa/libmain.cpp
LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o) LIBRARY_OBJECTS := $(LIBRARY_SOURCES:.cpp=.o)
LIBRARY_OBJECTS := $(LIBRARY_OBJECTS:.c=.o)
PROGRAM_OBJECTS := $(PROGRAM_SOURCES:.cpp=.o) PROGRAM_OBJECTS := $(PROGRAM_SOURCES:.cpp=.o)
VAMP_OBJECTS := $(VAMP_SOURCES:.cpp=.o) VAMP_OBJECTS := $(VAMP_SOURCES:.cpp=.o)
LADSPA_OBJECTS := $(LADSPA_SOURCES:.cpp=.o) LADSPA_OBJECTS := $(LADSPA_SOURCES:.cpp=.o)
@@ -134,57 +147,94 @@ distclean: clean
# DO NOT DELETE # DO NOT DELETE
src/AudioCurve.o: src/AudioCurve.h src/AudioCurve.o: src/AudioCurve.h src/sysutils.h
src/ConstantAudioCurve.o: src/ConstantAudioCurve.h src/AudioCurve.h src/ConstantAudioCurve.o: src/ConstantAudioCurve.h src/AudioCurve.h
src/FFT.o: src/FFT.h src/Thread.h src/ConstantAudioCurve.o: src/sysutils.h
src/FFT.o: src/FFT.h src/sysutils.h src/Thread.h src/Profiler.h
src/HighFrequencyAudioCurve.o: src/HighFrequencyAudioCurve.h src/AudioCurve.h src/HighFrequencyAudioCurve.o: src/HighFrequencyAudioCurve.h src/AudioCurve.h
src/HighFrequencyAudioCurve.o: src/Window.h src/HighFrequencyAudioCurve.o: src/sysutils.h src/Window.h
src/main.o: src/sysutils.h src/main.o: rubberband/RubberBandStretcher.h rubberband/TimeStretcher.h
src/main.o: src/sysutils.h src/Profiler.h
src/PercussiveAudioCurve.o: src/PercussiveAudioCurve.h src/AudioCurve.h src/PercussiveAudioCurve.o: src/PercussiveAudioCurve.h src/AudioCurve.h
src/Resampler.o: src/Resampler.h src/PercussiveAudioCurve.o: src/sysutils.h
src/RubberBandStretcher.o: src/StretcherImpl.h src/Window.h src/Thread.h src/Profiler.o: src/Profiler.h src/sysutils.h
src/RubberBandStretcher.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h src/Resampler.o: src/Resampler.h src/sysutils.h src/Profiler.h
src/RubberBandStretcher.o: src/FFT.h src/RingBuffer.o: src/RingBuffer.h src/Scavenger.h src/Thread.h
src/RingBuffer.o: src/sysutils.h src/Profiler.h
src/RubberBandStretcher.o: src/StretcherImpl.h
src/RubberBandStretcher.o: rubberband/RubberBandStretcher.h
src/RubberBandStretcher.o: rubberband/TimeStretcher.h src/Window.h
src/RubberBandStretcher.o: src/sysutils.h src/Thread.h src/RingBuffer.h
src/RubberBandStretcher.o: src/Scavenger.h src/Profiler.h src/FFT.h
src/SpectralDifferenceAudioCurve.o: src/SpectralDifferenceAudioCurve.h src/SpectralDifferenceAudioCurve.o: src/SpectralDifferenceAudioCurve.h
src/SpectralDifferenceAudioCurve.o: src/AudioCurve.h src/Window.h src/SpectralDifferenceAudioCurve.o: src/AudioCurve.h src/sysutils.h
src/StretchCalculator.o: src/StretchCalculator.h src/SpectralDifferenceAudioCurve.o: src/Window.h
src/StretchCalculator.o: src/StretchCalculator.h src/sysutils.h
src/StretcherChannelData.o: src/StretcherChannelData.h src/StretcherImpl.h src/StretcherChannelData.o: src/StretcherChannelData.h src/StretcherImpl.h
src/StretcherChannelData.o: src/Window.h src/Thread.h src/RingBuffer.h src/StretcherChannelData.o: rubberband/RubberBandStretcher.h
src/StretcherChannelData.o: src/Scavenger.h src/sysutils.h src/FFT.h src/StretcherChannelData.o: rubberband/TimeStretcher.h src/Window.h
src/StretcherChannelData.o: src/sysutils.h src/Thread.h src/RingBuffer.h
src/StretcherChannelData.o: src/Scavenger.h src/Profiler.h src/FFT.h
src/StretcherChannelData.o: src/Resampler.h src/StretcherChannelData.o: src/Resampler.h
src/StretcherImpl.o: src/StretcherImpl.h src/Window.h src/Thread.h src/StretcherImpl.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherImpl.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h src/StretcherImpl.o: rubberband/TimeStretcher.h src/Window.h src/sysutils.h
src/StretcherImpl.o: src/FFT.h src/PercussiveAudioCurve.h src/AudioCurve.h src/StretcherImpl.o: src/Thread.h src/RingBuffer.h src/Scavenger.h
src/StretcherImpl.o: src/HighFrequencyAudioCurve.h src/StretcherImpl.o: src/Profiler.h src/FFT.h src/PercussiveAudioCurve.h
src/StretcherImpl.o: src/AudioCurve.h src/HighFrequencyAudioCurve.h
src/StretcherImpl.o: src/SpectralDifferenceAudioCurve.h src/StretcherImpl.o: src/SpectralDifferenceAudioCurve.h
src/StretcherImpl.o: src/ConstantAudioCurve.h src/StretchCalculator.h src/StretcherImpl.o: src/ConstantAudioCurve.h src/StretchCalculator.h
src/StretcherImpl.o: src/StretcherChannelData.h src/Resampler.h src/StretcherImpl.o: src/StretcherChannelData.h src/Resampler.h
src/StretcherProcess.o: src/StretcherImpl.h src/Window.h src/Thread.h src/StretcherProcess.o: src/StretcherImpl.h rubberband/RubberBandStretcher.h
src/StretcherProcess.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h src/StretcherProcess.o: rubberband/TimeStretcher.h src/Window.h
src/StretcherProcess.o: src/FFT.h src/PercussiveAudioCurve.h src/AudioCurve.h src/StretcherProcess.o: src/sysutils.h src/Thread.h src/RingBuffer.h
src/StretcherProcess.o: src/Scavenger.h src/Profiler.h src/FFT.h
src/StretcherProcess.o: src/PercussiveAudioCurve.h src/AudioCurve.h
src/StretcherProcess.o: src/HighFrequencyAudioCurve.h src/StretcherProcess.o: src/HighFrequencyAudioCurve.h
src/StretcherProcess.o: src/ConstantAudioCurve.h src/StretchCalculator.h src/StretcherProcess.o: src/ConstantAudioCurve.h src/StretchCalculator.h
src/StretcherProcess.o: src/StretcherChannelData.h src/Resampler.h src/StretcherProcess.o: src/StretcherChannelData.h src/Resampler.h
src/sysutils.o: src/sysutils.h src/sysutils.o: src/sysutils.h
src/Thread.o: src/Thread.h src/Thread.o: src/Thread.h
src/ConstantAudioCurve.o: src/AudioCurve.h src/Window.o: src/Window.h src/sysutils.h
src/HighFrequencyAudioCurve.o: src/AudioCurve.h src/Window.h rubberband/RubberBandStretcher.o: rubberband/TimeStretcher.h
src/PercussiveAudioCurve.o: src/AudioCurve.h src/AudioCurve.o: src/sysutils.h
src/RingBuffer.o: src/Scavenger.h src/Thread.h src/sysutils.h src/ConstantAudioCurve.o: src/AudioCurve.h src/sysutils.h
src/FFT.o: src/sysutils.h
src/HighFrequencyAudioCurve.o: src/AudioCurve.h src/sysutils.h src/Window.h
src/PercussiveAudioCurve.o: src/AudioCurve.h src/sysutils.h
src/Profiler.o: src/sysutils.h
src/Resampler.o: src/sysutils.h
src/RingBuffer.o: src/Scavenger.h src/Thread.h src/sysutils.h src/Profiler.h
src/Scavenger.o: src/Thread.h src/sysutils.h src/Scavenger.o: src/Thread.h src/sysutils.h
src/SpectralDifferenceAudioCurve.o: src/AudioCurve.h src/Window.h src/SpectralDifferenceAudioCurve.o: src/AudioCurve.h src/sysutils.h
src/StretcherChannelData.o: src/StretcherImpl.h src/Window.h src/Thread.h src/SpectralDifferenceAudioCurve.o: src/Window.h
src/StretcherChannelData.o: src/RingBuffer.h src/Scavenger.h src/sysutils.h src/StretcherChannelData.o: src/StretcherImpl.h
src/StretcherChannelData.o: src/FFT.h src/StretcherChannelData.o: rubberband/RubberBandStretcher.h
src/StretcherImpl.o: src/Window.h src/Thread.h src/RingBuffer.h src/StretcherChannelData.o: rubberband/TimeStretcher.h src/Window.h
src/StretcherImpl.o: src/Scavenger.h src/sysutils.h src/FFT.h src/StretcherChannelData.o: src/sysutils.h src/Thread.h src/RingBuffer.h
src/vamp/libmain.o: src/vamp/RubberBandVampPlugin.h src/StretcherChannelData.o: src/Scavenger.h src/Profiler.h src/FFT.h
src/vamp/RubberBandVampPlugin.o: src/vamp/RubberBandVampPlugin.h src/StretcherImpl.o: rubberband/RubberBandStretcher.h
src/vamp/RubberBandVampPlugin.o: src/StretchCalculator.h src/StretcherImpl.o: rubberband/TimeStretcher.h src/Window.h src/sysutils.h
src/ladspa/libmain.o: src/ladspa/RubberBandPitchShifter.h src/RingBuffer.h src/StretcherImpl.o: src/Thread.h src/RingBuffer.h src/Scavenger.h
src/ladspa/libmain.o: src/Scavenger.h src/Thread.h src/sysutils.h src/StretcherImpl.o: src/Profiler.h src/FFT.h
src/Window.o: src/sysutils.h
src/ladspa/libmain.o: src/ladspa/RubberBandPitchShifter.h
src/ladspa/libmain.o: src/RingBuffer.h src/Scavenger.h src/Thread.h
src/ladspa/libmain.o: src/sysutils.h src/Profiler.h
src/ladspa/RubberBandPitchShifter.o: src/ladspa/RubberBandPitchShifter.h src/ladspa/RubberBandPitchShifter.o: src/ladspa/RubberBandPitchShifter.h
src/ladspa/RubberBandPitchShifter.o: src/RingBuffer.h src/Scavenger.h src/ladspa/RubberBandPitchShifter.o: src/RingBuffer.h
src/ladspa/RubberBandPitchShifter.o: src/Thread.h src/sysutils.h src/ladspa/RubberBandPitchShifter.o: src/Scavenger.h src/Thread.h
src/ladspa/RubberBandPitchShifter.o: src/RingBuffer.h src/Scavenger.h src/ladspa/RubberBandPitchShifter.o: src/sysutils.h src/Profiler.h
src/ladspa/RubberBandPitchShifter.o: src/Thread.h src/sysutils.h src/ladspa/RubberBandPitchShifter.o: rubberband/RubberBandStretcher.h
src/ladspa/RubberBandPitchShifter.o: rubberband/TimeStretcher.h
src/vamp/libmain.o: src/vamp/RubberBandVampPlugin.h
src/vamp/libmain.o: rubberband/RubberBandStretcher.h
src/vamp/libmain.o: rubberband/TimeStretcher.h
src/vamp/RubberBandVampPlugin.o: src/vamp/RubberBandVampPlugin.h
src/vamp/RubberBandVampPlugin.o: rubberband/RubberBandStretcher.h
src/vamp/RubberBandVampPlugin.o: rubberband/TimeStretcher.h
src/vamp/RubberBandVampPlugin.o: src/StretchCalculator.h
src/ladspa/RubberBandPitchShifter.o: src/RingBuffer.h
src/ladspa/RubberBandPitchShifter.o: src/Scavenger.h src/Thread.h
src/ladspa/RubberBandPitchShifter.o: src/sysutils.h src/Profiler.h
src/vamp/RubberBandVampPlugin.o: rubberband/RubberBandStretcher.h
src/vamp/RubberBandVampPlugin.o: rubberband/TimeStretcher.h

2
README
View File

@@ -4,7 +4,7 @@ Rubber Band
An audio time-stretching and pitch-shifting library and utility program. An audio time-stretching and pitch-shifting library and utility program.
Copyright 2007 Chris Cannam, cannam@all-day-breakfast.com. Copyright 2008 Chris Cannam, cannam@all-day-breakfast.com.
Distributed under the GNU General Public License. Distributed under the GNU General Public License.

22
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for RubberBand 0.1. # Generated by GNU Autoconf 2.61 for RubberBand 1.1.
# #
# Report bugs to <cannam@all-day-breakfast.com>. # Report bugs to <cannam@all-day-breakfast.com>.
# #
@@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package. # Identity of this package.
PACKAGE_NAME='RubberBand' PACKAGE_NAME='RubberBand'
PACKAGE_TARNAME='rubberband' PACKAGE_TARNAME='rubberband'
PACKAGE_VERSION='0.1' PACKAGE_VERSION='1.1'
PACKAGE_STRING='RubberBand 0.1' PACKAGE_STRING='RubberBand 1.1'
PACKAGE_BUGREPORT='cannam@all-day-breakfast.com' PACKAGE_BUGREPORT='cannam@all-day-breakfast.com'
ac_unique_file="src/StretcherImpl.h" ac_unique_file="src/StretcherImpl.h"
@@ -1200,7 +1200,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures RubberBand 0.1 to adapt to many kinds of systems. \`configure' configures RubberBand 1.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1261,7 +1261,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of RubberBand 0.1:";; short | recursive ) echo "Configuration of RubberBand 1.1:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1352,7 +1352,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
RubberBand configure 0.1 RubberBand configure 1.1
generated by GNU Autoconf 2.61 generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1366,7 +1366,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by RubberBand $as_me 0.1, which was It was created by RubberBand $as_me 1.1, which was
generated by GNU Autoconf 2.61. Invocation command line was generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@ $ $0 $@
@@ -4746,6 +4746,10 @@ fi
if test "x$GCC" = "xyes"; then if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-fPIC\ -Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -fPIC -Wall" ;;
esac
case " $CXXFLAGS " in case " $CXXFLAGS " in
*[\ \ ]-fPIC\ -Wall[\ \ ]*) ;; *[\ \ ]-fPIC\ -Wall[\ \ ]*) ;;
*) CXXFLAGS="$CXXFLAGS -fPIC -Wall" ;; *) CXXFLAGS="$CXXFLAGS -fPIC -Wall" ;;
@@ -5180,7 +5184,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by RubberBand $as_me 0.1, which was This file was extended by RubberBand $as_me 1.1, which was
generated by GNU Autoconf 2.61. Invocation command line was generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -5223,7 +5227,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\ ac_cs_version="\\
RubberBand config.status 0.1 RubberBand config.status 1.1
configured by $0, generated by GNU Autoconf 2.61, configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

View File

@@ -1,5 +1,5 @@
AC_INIT(RubberBand, 0.1, cannam@all-day-breakfast.com) AC_INIT(RubberBand, 1.1, cannam@all-day-breakfast.com)
AC_CONFIG_SRCDIR(src/StretcherImpl.h) AC_CONFIG_SRCDIR(src/StretcherImpl.h)
AC_PROG_CXX AC_PROG_CXX
@@ -27,6 +27,10 @@ AC_SUBST(Vamp_LIBS)
changequote(,)dnl changequote(,)dnl
if test "x$GCC" = "xyes"; then if test "x$GCC" = "xyes"; then
case " $CFLAGS " in
*[\ \ ]-fPIC\ -Wall[\ \ ]*) ;;
*) CFLAGS="$CFLAGS -fPIC -Wall" ;;
esac
case " $CXXFLAGS " in case " $CXXFLAGS " in
*[\ \ ]-fPIC\ -Wall[\ \ ]*) ;; *[\ \ ]-fPIC\ -Wall[\ \ ]*) ;;
*) CXXFLAGS="$CXXFLAGS -fPIC -Wall" ;; *) CXXFLAGS="$CXXFLAGS -fPIC -Wall" ;;

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -19,6 +19,13 @@
#include <vector> #include <vector>
/**
* @mainpage RubberBand
*
* The Rubber Band API is contained in the single class
* RubberBand::RubberBandStretcher.
*/
namespace RubberBand namespace RubberBand
{ {
@@ -151,34 +158,72 @@ public:
* \li \c OptionWindowLong - Use a longer window. This is * \li \c OptionWindowLong - Use a longer window. This is
* likely to result in a smoother sound at the expense of * likely to result in a smoother sound at the expense of
* clarity and timing. * clarity and timing.
*
* 7. Flags prefixed \c OptionFormant control the handling of
* formant shape (spectral envelope) when pitch-shifting. These
* options may be changed at any time.
*
* \li \c OptionFormantShifted - Apply no special formant
* processing. The spectral envelope will be pitch shifted as
* normal.
*
* \li \c OptionFormantPreserved - Preserve the spectral
* envelope of the unshifted signal. This permits shifting the
* note frequency without so substantially affecting the
* perceived pitch profile of the voice or instrument.
*
* 8. 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.
*
* \li \c OptionPitchHighSpeed - Use a method with a CPU cost
* that is relatively moderate and predictable. This may
* sound less clear than OptionPitchHighQuality, especially
* for large pitch shifts.
* \li \c OptionPitchHighQuality - Use the highest quality
* method for pitch shifting. This method has a CPU cost
* approximately proportional to the required frequency shift.
*/ */
enum Option {
OptionProcessOffline = 0x00000000,
OptionProcessRealTime = 0x00000001,
OptionStretchElastic = 0x00000000,
OptionStretchPrecise = 0x00000010,
OptionTransientsCrisp = 0x00000000,
OptionTransientsMixed = 0x00000100,
OptionTransientsSmooth = 0x00000200,
OptionPhaseAdaptive = 0x00000000,
OptionPhasePeakLocked = 0x00001000,
OptionPhaseIndependent = 0x00002000,
OptionThreadingAuto = 0x00000000,
OptionThreadingNever = 0x00010000,
OptionThreadingAlways = 0x00020000,
OptionWindowStandard = 0x00000000,
OptionWindowShort = 0x00100000,
OptionWindowLong = 0x00200000,
OptionFormantShifted = 0x00000000,
OptionFormantPreserved = 0x01000000,
OptionPitchHighSpeed = 0x00000000,
OptionPitchHighQuality = 0x02000000
};
typedef int Options; typedef int Options;
static const int OptionProcessOffline = 0x00000000;
static const int OptionProcessRealTime = 0x00000001;
static const int OptionStretchElastic = 0x00000000; enum PresetOption {
static const int OptionStretchPrecise = 0x00000010; DefaultOptions = 0x00000000,
PercussiveOptions = 0x00102000
static const int OptionTransientsCrisp = 0x00000000; };
static const int OptionTransientsMixed = 0x00000100;
static const int OptionTransientsSmooth = 0x00000200;
static const int OptionPhaseAdaptive = 0x00000000;
static const int OptionPhasePeakLocked = 0x00001000;
static const int OptionPhaseIndependent = 0x00002000;
static const int OptionThreadingAuto = 0x00000000;
static const int OptionThreadingNever = 0x00010000;
static const int OptionThreadingAlways = 0x00020000;
static const int OptionWindowStandard = 0x00000000;
static const int OptionWindowShort = 0x00100000;
static const int OptionWindowLong = 0x00200000;
static const int DefaultOptions = 0x00000000;
static const int PercussiveOptions = OptionWindowShort | \
OptionPhaseIndependent;
/** /**
* Construct a time and pitch stretcher object to run at the given * Construct a time and pitch stretcher object to run at the given
@@ -293,6 +338,24 @@ public:
*/ */
virtual void setPhaseOption(Options options); virtual void setPhaseOption(Options options);
/**
* Change an OptionFormant configuration setting. This may be
* called at any time in any mode.
*
* Note that if running multi-threaded in Offline mode, the change
* may not take effect immediately if processing is already under
* way when this function is called.
*/
virtual void setFormantOption(Options options);
/**
* 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 transients option is fixed on
* construction).
*/
virtual void setPitchOption(Options options);
/** /**
* Tell the stretcher exactly how many input samples it will * Tell the stretcher exactly how many input samples it will
* receive. This is only useful in Offline mode, when it allows * receive. This is only useful in Offline mode, when it allows

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -14,6 +14,9 @@
#include "AudioCurve.h" #include "AudioCurve.h"
#include <iostream>
using namespace std;
namespace RubberBand namespace RubberBand
{ {
@@ -27,5 +30,15 @@ AudioCurve::~AudioCurve()
{ {
} }
float
AudioCurve::process(const double *R__ mag, size_t increment)
{
cerr << "WARNING: Using inefficient AudioCurve::process(double)" << endl;
float *tmp = new float[m_windowSize];
for (int i = 0; i < m_windowSize; ++i) tmp[i] = float(mag[i]);
float df = process(tmp, increment);
delete[] tmp;
return df;
}
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -17,6 +17,8 @@
#include <sys/types.h> #include <sys/types.h>
#include "sysutils.h"
namespace RubberBand namespace RubberBand
{ {
@@ -28,7 +30,8 @@ public:
virtual void setWindowSize(size_t newSize) = 0; virtual void setWindowSize(size_t newSize) = 0;
virtual float process(float *mag, size_t increment) = 0; virtual float process(const float *R__ mag, size_t increment) = 0;
virtual float process(const double *R__ mag, size_t increment);
virtual void reset() = 0; virtual void reset() = 0;
protected: protected:

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -38,7 +38,7 @@ ConstantAudioCurve::setWindowSize(size_t newSize)
} }
float float
ConstantAudioCurve::process(float *, size_t) ConstantAudioCurve::process(const float *R__, size_t)
{ {
return 1.f; return 1.f;
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -28,7 +28,7 @@ public:
virtual void setWindowSize(size_t newSize); virtual void setWindowSize(size_t newSize);
virtual float process(float *mag, size_t increment); virtual float process(const float *R__ mag, size_t increment);
virtual void reset(); virtual void reset();
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -15,6 +15,8 @@
#ifndef _RUBBERBAND_FFT_H_ #ifndef _RUBBERBAND_FFT_H_
#define _RUBBERBAND_FFT_H_ #define _RUBBERBAND_FFT_H_
#include "sysutils.h"
namespace RubberBand { namespace RubberBand {
class FFTImpl; class FFTImpl;
@@ -36,22 +38,24 @@ class FFT
public: public:
enum Exception { InvalidSize }; enum Exception { InvalidSize };
FFT(unsigned int size); // may throw InvalidSize FFT(int size, int debugLevel = 0); // may throw InvalidSize
~FFT(); ~FFT();
void forward(double *realIn, double *realOut, double *imagOut); void forward(const double *R__ realIn, double *R__ realOut, double *R__ imagOut);
void forwardPolar(double *realIn, double *magOut, double *phaseOut); void forwardPolar(const double *R__ realIn, double *R__ magOut, double *R__ phaseOut);
void forwardMagnitude(double *realIn, double *magOut); void forwardMagnitude(const double *R__ realIn, double *R__ magOut);
void forward(float *realIn, float *realOut, float *imagOut); void forward(const float *R__ realIn, float *R__ realOut, float *R__ imagOut);
void forwardPolar(float *realIn, float *magOut, float *phaseOut); void forwardPolar(const float *R__ realIn, float *R__ magOut, float *R__ phaseOut);
void forwardMagnitude(float *realIn, float *magOut); void forwardMagnitude(const float *R__ realIn, float *R__ magOut);
void inverse(double *realIn, double *imagIn, double *realOut); void inverse(const double *R__ realIn, const double *R__ imagIn, double *R__ realOut);
void inversePolar(double *magIn, double *phaseIn, double *realOut); void inversePolar(const double *R__ magIn, const double *R__ phaseIn, double *R__ realOut);
void inverseCepstral(const double *R__ magIn, double *R__ cepOut);
void inverse(float *realIn, float *imagIn, float *realOut); void inverse(const float *R__ realIn, const float *R__ imagIn, float *R__ realOut);
void inversePolar(float *magIn, float *phaseIn, float *realOut); void inversePolar(const float *R__ magIn, const float *R__ phaseIn, float *R__ realOut);
void inverseCepstral(const float *R__ magIn, float *R__ cepOut);
// Calling one or both of these is optional -- if neither is // Calling one or both of these is optional -- if neither is
// called, the first call to a forward or inverse method will call // called, the first call to a forward or inverse method will call

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -38,12 +38,14 @@ HighFrequencyAudioCurve::setWindowSize(size_t newSize)
} }
float float
HighFrequencyAudioCurve::process(float *mag, size_t increment) HighFrequencyAudioCurve::process(const float *R__ mag, size_t increment)
{ {
float result = 0.0; float result = 0.0;
for (size_t n = 0; n <= m_windowSize / 2; ++n) { const int sz = m_windowSize / 2;
result += mag[n] * n;
for (int n = 0; n <= sz; ++n) {
result = result + mag[n] * n;
} }
return result; return result;

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -30,7 +30,7 @@ public:
virtual void setWindowSize(size_t newSize); virtual void setWindowSize(size_t newSize);
virtual float process(float *mag, size_t increment); virtual float process(const float *R__ mag, size_t increment);
virtual void reset(); virtual void reset();
}; };

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -14,15 +14,18 @@
#include "PercussiveAudioCurve.h" #include "PercussiveAudioCurve.h"
#include "Profiler.h"
#include <cmath> #include <cmath>
namespace RubberBand namespace RubberBand
{ {
PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) : PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize) AudioCurve(sampleRate, windowSize)
{ {
m_prevMag = new double[m_windowSize/2 + 1]; m_prevMag = new float[m_windowSize/2 + 1];
for (size_t i = 0; i <= m_windowSize/2; ++i) { for (size_t i = 0; i <= m_windowSize/2; ++i) {
m_prevMag[i] = 0.f; m_prevMag[i] = 0.f;
@@ -45,29 +48,60 @@ PercussiveAudioCurve::reset()
void void
PercussiveAudioCurve::setWindowSize(size_t newSize) PercussiveAudioCurve::setWindowSize(size_t newSize)
{ {
delete[] m_prevMag;
m_windowSize = newSize; m_windowSize = newSize;
m_prevMag = new double[m_windowSize/2 + 1]; delete[] m_prevMag;
m_prevMag = new float[m_windowSize/2 + 1];
reset(); reset();
} }
float float
PercussiveAudioCurve::process(float *mag, size_t increment) PercussiveAudioCurve::process(const float *R__ mag, size_t increment)
{ {
static float threshold = pow(10, 0.3); static float threshold = powf(10.f, 0.15f); // 3dB rise in square of magnitude
static float zeroThresh = pow(10, -16); static float zeroThresh = powf(10.f, -8);
size_t count = 0; size_t count = 0;
size_t nonZeroCount = 0; size_t nonZeroCount = 0;
for (size_t n = 1; n <= m_windowSize / 2; ++n) { const int sz = m_windowSize / 2;
float sqrmag = mag[n] * mag[n];
bool above = ((sqrmag / m_prevMag[n]) >= threshold); for (int n = 1; n <= sz; ++n) {
bool above = ((mag[n] / m_prevMag[n]) >= threshold);
if (above) ++count; if (above) ++count;
if (sqrmag > zeroThresh) ++nonZeroCount; if (mag[n] > zeroThresh) ++nonZeroCount;
m_prevMag[n] = sqrmag; }
for (int n = 1; n <= sz; ++n) {
m_prevMag[n] = mag[n];
}
if (nonZeroCount == 0) return 0;
else return float(count) / float(nonZeroCount);
}
float
PercussiveAudioCurve::process(const double *R__ mag, size_t increment)
{
Profiler profiler("PercussiveAudioCurve::process");
static double threshold = pow(10.0, 0.15); // 3dB rise in square of magnitude
static double zeroThresh = pow(10.0, -8);
size_t count = 0;
size_t nonZeroCount = 0;
const int sz = m_windowSize / 2;
for (int n = 1; n <= sz; ++n) {
bool above = ((mag[n] / m_prevMag[n]) >= threshold);
if (above) ++count;
if (mag[n] > zeroThresh) ++nonZeroCount;
}
for (int n = 1; n <= sz; ++n) {
m_prevMag[n] = mag[n];
} }
if (nonZeroCount == 0) return 0; if (nonZeroCount == 0) return 0;

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -29,11 +29,12 @@ public:
virtual void setWindowSize(size_t newSize); virtual void setWindowSize(size_t newSize);
virtual float process(float *mag, size_t increment); virtual float process(const float *R__ mag, size_t increment);
virtual float process(const double *R__ mag, size_t increment);
virtual void reset(); virtual void reset();
protected: protected:
double *m_prevMag; float *R__ m_prevMag;
}; };
} }

176
src/Profiler.cpp Normal file
View File

@@ -0,0 +1,176 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "Profiler.h"
#include <algorithm>
#include <set>
#include <string>
#include <map>
#include <cstdio>
namespace RubberBand {
#ifndef NO_TIMING
Profiler::ProfileMap
Profiler::m_profiles;
Profiler::WorstCallMap
Profiler::m_worstCalls;
void
Profiler::add(const char *id, float ms)
{
ProfileMap::iterator pmi = m_profiles.find(id);
if (pmi != m_profiles.end()) {
++pmi->second.first;
pmi->second.second += ms;
} else {
m_profiles[id] = TimePair(1, ms);
}
WorstCallMap::iterator wci = m_worstCalls.find(id);
if (wci != m_worstCalls.end()) {
if (ms > wci->second) wci->second = ms;
} else {
m_worstCalls[id] = ms;
}
}
void
Profiler::dump()
{
#ifdef PROFILE_CLOCKS
fprintf(stderr, "Profiling points [CPU time]:\n");
#else
fprintf(stderr, "Profiling points [Wall time]:\n");
#endif
fprintf(stderr, "\nBy name:\n");
typedef std::set<const char *, std::less<std::string> > StringSet;
StringSet profileNames;
for (ProfileMap::const_iterator i = m_profiles.begin();
i != m_profiles.end(); ++i) {
profileNames.insert(i->first);
}
for (StringSet::const_iterator i = profileNames.begin();
i != profileNames.end(); ++i) {
ProfileMap::const_iterator j = m_profiles.find(*i);
if (j == m_profiles.end()) continue;
const TimePair &pp(j->second);
fprintf(stderr, "%s(%d):\n", *i, pp.first);
fprintf(stderr, "\tReal: \t%f ms \t[%f ms total]\n",
(pp.second / pp.first),
(pp.second));
WorstCallMap::const_iterator k = m_worstCalls.find(*i);
if (k == m_worstCalls.end()) continue;
fprintf(stderr, "\tWorst:\t%f ms/call\n", k->second);
}
typedef std::multimap<float, const char *> TimeRMap;
typedef std::multimap<int, const char *> IntRMap;
TimeRMap totmap, avgmap, worstmap;
IntRMap ncallmap;
for (ProfileMap::const_iterator i = m_profiles.begin();
i != m_profiles.end(); ++i) {
totmap.insert(TimeRMap::value_type(i->second.second, i->first));
avgmap.insert(TimeRMap::value_type(i->second.second /
i->second.first, i->first));
ncallmap.insert(IntRMap::value_type(i->second.first, i->first));
}
for (WorstCallMap::const_iterator i = m_worstCalls.begin();
i != m_worstCalls.end(); ++i) {
worstmap.insert(TimeRMap::value_type(i->second, i->first));
}
fprintf(stderr, "\nBy total:\n");
for (TimeRMap::const_iterator i = totmap.end(); i != totmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %f ms\n", i->second, i->first);
}
fprintf(stderr, "\nBy average:\n");
for (TimeRMap::const_iterator i = avgmap.end(); i != avgmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %f ms\n", i->second, i->first);
}
fprintf(stderr, "\nBy worst case:\n");
for (TimeRMap::const_iterator i = worstmap.end(); i != worstmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %f ms\n", i->second, i->first);
}
fprintf(stderr, "\nBy number of calls:\n");
for (IntRMap::const_iterator i = ncallmap.end(); i != ncallmap.begin(); ) {
--i;
fprintf(stderr, "%-40s %d\n", i->second, i->first);
}
}
Profiler::Profiler(const char* c) :
m_c(c),
m_ended(false)
{
#ifdef PROFILE_CLOCKS
m_start = clock();
#else
(void)gettimeofday(&m_start, 0);
#endif
}
Profiler::~Profiler()
{
if (!m_ended) end();
}
void
Profiler::end()
{
#ifdef PROFILE_CLOCKS
clock_t end = clock();
clock_t elapsed = end - m_start;
float ms = float((double(elapsed) / double(CLOCKS_PER_SEC)) * 1000.0);
#else
struct timeval tv;
(void)gettimeofday(&tv, 0);
tv.tv_sec -= m_start.tv_sec;
if (tv.tv_usec < m_start.tv_usec) {
tv.tv_usec += 1000000;
tv.tv_sec -= 1;
}
tv.tv_usec -= m_start.tv_usec;
float ms = float((double(tv.tv_sec) + (double(tv.tv_usec) / 1000000.0)) * 1000.0);
#endif
add(m_c, ms);
m_ended = true;
}
#endif
}

91
src/Profiler.h Normal file
View File

@@ -0,0 +1,91 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#ifndef _PROFILER_H_
#define _PROFILER_H_
#define NO_TIMING 1
//#define WANT_TIMING 1
//#define PROFILE_CLOCKS 1
#ifdef NDEBUG
#ifndef WANT_TIMING
#define NO_TIMING 1
#endif
#endif
#ifndef NO_TIMING
#ifdef PROFILE_CLOCKS
#include <time.h>
#else
#include "sysutils.h"
#ifndef _WIN32
#include <sys/time.h>
#endif
#endif
#endif
#include <map>
namespace RubberBand {
#ifndef NO_TIMING
class Profiler
{
public:
Profiler(const char *name);
~Profiler();
void end(); // same action as dtor
static void dump();
protected:
const char* m_c;
#ifdef PROFILE_CLOCKS
clock_t m_start;
#else
struct timeval m_start;
#endif
bool m_showOnDestruct;
bool m_ended;
typedef std::pair<int, float> TimePair;
typedef std::map<const char *, TimePair> ProfileMap;
typedef std::map<const char *, float> WorstCallMap;
static ProfileMap m_profiles;
static WorstCallMap m_worstCalls;
static void add(const char *, float);
};
#else
class Profiler
{
public:
Profiler(const char *, bool = false) { }
~Profiler() { }
void update() const { }
void end() { }
static void dump() { }
};
#endif
}
#endif

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -14,6 +14,8 @@
#include "Resampler.h" #include "Resampler.h"
#include "Profiler.h"
#include <cstdlib> #include <cstdlib>
#include <cmath> #include <cmath>
@@ -22,16 +24,40 @@
#include <samplerate.h> #include <samplerate.h>
namespace RubberBand { namespace RubberBand {
class Resampler::D class ResamplerImpl
{ {
public: public:
D(Quality quality, size_t channels, size_t maxBufferSize); virtual ~ResamplerImpl() { }
~D();
virtual int resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out,
int incount,
float ratio,
bool final) = 0;
size_t resample(float **in, float **out, virtual void reset() = 0;
size_t incount, float ratio, bool final); };
namespace Resamplers {
class D_SRC : public ResamplerImpl
{
public:
D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
int m_debugLevel);
~D_SRC();
int resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out,
int incount,
float ratio,
bool final);
void reset(); void reset();
@@ -39,25 +65,30 @@ protected:
SRC_STATE *m_src; SRC_STATE *m_src;
float *m_iin; float *m_iin;
float *m_iout; float *m_iout;
size_t m_channels; int m_channels;
size_t m_iinsize; int m_iinsize;
size_t m_ioutsize; int m_ioutsize;
int m_debugLevel;
}; };
Resampler::D::D(Quality quality, size_t channels, size_t maxBufferSize) : D_SRC::D_SRC(Resampler::Quality quality, int channels, int maxBufferSize,
int debugLevel) :
m_src(0), m_src(0),
m_iin(0), m_iin(0),
m_iout(0), m_iout(0),
m_channels(channels), m_channels(channels),
m_iinsize(0), m_iinsize(0),
m_ioutsize(0) m_ioutsize(0),
m_debugLevel(debugLevel)
{ {
// std::cerr << "Resampler::Resampler: using libsamplerate implementation" if (m_debugLevel > 0) {
// << std::endl; std::cerr << "Resampler::Resampler: using libsamplerate implementation"
<< std::endl;
}
int err = 0; int err = 0;
m_src = src_new(quality == Best ? SRC_SINC_BEST_QUALITY : m_src = src_new(quality == Resampler::Best ? SRC_SINC_BEST_QUALITY :
quality == Fastest ? SRC_LINEAR : quality == Resampler::Fastest ? SRC_LINEAR :
SRC_SINC_FASTEST, SRC_SINC_FASTEST,
channels, &err); channels, &err);
@@ -72,7 +103,7 @@ Resampler::D::D(Quality quality, size_t channels, size_t maxBufferSize) :
} }
} }
Resampler::D::~D() D_SRC::~D_SRC()
{ {
src_delete(m_src); src_delete(m_src);
if (m_iinsize > 0) { if (m_iinsize > 0) {
@@ -83,16 +114,19 @@ Resampler::D::~D()
} }
} }
size_t int
Resampler::D::resample(float **in, float **out, size_t incount, float ratio, D_SRC::resample(const float *const R__ *const R__ in,
bool final) float *const R__ *const R__ out,
int incount,
float ratio,
bool final)
{ {
SRC_DATA data; SRC_DATA data;
size_t outcount = lrintf(ceilf(incount * ratio)); int outcount = lrintf(ceilf(incount * ratio));
if (m_channels == 1) { if (m_channels == 1) {
data.data_in = *in; data.data_in = const_cast<float *>(*in); //!!!???
data.data_out = *out; data.data_out = *out;
} else { } else {
if (incount * m_channels > m_iinsize) { if (incount * m_channels > m_iinsize) {
@@ -103,8 +137,8 @@ Resampler::D::resample(float **in, float **out, size_t incount, float ratio,
m_ioutsize = outcount * m_channels; m_ioutsize = outcount * m_channels;
m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float)); m_iout = (float *)realloc(m_iout, m_ioutsize * sizeof(float));
} }
for (size_t i = 0; i < incount; ++i) { for (int i = 0; i < incount; ++i) {
for (size_t c = 0; c < m_channels; ++c) { for (int c = 0; c < m_channels; ++c) {
m_iin[i * m_channels + c] = in[c][i]; m_iin[i * m_channels + c] = in[c][i];
} }
} }
@@ -123,7 +157,7 @@ Resampler::D::resample(float **in, float **out, size_t incount, float ratio,
if (m_channels > 1) { if (m_channels > 1) {
for (int i = 0; i < data.output_frames_gen; ++i) { for (int i = 0; i < data.output_frames_gen; ++i) {
for (size_t c = 0; c < m_channels; ++c) { for (int c = 0; c < m_channels; ++c) {
out[c][i] = m_iout[i * m_channels + c]; out[c][i] = m_iout[i * m_channels + c];
} }
} }
@@ -133,37 +167,81 @@ Resampler::D::resample(float **in, float **out, size_t incount, float ratio,
} }
void void
Resampler::D::reset() D_SRC::reset()
{ {
src_reset(m_src); src_reset(m_src);
} }
} // end namespace
namespace RubberBand { } /* end namespace Resamplers */
Resampler::Resampler(Quality quality, size_t channels, size_t maxBufferSize) Resampler::Resampler(Resampler::Quality quality, int channels,
int maxBufferSize, int debugLevel)
{ {
m_d = new D(quality, channels, maxBufferSize); m_method = -1;
switch (quality) {
case Resampler::Best:
m_method = 1;
break;
case Resampler::FastestTolerable:
m_method = 1;
break;
case Resampler::Fastest:
m_method = 1;
break;
}
if (m_method == -1) {
std::cerr << "Resampler::Resampler(" << quality << ", " << channels
<< ", " << maxBufferSize << "): No implementation available!"
<< std::endl;
abort();
}
switch (m_method) {
case 0:
std::cerr << "Resampler::Resampler(" << quality << ", " << channels
<< ", " << maxBufferSize << "): No implementation available!"
<< std::endl;
abort();
break;
case 1:
d = new Resamplers::D_SRC(quality, channels, maxBufferSize, debugLevel);
break;
case 2:
std::cerr << "Resampler::Resampler(" << quality << ", " << channels
<< ", " << maxBufferSize << "): No implementation available!"
<< std::endl;
abort();
break;
}
} }
Resampler::~Resampler() Resampler::~Resampler()
{ {
delete m_d; delete d;
} }
size_t int
Resampler::resample(float **in, float **out, Resampler::resample(const float *const R__ *const R__ in,
size_t incount, float ratio, bool final) float *const R__ *const R__ out,
int incount, float ratio, bool final)
{ {
return m_d->resample(in, out, incount, ratio, final); Profiler profiler("Resampler::resample");
return d->resample(in, out, incount, ratio, final);
} }
void void
Resampler::reset() Resampler::reset()
{ {
m_d->reset(); d->reset();
} }
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -17,8 +17,12 @@
#include <sys/types.h> #include <sys/types.h>
#include "sysutils.h"
namespace RubberBand { namespace RubberBand {
class ResamplerImpl;
class Resampler class Resampler
{ {
public: public:
@@ -30,17 +34,21 @@ public:
* that may be passed to the resample function before the * that may be passed to the resample function before the
* resampler needs to reallocate its internal buffers. * resampler needs to reallocate its internal buffers.
*/ */
Resampler(Quality quality, size_t channels, size_t maxBufferSize = 0); Resampler(Quality quality, int channels, int maxBufferSize = 0,
int debugLevel = 0);
~Resampler(); ~Resampler();
size_t resample(float **in, float **out, int resample(const float *const R__ *const R__ in,
size_t incount, float ratio, bool final = false); float *const R__ *const R__ out,
int incount,
float ratio,
bool final = false);
void reset(); void reset();
protected: protected:
class D; ResamplerImpl *d;
D *m_d; int m_method;
}; };
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -17,11 +17,15 @@
#include <sys/types.h> #include <sys/types.h>
#include <cstring>
#ifndef _WIN32 #ifndef _WIN32
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#include "Scavenger.h" #include "Scavenger.h"
#include "Profiler.h"
//#define DEBUG_RINGBUFFER 1 //#define DEBUG_RINGBUFFER 1
@@ -57,7 +61,7 @@ public:
* power of two, this means n should ideally be some power of two * power of two, this means n should ideally be some power of two
* minus one. * minus one.
*/ */
RingBuffer(size_t n); RingBuffer(int n);
virtual ~RingBuffer(); virtual ~RingBuffer();
@@ -65,7 +69,7 @@ public:
* Return the total capacity of the ring buffer in samples. * Return the total capacity of the ring buffer in samples.
* (This is the argument n passed to the constructor.) * (This is the argument n passed to the constructor.)
*/ */
size_t getSize() const; int getSize() const;
/** /**
* Resize the ring buffer. This also empties it; use resized() * Resize the ring buffer. This also empties it; use resized()
@@ -73,7 +77,7 @@ public:
* new, larger buffer; the old buffer is scavenged after a seemly * new, larger buffer; the old buffer is scavenged after a seemly
* delay. Should be called from the write thread. * delay. Should be called from the write thread.
*/ */
void resize(size_t newSize); void resize(int newSize);
/** /**
* Return a new ring buffer (allocated with "new" -- called must * Return a new ring buffer (allocated with "new" -- called must
@@ -83,7 +87,7 @@ public:
* or inconsistent. If this buffer's data will not fit in the new * or inconsistent. If this buffer's data will not fit in the new
* size, the contents are undefined. * size, the contents are undefined.
*/ */
RingBuffer<T, N> *resized(size_t newSize, int R = 0) const; RingBuffer<T, N> *resized(int newSize, int R = 0) const;
/** /**
* Lock the ring buffer into physical memory. Returns true * Lock the ring buffer into physical memory. Returns true
@@ -101,19 +105,19 @@ public:
* Return the amount of data available for reading by reader R, in * Return the amount of data available for reading by reader R, in
* samples. * samples.
*/ */
size_t getReadSpace(int R = 0) const; int getReadSpace(int R = 0) const;
/** /**
* Return the amount of space available for writing, in samples. * Return the amount of space available for writing, in samples.
*/ */
size_t getWriteSpace() const; int getWriteSpace() const;
/** /**
* Read n samples from the buffer, for reader R. If fewer than n * Read n samples from the buffer, for reader R. If fewer than n
* are available, the remainder will be zeroed out. Returns the * are available, the remainder will be zeroed out. Returns the
* number of samples actually read. * number of samples actually read.
*/ */
size_t read(T *destination, size_t n, int R = 0); int read(T *R__ destination, int n, int R = 0);
/** /**
* Read n samples from the buffer, for reader R, adding them to * Read n samples from the buffer, for reader R, adding them to
@@ -121,7 +125,7 @@ public:
* will be left alone. Returns the number of samples actually * will be left alone. Returns the number of samples actually
* read. * read.
*/ */
size_t readAdding(T *destination, size_t n, int R = 0); int readAdding(T *R__ destination, int n, int R = 0);
/** /**
* Read one sample from the buffer, for reader R. If no sample is * Read one sample from the buffer, for reader R. If no sample is
@@ -139,7 +143,7 @@ public:
* n are available, the remainder will be zeroed out. Returns the * n are available, the remainder will be zeroed out. Returns the
* number of samples actually read. * number of samples actually read.
*/ */
size_t peek(T *destination, size_t n, int R = 0) const; int peek(T *R__ destination, int n, int R = 0) const;
/** /**
* Read one sample from the buffer, if available, without * Read one sample from the buffer, if available, without
@@ -155,27 +159,27 @@ public:
* samples). Returns the number of samples actually available for * samples). Returns the number of samples actually available for
* discarding. * discarding.
*/ */
size_t skip(size_t n, int R = 0); int skip(int n, int R = 0);
/** /**
* Write n samples to the buffer. If insufficient space is * Write n samples to the buffer. If insufficient space is
* available, not all samples may actually be written. Returns * available, not all samples may actually be written. Returns
* the number of samples actually written. * the number of samples actually written.
*/ */
size_t write(const T *source, size_t n); int write(const T *source, int n);
/** /**
* Write n zero-value samples to the buffer. If insufficient * Write n zero-value samples to the buffer. If insufficient
* space is available, not all zeros may actually be written. * space is available, not all zeros may actually be written.
* Returns the number of zeroes actually written. * Returns the number of zeroes actually written.
*/ */
size_t zero(size_t n); int zero(int n);
protected: protected:
T *m_buffer; T *R__ m_buffer;
volatile size_t m_writer; volatile int m_writer;
volatile size_t m_readers[N]; volatile int m_readers[N];
size_t m_size; int m_size;
bool m_mlocked; bool m_mlocked;
static Scavenger<ScavengerArrayWrapper<T> > m_scavenger; static Scavenger<ScavengerArrayWrapper<T> > m_scavenger;
@@ -189,7 +193,7 @@ template <typename T, int N>
Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger; Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger;
template <typename T, int N> template <typename T, int N>
RingBuffer<T, N>::RingBuffer(size_t n) : RingBuffer<T, N>::RingBuffer(int n) :
m_buffer(new T[n + 1]), m_buffer(new T[n + 1]),
m_writer(0), m_writer(0),
m_size(n + 1), m_size(n + 1),
@@ -220,7 +224,7 @@ RingBuffer<T, N>::~RingBuffer()
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::getSize() const RingBuffer<T, N>::getSize() const
{ {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
@@ -232,7 +236,7 @@ RingBuffer<T, N>::getSize() const
template <typename T, int N> template <typename T, int N>
void void
RingBuffer<T, N>::resize(size_t newSize) RingBuffer<T, N>::resize(int newSize)
{ {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resize(" << newSize << ")" << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resize(" << newSize << ")" << std::endl;
@@ -259,12 +263,12 @@ RingBuffer<T, N>::resize(size_t newSize)
template <typename T, int N> template <typename T, int N>
RingBuffer<T, N> * RingBuffer<T, N> *
RingBuffer<T, N>::resized(size_t newSize, int R) const RingBuffer<T, N>::resized(int newSize, int R) const
{ {
RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize); RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize);
size_t w = m_writer; int w = m_writer;
size_t r = m_readers[R]; int r = m_readers[R];
while (r != w) { while (r != w) {
T value = m_buffer[r]; T value = m_buffer[r];
@@ -297,12 +301,12 @@ RingBuffer<T, N>::reset()
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::getReadSpace(int R) const RingBuffer<T, N>::getReadSpace(int R) const
{ {
size_t writer = m_writer; int writer = m_writer;
size_t reader = m_readers[R]; int reader = m_readers[R];
size_t space; int space;
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): reader " << reader << ", writer " << writer << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): reader " << reader << ", writer " << writer << std::endl;
@@ -320,20 +324,20 @@ RingBuffer<T, N>::getReadSpace(int R) const
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::getWriteSpace() const RingBuffer<T, N>::getWriteSpace() const
{ {
size_t space = 0; int space = 0;
for (int i = 0; i < N; ++i) { for (int i = 0; i < N; ++i) {
size_t writer = m_writer; int writer = m_writer;
size_t reader = m_readers[i]; int reader = m_readers[i];
size_t here = (reader + m_size - writer - 1); int here = (reader + m_size - writer - 1);
if (here >= m_size) here -= m_size; if (here >= m_size) here -= m_size;
if (i == 0 || here < space) space = here; if (i == 0 || here < space) space = here;
} }
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
size_t rs(getReadSpace()), rp(m_readers[0]); int rs(getReadSpace()), rp(m_readers[0]);
std::cerr << "RingBuffer: write space " << space << ", read space " std::cerr << "RingBuffer: write space " << space << ", read space "
<< rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl; << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
@@ -348,39 +352,44 @@ RingBuffer<T, N>::getWriteSpace() const
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::read(T *destination, size_t n, int R) RingBuffer<T, N>::read(T *R__ destination, int n, int R)
{ {
Profiler profiler("RingBuffer::read");
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
#endif #endif
size_t available = getReadSpace(R); int available = getReadSpace(R);
if (n > available) { if (n > available) {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "WARNING: Only " << available << " samples available" std::cerr << "WARNING: Only " << available << " samples available"
<< std::endl; << std::endl;
#endif #endif
for (size_t i = available; i < n; ++i) { for (int i = available; i < n; ++i) {
destination[i] = 0; destination[i] = 0;
} }
n = available; n = available;
} }
if (n == 0) return n; if (n == 0) return n;
size_t reader = m_readers[R]; int reader = m_readers[R];
size_t here = m_size - reader; int here = m_size - reader;
T *const R__ bufbase = m_buffer + reader;
if (here >= n) { if (here >= n) {
for (size_t i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
destination[i] = (m_buffer + reader)[i]; destination[i] = bufbase[i];
} }
} else { } else {
for (size_t i = 0; i < here; ++i) { for (int i = 0; i < here; ++i) {
destination[i] = (m_buffer + reader)[i]; destination[i] = bufbase[i];
} }
for (size_t i = 0; i < (n - here); ++i) { T *const R__ destbase = destination + here;
destination[i + here] = m_buffer[i]; const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] = m_buffer[i];
} }
} }
@@ -396,14 +405,16 @@ RingBuffer<T, N>::read(T *destination, size_t n, int R)
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::readAdding(T *destination, size_t n, int R) RingBuffer<T, N>::readAdding(T *R__ destination, int n, int R)
{ {
Profiler profiler("RingBuffer::readAdding");
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
#endif #endif
size_t available = getReadSpace(R); int available = getReadSpace(R);
if (n > available) { if (n > available) {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "WARNING: Only " << available << " samples available" std::cerr << "WARNING: Only " << available << " samples available"
@@ -413,19 +424,22 @@ RingBuffer<T, N>::readAdding(T *destination, size_t n, int R)
} }
if (n == 0) return n; if (n == 0) return n;
size_t reader = m_readers[R]; int reader = m_readers[R];
size_t here = m_size - reader; int here = m_size - reader;
const T *const R__ bufbase = m_buffer + reader;
if (here >= n) { if (here >= n) {
for (size_t i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
destination[i] += (m_buffer + reader)[i]; destination[i] += bufbase[i];
} }
} else { } else {
for (size_t i = 0; i < here; ++i) { for (int i = 0; i < here; ++i) {
destination[i] += (m_buffer + reader)[i]; destination[i] += bufbase[i];
} }
for (size_t i = 0; i < (n - here); ++i) { T *const R__ destbase = destination + here;
destination[i + here] += m_buffer[i]; const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] += m_buffer[i];
} }
} }
@@ -450,7 +464,7 @@ RingBuffer<T, N>::readOne(int R)
#endif #endif
return 0; return 0;
} }
size_t reader = m_readers[R]; int reader = m_readers[R];
T value = m_buffer[reader]; T value = m_buffer[reader];
if (++reader == m_size) reader = 0; if (++reader == m_size) reader = 0;
m_readers[R] = reader; m_readers[R] = reader;
@@ -458,14 +472,16 @@ RingBuffer<T, N>::readOne(int R)
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::peek(T *destination, size_t n, int R) const RingBuffer<T, N>::peek(T *R__ destination, int n, int R) const
{ {
Profiler profiler("RingBuffer::peek");
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
#endif #endif
size_t available = getReadSpace(R); int available = getReadSpace(R);
if (n > available) { if (n > available) {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "WARNING: Only " << available << " samples available" std::cerr << "WARNING: Only " << available << " samples available"
@@ -476,19 +492,22 @@ RingBuffer<T, N>::peek(T *destination, size_t n, int R) const
} }
if (n == 0) return n; if (n == 0) return n;
size_t reader = m_readers[R]; int reader = m_readers[R];
size_t here = m_size - reader; int here = m_size - reader;
const T *const R__ bufbase = m_buffer + reader;
if (here >= n) { if (here >= n) {
for (size_t i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
destination[i] = (m_buffer + reader)[i]; destination[i] = bufbase[i];
} }
} else { } else {
for (size_t i = 0; i < here; ++i) { for (int i = 0; i < here; ++i) {
destination[i] = (m_buffer + reader)[i]; destination[i] = bufbase[i];
} }
for (size_t i = 0; i < (n - here); ++i) { T *const R__ destbase = destination + here;
destination[i + here] = m_buffer[i]; const int nh = n - here;
for (int i = 0; i < nh; ++i) {
destbase[i] = m_buffer[i];
} }
} }
@@ -519,14 +538,14 @@ RingBuffer<T, N>::peekOne(int R) const
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::skip(size_t n, int R) RingBuffer<T, N>::skip(int n, int R)
{ {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
#endif #endif
size_t available = getReadSpace(R); int available = getReadSpace(R);
if (n > available) { if (n > available) {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "WARNING: Only " << available << " samples available" std::cerr << "WARNING: Only " << available << " samples available"
@@ -536,7 +555,7 @@ RingBuffer<T, N>::skip(size_t n, int R)
} }
if (n == 0) return n; if (n == 0) return n;
size_t reader = m_readers[R]; int reader = m_readers[R];
reader += n; reader += n;
while (reader >= m_size) reader -= m_size; while (reader >= m_size) reader -= m_size;
m_readers[R] = reader; m_readers[R] = reader;
@@ -544,14 +563,16 @@ RingBuffer<T, N>::skip(size_t n, int R)
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::write(const T *source, size_t n) RingBuffer<T, N>::write(const T *source, int n)
{ {
Profiler profiler("RingBuffer::write");
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
#endif #endif
size_t available = getWriteSpace(); int available = getWriteSpace();
if (n > available) { if (n > available) {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "WARNING: Only room for " << available << " samples" std::cerr << "WARNING: Only room for " << available << " samples"
@@ -561,18 +582,23 @@ RingBuffer<T, N>::write(const T *source, size_t n)
} }
if (n == 0) return n; if (n == 0) return n;
size_t writer = m_writer; int writer = m_writer;
size_t here = m_size - writer; int here = m_size - writer;
T *const R__ bufbase = m_buffer + writer;
if (here >= n) { if (here >= n) {
for (size_t i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
(m_buffer + writer)[i] = source[i]; bufbase[i] = source[i];
} }
} else { } else {
for (size_t i = 0; i < here; ++i) { for (int i = 0; i < here; ++i) {
(m_buffer + writer)[i] = source[i]; bufbase[i] = source[i];
} }
for (size_t i = 0; i < (n - here); ++i) { const int nh = n - here;
m_buffer[i] = (source + here)[i]; const T *const R__ srcbase = source + here;
T *const R__ buf = m_buffer;
for (int i = 0; i < nh; ++i) {
buf[i] = srcbase[i];
} }
} }
@@ -588,14 +614,16 @@ RingBuffer<T, N>::write(const T *source, size_t n)
} }
template <typename T, int N> template <typename T, int N>
size_t int
RingBuffer<T, N>::zero(size_t n) RingBuffer<T, N>::zero(int n)
{ {
Profiler profiler("RingBuffer::zero");
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl; std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
#endif #endif
size_t available = getWriteSpace(); int available = getWriteSpace();
if (n > available) { if (n > available) {
#ifdef DEBUG_RINGBUFFER #ifdef DEBUG_RINGBUFFER
std::cerr << "WARNING: Only room for " << available << " samples" std::cerr << "WARNING: Only room for " << available << " samples"
@@ -605,17 +633,20 @@ RingBuffer<T, N>::zero(size_t n)
} }
if (n == 0) return n; if (n == 0) return n;
size_t writer = m_writer; int writer = m_writer;
size_t here = m_size - writer; int here = m_size - writer;
T *const R__ bufbase = m_buffer + writer;
if (here >= n) { if (here >= n) {
for (size_t i = 0; i < n; ++i) { for (int i = 0; i < n; ++i) {
(m_buffer + writer)[i] = 0; bufbase[i] = 0;
} }
} else { } else {
for (size_t i = 0; i < here; ++i) { for (int i = 0; i < here; ++i) {
(m_buffer + writer)[i] = 0; bufbase[i] = 0;
} }
for (size_t i = 0; i < (n - here); ++i) { const int nh = n - here;
for (int i = 0; i < nh; ++i) {
m_buffer[i] = 0; m_buffer[i] = 0;
} }
} }
@@ -633,4 +664,6 @@ RingBuffer<T, N>::zero(size_t n)
} }
//#include "RingBuffer.cpp"
#endif // _RINGBUFFER_H_ #endif // _RINGBUFFER_H_

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -81,6 +81,18 @@ RubberBandStretcher::setPhaseOption(Options options)
m_d->setPhaseOption(options); m_d->setPhaseOption(options);
} }
void
RubberBandStretcher::setFormantOption(Options options)
{
m_d->setFormantOption(options);
}
void
RubberBandStretcher::setPitchOption(Options options)
{
m_d->setPitchOption(options);
}
void void
RubberBandStretcher::setExpectedInputDuration(size_t samples) RubberBandStretcher::setExpectedInputDuration(size_t samples)
{ {

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -17,9 +17,12 @@
#include <vector> #include <vector>
#include <list> #include <list>
#include <sys/time.h>
#include <iostream> #include <iostream>
#ifndef WIN32
#include <sys/time.h>
#endif
#include "Thread.h" #include "Thread.h"
#include "sysutils.h" #include "sysutils.h"

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -20,7 +20,7 @@ namespace RubberBand
SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize) : SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurve(sampleRate, windowSize) AudioCurve(sampleRate, windowSize)
{ {
m_prevMag = new double[m_windowSize/2 + 1]; m_prevMag = new float[m_windowSize/2 + 1];
for (size_t i = 0; i <= m_windowSize/2; ++i) { for (size_t i = 0; i <= m_windowSize/2; ++i) {
m_prevMag[i] = 0.f; m_prevMag[i] = 0.f;
@@ -43,11 +43,16 @@ SpectralDifferenceAudioCurve::reset()
void void
SpectralDifferenceAudioCurve::setWindowSize(size_t newSize) SpectralDifferenceAudioCurve::setWindowSize(size_t newSize)
{ {
delete[] m_prevMag;
m_windowSize = newSize; m_windowSize = newSize;
m_prevMag = new float[m_windowSize/2 + 1];
reset();
} }
float float
SpectralDifferenceAudioCurve::process(float *mag, size_t increment) SpectralDifferenceAudioCurve::process(const float *R__ mag, size_t increment)
{ {
float result = 0.0; float result = 0.0;

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -30,11 +30,11 @@ public:
virtual void setWindowSize(size_t newSize); virtual void setWindowSize(size_t newSize);
virtual float process(float *mag, size_t increment); virtual float process(const float *R__ mag, size_t increment);
virtual void reset(); virtual void reset();
protected: protected:
double *m_prevMag; float *R__ m_prevMag;
}; };
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -19,6 +19,9 @@
#include <deque> #include <deque>
#include <set> #include <set>
#include <cassert> #include <cassert>
#include <algorithm>
#include "sysutils.h"
namespace RubberBand namespace RubberBand
{ {
@@ -162,9 +165,11 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
int int
StretchCalculator::calculateSingle(double ratio, StretchCalculator::calculateSingle(double ratio,
size_t inputDurationSoFar, float df,
float df) size_t increment)
{ {
if (increment == 0) increment = m_increment;
bool isTransient = false; bool isTransient = false;
// We want to ensure, as close as possible, that the phase reset // We want to ensure, as close as possible, that the phase reset
@@ -176,10 +181,10 @@ StretchCalculator::calculateSingle(double ratio,
// from the ratio directly. For the moment we're happy if it // from the ratio directly. For the moment we're happy if it
// works well in common situations. // works well in common situations.
float transientThreshold = 0.35; float transientThreshold = 0.35f;
if (ratio > 1) transientThreshold = 0.25; if (ratio > 1) transientThreshold = 0.25f;
if (m_useHardPeaks && df > m_prevDf * 1.1 && df > transientThreshold) { if (m_useHardPeaks && df > m_prevDf * 1.1f && df > transientThreshold) {
isTransient = true; isTransient = true;
} }
@@ -192,37 +197,37 @@ StretchCalculator::calculateSingle(double ratio,
if (isTransient && m_transientAmnesty == 0) { if (isTransient && m_transientAmnesty == 0) {
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
std::cerr << "StretchCalculator::calculateSingle: transient found at " std::cerr << "StretchCalculator::calculateSingle: transient"
<< inputDurationSoFar << std::endl; << std::endl;
} }
m_divergence += m_increment - (m_increment * ratio); m_divergence += increment - (increment * ratio);
// as in offline mode, 0.05 sec approx min between transients // as in offline mode, 0.05 sec approx min between transients
m_transientAmnesty = m_transientAmnesty =
lrint(ceil(double(m_sampleRate) / (20 * double(m_increment)))); lrint(ceil(double(m_sampleRate) / (20 * double(increment))));
m_recovery = m_divergence / ((m_sampleRate / 10.0) / m_increment); m_recovery = m_divergence / ((m_sampleRate / 10.0) / increment);
return -m_increment; return -int(increment);
} }
if (m_prevRatio != ratio) { if (m_prevRatio != ratio) {
m_recovery = m_divergence / ((m_sampleRate / 10.0) / m_increment); m_recovery = m_divergence / ((m_sampleRate / 10.0) / increment);
m_prevRatio = ratio; m_prevRatio = ratio;
} }
if (m_transientAmnesty > 0) --m_transientAmnesty; if (m_transientAmnesty > 0) --m_transientAmnesty;
int incr = lrint(m_increment * ratio - m_recovery); int incr = lrint(increment * ratio - m_recovery);
if (m_debugLevel > 2 || (m_debugLevel > 1 && m_divergence != 0)) { if (m_debugLevel > 2 || (m_debugLevel > 1 && m_divergence != 0)) {
std::cerr << "divergence = " << m_divergence << ", recovery = " << m_recovery << ", incr = " << incr << ", "; std::cerr << "divergence = " << m_divergence << ", recovery = " << m_recovery << ", incr = " << incr << ", ";
} }
if (incr < lrint((m_increment * ratio) / 2)) { if (incr < lrint((increment * ratio) / 2)) {
incr = lrint((m_increment * ratio) / 2); incr = lrint((increment * ratio) / 2);
} else if (incr > lrint(m_increment * ratio * 2)) { } else if (incr > lrint(increment * ratio * 2)) {
incr = lrint(m_increment * ratio * 2); incr = lrint(increment * ratio * 2);
} }
double divdiff = (m_increment * ratio) - incr; double divdiff = (increment * ratio) - incr;
if (m_debugLevel > 2 || (m_debugLevel > 1 && m_divergence != 0)) { if (m_debugLevel > 2 || (m_debugLevel > 1 && m_divergence != 0)) {
std::cerr << "divdiff = " << divdiff << std::endl; std::cerr << "divdiff = " << divdiff << std::endl;
@@ -232,7 +237,7 @@ StretchCalculator::calculateSingle(double ratio,
m_divergence -= divdiff; m_divergence -= divdiff;
if ((prevDivergence < 0 && m_divergence > 0) || if ((prevDivergence < 0 && m_divergence > 0) ||
(prevDivergence > 0 && m_divergence < 0)) { (prevDivergence > 0 && m_divergence < 0)) {
m_recovery = m_divergence / ((m_sampleRate / 10.0) / m_increment); m_recovery = m_divergence / ((m_sampleRate / 10.0) / increment);
} }
return incr; return incr;

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -45,9 +45,12 @@ public:
* phase-lock audio curve. State is retained between calls in the * phase-lock audio curve. State is retained between calls in the
* StretchCalculator object; call reset() to reset it. This uses * StretchCalculator object; call reset() to reset it. This uses
* a less sophisticated method than the offline calculate(). * a less sophisticated method than the offline calculate().
*
* If increment is non-zero, use it for the input increment for
* this block in preference to m_increment.
*/ */
virtual int calculateSingle(double ratio, size_t inputDurationSoFar, virtual int calculateSingle(double ratio, float curveValue,
float curveValue); size_t increment = 0);
void setUseHardPeaks(bool use) { m_useHardPeaks = use; } void setUseHardPeaks(bool use) { m_useHardPeaks = use; }

View File

@@ -1,22 +1,39 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "StretcherChannelData.h" #include "StretcherChannelData.h"
#include "Resampler.h" #include "Resampler.h"
namespace RubberBand namespace RubberBand
{ {
RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize, RubberBandStretcher::Impl::ChannelData::ChannelData(size_t windowSize,
size_t outbufSize) int overSample,
size_t outbufSize) :
oversample(overSample)
{ {
std::set<size_t> s; std::set<size_t> s;
construct(s, windowSize, outbufSize); construct(s, windowSize, outbufSize);
} }
RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes, RubberBandStretcher::Impl::ChannelData::ChannelData(const std::set<size_t> &windowSizes,
int overSample,
size_t initialWindowSize, size_t initialWindowSize,
size_t outbufSize) size_t outbufSize) :
oversample(overSample)
{ {
construct(windowSizes, initialWindowSize, outbufSize); construct(windowSizes, initialWindowSize, outbufSize);
} }
@@ -37,7 +54,8 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
if (initialWindowSize > maxSize) maxSize = initialWindowSize; if (initialWindowSize > maxSize) maxSize = initialWindowSize;
} }
size_t realSize = maxSize/2 + 1; // size of the real "half" of freq data // max size of the real "half" of freq data
size_t realSize = (maxSize * oversample)/2 + 1;
// std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl; // std::cerr << "ChannelData::construct([" << windowSizes.size() << "], " << maxSize << ", " << outbufSize << ")" << std::endl;
@@ -51,19 +69,21 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
prevPhase = new double[realSize]; prevPhase = new double[realSize];
unwrappedPhase = new double[realSize]; unwrappedPhase = new double[realSize];
freqPeak = new size_t[realSize]; freqPeak = new size_t[realSize];
envelope = new double[realSize];
fltbuf = new float[maxSize];
accumulator = new float[maxSize]; accumulator = new float[maxSize];
windowAccumulator = new float[maxSize]; windowAccumulator = new float[maxSize];
fltbuf = new float[maxSize];
for (std::set<size_t>::const_iterator i = windowSizes.begin(); for (std::set<size_t>::const_iterator i = windowSizes.begin();
i != windowSizes.end(); ++i) { i != windowSizes.end(); ++i) {
ffts[*i] = new FFT(*i); ffts[*i] = new FFT(*i * oversample);
ffts[*i]->initDouble(); ffts[*i]->initDouble();
} }
if (windowSizes.find(initialWindowSize) == windowSizes.end()) { if (windowSizes.find(initialWindowSize) == windowSizes.end()) {
ffts[initialWindowSize] = new FFT(initialWindowSize); ffts[initialWindowSize] = new FFT(initialWindowSize * oversample);
ffts[initialWindowSize]->initDouble(); ffts[initialWindowSize]->initDouble();
} }
fft = ffts[initialWindowSize]; fft = ffts[initialWindowSize];
@@ -82,16 +102,17 @@ RubberBandStretcher::Impl::ChannelData::construct(const std::set<size_t> &window
prevPhase[i] = 0.0; prevPhase[i] = 0.0;
unwrappedPhase[i] = 0.0; unwrappedPhase[i] = 0.0;
freqPeak[i] = 0; freqPeak[i] = 0;
envelope[i] = 0.0;
} }
for (size_t i = 0; i < initialWindowSize; ++i) { for (size_t i = 0; i < initialWindowSize * oversample; ++i) {
dblbuf[i] = 0.0; dblbuf[i] = 0.0;
} }
for (size_t i = 0; i < maxSize; ++i) { for (size_t i = 0; i < maxSize; ++i) {
accumulator[i] = 0.f; accumulator[i] = 0.f;
windowAccumulator[i] = 0.f; windowAccumulator[i] = 0.f;
fltbuf[i] = 0.0; fltbuf[i] = 0.f;
} }
} }
@@ -99,7 +120,7 @@ void
RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize) RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
{ {
size_t oldSize = inbuf->getSize(); size_t oldSize = inbuf->getSize();
size_t realSize = windowSize/2 + 1; size_t realSize = (windowSize * oversample) / 2 + 1;
// std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl; // std::cerr << "ChannelData::setWindowSize(" << windowSize << ") [from " << oldSize << "]" << std::endl;
@@ -114,7 +135,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
if (ffts.find(windowSize) == ffts.end()) { if (ffts.find(windowSize) == ffts.end()) {
//!!! this also requires a lock, but it shouldn't occur in //!!! this also requires a lock, but it shouldn't occur in
//RT mode with proper initialisation //RT mode with proper initialisation
ffts[windowSize] = new FFT(windowSize); ffts[windowSize] = new FFT(windowSize * oversample);
ffts[windowSize]->initDouble(); ffts[windowSize]->initDouble();
} }
@@ -122,7 +143,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
dblbuf = fft->getDoubleTimeBuffer(); dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize; ++i) { for (size_t i = 0; i < windowSize * oversample; ++i) {
dblbuf[i] = 0.0; dblbuf[i] = 0.0;
} }
@@ -155,16 +176,19 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
delete[] prevPhase; delete[] prevPhase;
delete[] unwrappedPhase; delete[] unwrappedPhase;
delete[] freqPeak; delete[] freqPeak;
delete[] envelope;
mag = new double[realSize]; mag = new double[realSize];
phase = new double[realSize]; phase = new double[realSize];
prevPhase = new double[realSize]; prevPhase = new double[realSize];
unwrappedPhase = new double[realSize]; unwrappedPhase = new double[realSize];
freqPeak = new size_t[realSize]; freqPeak = new size_t[realSize];
envelope = new double[realSize];
delete[] fltbuf; delete[] fltbuf;
fltbuf = new float[windowSize]; fltbuf = new float[windowSize];
// But we do want to preserve data in these // But we do want to preserve data in these
float *newAcc = new float[windowSize]; float *newAcc = new float[windowSize];
@@ -185,10 +209,11 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
prevPhase[i] = 0.0; prevPhase[i] = 0.0;
unwrappedPhase[i] = 0.0; unwrappedPhase[i] = 0.0;
freqPeak[i] = 0; freqPeak[i] = 0;
envelope[i] = 0.0;
} }
for (size_t i = 0; i < windowSize; ++i) { for (size_t i = 0; i < windowSize; ++i) {
fltbuf[i] = 0.0; fltbuf[i] = 0.f;
} }
for (size_t i = oldSize; i < windowSize; ++i) { for (size_t i = oldSize; i < windowSize; ++i) {
@@ -197,7 +222,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
} }
if (ffts.find(windowSize) == ffts.end()) { if (ffts.find(windowSize) == ffts.end()) {
ffts[windowSize] = new FFT(windowSize); ffts[windowSize] = new FFT(windowSize * oversample);
ffts[windowSize]->initDouble(); ffts[windowSize]->initDouble();
} }
@@ -205,7 +230,7 @@ RubberBandStretcher::Impl::ChannelData::setWindowSize(size_t windowSize)
dblbuf = fft->getDoubleTimeBuffer(); dblbuf = fft->getDoubleTimeBuffer();
for (size_t i = 0; i < windowSize; ++i) { for (size_t i = 0; i < windowSize * oversample; ++i) {
dblbuf[i] = 0.0; dblbuf[i] = 0.0;
} }
} }
@@ -228,13 +253,32 @@ RubberBandStretcher::Impl::ChannelData::setOutbufSize(size_t outbufSize)
} }
} }
void
RubberBandStretcher::Impl::ChannelData::setResampleBufSize(size_t sz)
{
if (!resamplebuf) {
resamplebuf = new float[sz];
resamplebufSize = sz;
return;
}
delete[] resamplebuf;
resamplebuf = new float[sz];
for (size_t i = 0; i < sz; ++i) resamplebuf[i] = 0.f;
resamplebufSize = sz;
}
RubberBandStretcher::Impl::ChannelData::~ChannelData() RubberBandStretcher::Impl::ChannelData::~ChannelData()
{ {
delete resampler; delete resampler;
delete[] resamplebuf;
if (resamplebuf) {
delete[] resamplebuf;
}
delete inbuf; delete inbuf;
delete outbuf; delete outbuf;
delete[] mag; delete[] mag;
delete[] phase; delete[] phase;
delete[] prevPhase; delete[] prevPhase;
@@ -243,6 +287,7 @@ RubberBandStretcher::Impl::ChannelData::~ChannelData()
delete[] accumulator; delete[] accumulator;
delete[] windowAccumulator; delete[] windowAccumulator;
delete[] fltbuf; delete[] fltbuf;
delete[] envelope;
for (std::map<size_t, FFT *>::iterator i = ffts.begin(); for (std::map<size_t, FFT *>::iterator i = ffts.begin();
i != ffts.end(); ++i) { i != ffts.end(); ++i) {
@@ -264,6 +309,7 @@ RubberBandStretcher::Impl::ChannelData::reset()
inCount = 0; inCount = 0;
inputSize = -1; inputSize = -1;
outCount = 0; outCount = 0;
unchanged = true;
draining = false; draining = false;
outputComplete = false; outputComplete = false;
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -19,6 +19,8 @@
#include <set> #include <set>
//#define EXPERIMENT 1
namespace RubberBand namespace RubberBand
{ {
@@ -39,7 +41,7 @@ public:
* the pitch scale factor and any maximum processing block * the pitch scale factor and any maximum processing block
* size specified by the user of the code. * size specified by the user of the code.
*/ */
ChannelData(size_t windowSize, size_t outbufSize); ChannelData(size_t windowSize, int overSample, size_t outbufSize);
/** /**
* Construct a ChannelData structure that can process at * Construct a ChannelData structure that can process at
@@ -54,7 +56,7 @@ public:
* called subsequently. * called subsequently.
*/ */
ChannelData(const std::set<size_t> &windowSizes, ChannelData(const std::set<size_t> &windowSizes,
size_t initialWindowSize, size_t outbufSize); int overSample, size_t initialWindowSize, size_t outbufSize);
~ChannelData(); ~ChannelData();
/** /**
@@ -76,6 +78,12 @@ public:
*/ */
void setOutbufSize(size_t outbufSize); void setOutbufSize(size_t outbufSize);
/**
* Set the resampler buffer size. Default if not called is no
* buffer allocated at all.
*/
void setResampleBufSize(size_t resamplebufSize);
RingBuffer<float> *inbuf; RingBuffer<float> *inbuf;
RingBuffer<float> *outbuf; RingBuffer<float> *outbuf;
@@ -85,6 +93,7 @@ public:
double *prevPhase; double *prevPhase;
double *unwrappedPhase; double *unwrappedPhase;
size_t *freqPeak; size_t *freqPeak;
float *accumulator; float *accumulator;
@@ -93,6 +102,8 @@ public:
float *fltbuf; float *fltbuf;
double *dblbuf; // owned by FFT object, only used for time domain FFT i/o double *dblbuf; // owned by FFT object, only used for time domain FFT i/o
double *envelope; // for cepstral formant shift
bool unchanged;
size_t prevIncrement; // only used in RT mode size_t prevIncrement; // only used in RT mode
@@ -111,6 +122,8 @@ public:
float *resamplebuf; float *resamplebuf;
size_t resamplebufSize; size_t resamplebufSize;
int oversample;
private: private:
void construct(const std::set<size_t> &windowSizes, void construct(const std::set<size_t> &windowSizes,
size_t initialWindowSize, size_t outbufSize); size_t initialWindowSize, size_t outbufSize);

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -20,6 +20,7 @@
#include "StretchCalculator.h" #include "StretchCalculator.h"
#include "StretcherChannelData.h" #include "StretcherChannelData.h"
#include "Resampler.h" #include "Resampler.h"
#include "Profiler.h"
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
@@ -34,6 +35,7 @@ using std::set;
using std::max; using std::max;
using std::min; using std::min;
namespace RubberBand { namespace RubberBand {
const size_t const size_t
@@ -46,6 +48,7 @@ int
RubberBandStretcher::Impl::m_defaultDebugLevel = 0; RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher, RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
size_t sampleRate, size_t sampleRate,
size_t channels, size_t channels,
@@ -80,6 +83,7 @@ RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
m_freq2(12000), m_freq2(12000),
m_baseWindowSize(m_defaultWindowSize) m_baseWindowSize(m_defaultWindowSize)
{ {
if (m_debugLevel > 0) { if (m_debugLevel > 0) {
cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_stretcher->m_sampleRate << ", options = " << options << endl; cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_stretcher->m_sampleRate << ", options = " << options << endl;
} }
@@ -321,31 +325,62 @@ RubberBandStretcher::Impl::calculateSizes()
if (m_realtime) { if (m_realtime) {
// use a fixed input increment
inputIncrement = roundUp(int(m_defaultIncrement * m_rateMultiple));
if (r < 1) { if (r < 1) {
bool rsb = (m_pitchScale < 1.0 && !resampleBeforeStretching());
float windowIncrRatio = 4.5;
if (r == 1.0) windowIncrRatio = 4;
else if (rsb) windowIncrRatio = 4.5;
else windowIncrRatio = 6;
inputIncrement = int(windowSize / windowIncrRatio);
outputIncrement = int(floor(inputIncrement * r)); outputIncrement = int(floor(inputIncrement * r));
if (outputIncrement < 1) {
outputIncrement = 1; // Very long stretch or very low pitch shift
inputIncrement = roundUp(lrint(ceil(outputIncrement / r))); if (outputIncrement < m_defaultIncrement / 4) {
windowSize = inputIncrement * 4; if (outputIncrement < 1) outputIncrement = 1;
while (outputIncrement < m_defaultIncrement / 4 &&
windowSize < m_baseWindowSize * 4) {
outputIncrement *= 2;
inputIncrement = lrint(ceil(outputIncrement / r));
windowSize = roundUp(lrint(ceil(inputIncrement * windowIncrRatio)));
}
} }
} else { } else {
outputIncrement = int(ceil(inputIncrement * r));
while (outputIncrement > 1024 && inputIncrement > 1) { bool rsb = (m_pitchScale > 1.0 && resampleBeforeStretching());
inputIncrement /= 2; float windowIncrRatio = 4.5;
outputIncrement = lrint(ceil(inputIncrement * r)); if (r == 1.0) windowIncrRatio = 4;
else if (rsb) windowIncrRatio = 4.5;
else windowIncrRatio = 6;
outputIncrement = int(windowSize / windowIncrRatio);
inputIncrement = int(outputIncrement / r);
while (outputIncrement > 1024 * m_rateMultiple &&
inputIncrement > 1) {
outputIncrement /= 2;
inputIncrement = int(outputIncrement / r);
}
size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio));
if (windowSize < minwin) windowSize = minwin;
if (rsb) {
// cerr << "adjusting window size from " << windowSize;
size_t newWindowSize = roundUp(lrint(windowSize / m_pitchScale));
if (newWindowSize < 512) newWindowSize = 512;
size_t div = windowSize / newWindowSize;
if (inputIncrement > div && outputIncrement > div) {
inputIncrement /= div;
outputIncrement /= div;
windowSize /= div;
}
// cerr << " to " << windowSize << " (inputIncrement = " << inputIncrement << ", outputIncrement = " << outputIncrement << ")" << endl;
} }
windowSize = std::max(windowSize, roundUp(outputIncrement * 6));
if (r > 5) while (windowSize < 8192) windowSize *= 2;
} }
} else { } else {
// use a variable increment
if (r < 1) { if (r < 1) {
inputIncrement = windowSize / 4; inputIncrement = windowSize / 4;
while (inputIncrement >= 512) inputIncrement /= 2; while (inputIncrement >= 512) inputIncrement /= 2;
@@ -365,7 +400,7 @@ RubberBandStretcher::Impl::calculateSizes()
windowSize = std::max(windowSize, roundUp(outputIncrement * 6)); windowSize = std::max(windowSize, roundUp(outputIncrement * 6));
if (r > 5) while (windowSize < 8192) windowSize *= 2; if (r > 5) while (windowSize < 8192) windowSize *= 2;
} }
} }
if (m_expectedInputDuration > 0) { if (m_expectedInputDuration > 0) {
while (inputIncrement * 4 > m_expectedInputDuration && while (inputIncrement * 4 > m_expectedInputDuration &&
@@ -450,8 +485,9 @@ RubberBandStretcher::Impl::configure()
set<size_t> windowSizes; set<size_t> windowSizes;
if (m_realtime) { if (m_realtime) {
windowSizes.insert(m_baseWindowSize); windowSizes.insert(m_baseWindowSize);
windowSizes.insert(m_baseWindowSize / 2);
windowSizes.insert(m_baseWindowSize * 2); windowSizes.insert(m_baseWindowSize * 2);
windowSizes.insert(m_baseWindowSize * 4); // windowSizes.insert(m_baseWindowSize * 4);
} }
windowSizes.insert(m_windowSize); windowSizes.insert(m_windowSize);
@@ -479,13 +515,13 @@ RubberBandStretcher::Impl::configure()
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
m_channelData.push_back m_channelData.push_back
(new ChannelData(windowSizes, m_windowSize, m_outbufSize)); (new ChannelData(windowSizes, 1, m_windowSize, m_outbufSize));
} }
} }
if (!m_realtime && windowSizeChanged) { if (!m_realtime && windowSizeChanged) {
delete m_studyFFT; delete m_studyFFT;
m_studyFFT = new FFT(m_windowSize); m_studyFFT = new FFT(m_windowSize, m_debugLevel);
m_studyFFT->initFloat(); m_studyFFT->initFloat();
} }
@@ -496,7 +532,8 @@ RubberBandStretcher::Impl::configure()
if (m_channelData[c]->resampler) continue; if (m_channelData[c]->resampler) continue;
m_channelData[c]->resampler = m_channelData[c]->resampler =
new Resampler(Resampler::FastestTolerable, 1, 4096 * 16); new Resampler(Resampler::FastestTolerable, 1, 4096 * 16,
m_debugLevel);
// rbs is the amount of buffer space we think we'll need // rbs is the amount of buffer space we think we'll need
// for resampling; but allocate a sensible amount in case // for resampling; but allocate a sensible amount in case
@@ -504,8 +541,7 @@ RubberBandStretcher::Impl::configure()
size_t rbs = size_t rbs =
lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)); lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale));
if (rbs < m_increment * 16) rbs = m_increment * 16; if (rbs < m_increment * 16) rbs = m_increment * 16;
m_channelData[c]->resamplebufSize = rbs; m_channelData[c]->setResampleBufSize(rbs);
m_channelData[c]->resamplebuf = new float[rbs];
} }
} }
@@ -609,12 +645,11 @@ RubberBandStretcher::Impl::reconfigure()
std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl; std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
m_channelData[c]->resampler = m_channelData[c]->resampler =
new Resampler(Resampler::FastestTolerable, 1, m_windowSize); new Resampler(Resampler::FastestTolerable, 1, m_windowSize,
m_debugLevel);
m_channelData[c]->resamplebufSize = m_channelData[c]->setResampleBufSize
lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)); (lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)));
m_channelData[c]->resamplebuf =
new float[m_channelData[c]->resamplebufSize];
} }
} }
@@ -637,9 +672,9 @@ RubberBandStretcher::Impl::setTransientsOption(Options options)
cerr << "RubberBandStretcher::Impl::setTransientsOption: Not permissible in non-realtime mode" << endl; cerr << "RubberBandStretcher::Impl::setTransientsOption: Not permissible in non-realtime mode" << endl;
return; return;
} }
m_options &= ~(OptionTransientsMixed | int mask = (OptionTransientsMixed | OptionTransientsSmooth | OptionTransientsCrisp);
OptionTransientsSmooth | m_options &= ~mask;
OptionTransientsCrisp); options &= mask;
m_options |= options; m_options |= options;
m_stretchCalculator->setUseHardPeaks m_stretchCalculator->setUseHardPeaks
@@ -649,15 +684,44 @@ RubberBandStretcher::Impl::setTransientsOption(Options options)
void void
RubberBandStretcher::Impl::setPhaseOption(Options options) RubberBandStretcher::Impl::setPhaseOption(Options options)
{ {
m_options &= ~(OptionPhaseAdaptive | int mask = (OptionPhaseAdaptive | OptionPhasePeakLocked | OptionPhaseIndependent);
OptionPhasePeakLocked | m_options &= ~mask;
OptionPhaseIndependent); options &= mask;
m_options |= options; m_options |= options;
} }
void
RubberBandStretcher::Impl::setFormantOption(Options options)
{
int mask = (OptionFormantShifted | OptionFormantPreserved);
m_options &= ~mask;
options &= mask;
m_options |= options;
}
void
RubberBandStretcher::Impl::setPitchOption(Options options)
{
if (!m_realtime) {
cerr << "RubberBandStretcher::Impl::setPitchOption: Pitch option is not used in non-RT mode" << endl;
return;
}
Options prior = m_options;
int mask = (OptionPitchHighQuality | OptionPitchHighSpeed);
m_options &= ~mask;
options &= mask;
m_options |= options;
if (prior != m_options) reconfigure();
}
void void
RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool final) RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool final)
{ {
Profiler profiler("RubberBandStretcher::Impl::study");
if (m_realtime) { if (m_realtime) {
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
cerr << "RubberBandStretcher::Impl::study: Not meaningful in realtime mode" << endl; cerr << "RubberBandStretcher::Impl::study: Not meaningful in realtime mode" << endl;
@@ -817,6 +881,8 @@ RubberBandStretcher::Impl::getExactTimePoints() const
void void
RubberBandStretcher::Impl::calculateStretch() RubberBandStretcher::Impl::calculateStretch()
{ {
Profiler profiler("RubberBandStretcher::Impl::calculateStretch");
std::vector<int> increments = m_stretchCalculator->calculate std::vector<int> increments = m_stretchCalculator->calculate
(getEffectiveRatio(), (getEffectiveRatio(),
m_inputDuration, m_inputDuration,
@@ -843,6 +909,8 @@ RubberBandStretcher::Impl::setDebugLevel(int level)
size_t size_t
RubberBandStretcher::Impl::getSamplesRequired() const RubberBandStretcher::Impl::getSamplesRequired() const
{ {
Profiler profiler("RubberBandStretcher::Impl::getSamplesRequired");
size_t reqd = 0; size_t reqd = 0;
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
@@ -878,6 +946,8 @@ RubberBandStretcher::Impl::getSamplesRequired() const
void void
RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final) RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final)
{ {
Profiler profiler("RubberBandStretcher::Impl::process");
if (m_mode == Finished) { if (m_mode == Finished) {
cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl; cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl;
return; return;
@@ -935,10 +1005,12 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
// have actually been processed. // have actually been processed.
allConsumed = true; allConsumed = true;
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
consumed[c] += consumeChannel(c, consumed[c] += consumeChannel(c,
input[c] + consumed[c], input[c] + consumed[c],
samples - consumed[c]); samples - consumed[c],
final);
if (consumed[c] < samples) { if (consumed[c] < samples) {
allConsumed = false; allConsumed = false;
// cerr << "process: waiting on input consumption for channel " << c << endl; // cerr << "process: waiting on input consumption for channel " << c << endl;
@@ -988,36 +1060,6 @@ RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bo
if (final) m_mode = Finished; if (final) m_mode = Finished;
} }
size_t
RubberBandStretcher::Impl::consumeChannel(size_t c, const float *input, size_t samples)
{
size_t consumed = 0;
ChannelData &cd = *m_channelData[c];
RingBuffer<float> &inbuf = *cd.inbuf;
while (consumed < samples) {
size_t writable = inbuf.getWriteSpace();
// cerr << "channel " << c << ": samples remaining = " << samples - consumed << ", writable space = " << writable << endl;
writable = min(writable, samples - consumed);
if (writable == 0) {
// warn
// cerr << "WARNING: writable == 0 for ch " << c << " (consumed = " << consumed << ", samples = " << samples << ")" << endl;
return consumed;
} else {
inbuf.write(input + consumed, writable);
consumed += writable;
cd.inCount += writable;
}
}
return samples;
}
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -50,6 +50,8 @@ public:
void setTransientsOption(Options); void setTransientsOption(Options);
void setPhaseOption(Options); void setPhaseOption(Options);
void setFormantOption(Options);
void setPitchOption(Options);
void setExpectedInputDuration(size_t samples); void setExpectedInputDuration(size_t samples);
void setMaxProcessSize(size_t samples); void setMaxProcessSize(size_t samples);
@@ -86,7 +88,8 @@ protected:
RubberBandStretcher *m_stretcher; RubberBandStretcher *m_stretcher;
size_t m_channels; size_t m_channels;
size_t consumeChannel(size_t channel, const float *input, size_t samples); size_t consumeChannel(size_t channel, const float *input,
size_t samples, bool final);
void processChunks(size_t channel, bool &any, bool &last); void processChunks(size_t channel, bool &any, bool &last);
bool processOneChunk(); // across all channels, for real time use bool processOneChunk(); // across all channels, for real time use
bool processChunkForChannel(size_t channel, size_t phaseIncrement, bool processChunkForChannel(size_t channel, size_t phaseIncrement,
@@ -98,6 +101,7 @@ protected:
size_t &shiftIncrement, bool &phaseReset); size_t &shiftIncrement, bool &phaseReset);
void analyseChunk(size_t channel); void analyseChunk(size_t channel);
void modifyChunk(size_t channel, size_t outputIncrement, bool phaseReset); void modifyChunk(size_t channel, size_t outputIncrement, bool phaseReset);
void formantShiftChunk(size_t channel);
void synthesiseChunk(size_t channel); void synthesiseChunk(size_t channel);
void writeChunk(size_t channel, size_t shiftIncrement, bool last); void writeChunk(size_t channel, size_t shiftIncrement, bool last);
@@ -109,6 +113,8 @@ protected:
size_t roundUp(size_t value); // to next power of two size_t roundUp(size_t value); // to next power of two
bool resampleBeforeStretching() const;
double m_timeRatio; double m_timeRatio;
double m_pitchScale; double m_pitchScale;

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -19,11 +19,14 @@
#include "StretchCalculator.h" #include "StretchCalculator.h"
#include "StretcherChannelData.h" #include "StretcherChannelData.h"
#include "Resampler.h" #include "Resampler.h"
#include "Profiler.h"
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <set> #include <set>
#include <map> #include <map>
#include <deque>
using std::cerr; using std::cerr;
using std::endl; using std::endl;
@@ -97,9 +100,82 @@ RubberBandStretcher::Impl::ProcessThread::abandon()
m_abandoning = true; m_abandoning = true;
} }
bool
RubberBandStretcher::Impl::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) {
return (m_pitchScale < 1.0); // better sound
} else {
return (m_pitchScale > 1.0); // better performance
}
}
size_t
RubberBandStretcher::Impl::consumeChannel(size_t c, const float *input,
size_t samples, bool final)
{
Profiler profiler("RubberBandStretcher::Impl::consumeChannel");
ChannelData &cd = *m_channelData[c];
RingBuffer<float> &inbuf = *cd.inbuf;
size_t toWrite = samples;
size_t writable = inbuf.getWriteSpace();
bool resampling = resampleBeforeStretching();
if (resampling) {
toWrite = int(ceil(samples / m_pitchScale));
if (writable < toWrite) {
samples = int(floor(writable * m_pitchScale));
if (samples == 0) return 0;
}
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;
cd.setResampleBufSize(reqSize);
}
toWrite = cd.resampler->resample(&input,
&cd.resamplebuf,
samples,
1.0 / m_pitchScale,
final);
}
if (writable < toWrite) {
if (resampling) {
return 0;
}
toWrite = writable;
}
if (resampling) {
inbuf.write(cd.resamplebuf, toWrite);
cd.inCount += samples;
return samples;
} else {
inbuf.write(input, toWrite);
cd.inCount += toWrite;
return toWrite;
}
}
void void
RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last) RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
{ {
Profiler profiler("RubberBandStretcher::Impl::processChunks");
// Process as many chunks as there are available on the input // Process as many chunks as there are available on the input
// buffer for channel c. This requires that the increments have // buffer for channel c. This requires that the increments have
// already been calculated. // already been calculated.
@@ -140,6 +216,8 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
bool bool
RubberBandStretcher::Impl::processOneChunk() RubberBandStretcher::Impl::processOneChunk()
{ {
Profiler profiler("RubberBandStretcher::Impl::processOneChunk");
// Process a single chunk for all channels, provided there is // Process a single chunk for all channels, provided there is
// enough data on each channel for at least one chunk. This is // enough data on each channel for at least one chunk. This is
// able to calculate increments as it goes along. // able to calculate increments as it goes along.
@@ -173,6 +251,8 @@ RubberBandStretcher::Impl::processOneChunk()
bool bool
RubberBandStretcher::Impl::testInbufReadSpace(size_t c) RubberBandStretcher::Impl::testInbufReadSpace(size_t c)
{ {
Profiler profiler("RubberBandStretcher::Impl::testInbufReadSpace");
ChannelData &cd = *m_channelData[c]; ChannelData &cd = *m_channelData[c];
RingBuffer<float> &inbuf = *cd.inbuf; RingBuffer<float> &inbuf = *cd.inbuf;
@@ -223,6 +303,8 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
size_t shiftIncrement, size_t shiftIncrement,
bool phaseReset) bool phaseReset)
{ {
Profiler profiler("RubberBandStretcher::Impl::processChunkForChannel");
// Process a single chunk on a single channel. This assumes // Process a single chunk on a single channel. This assumes
// enough input data is available; caller must have tested this // enough input data is available; caller must have tested this
// using e.g. testInbufReadSpace first. Return true if this is // using e.g. testInbufReadSpace first. Return true if this is
@@ -284,7 +366,9 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
} }
if (m_threaded) { if (m_threaded) {
size_t required = shiftIncrement;
int required = shiftIncrement;
if (m_pitchScale != 1.0) { if (m_pitchScale != 1.0) {
required = int(required / m_pitchScale) + 1; required = int(required / m_pitchScale) + 1;
} }
@@ -313,6 +397,8 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
size_t &shiftIncrementRtn, size_t &shiftIncrementRtn,
bool &phaseReset) bool &phaseReset)
{ {
Profiler profiler("RubberBandStretcher::Impl::calculateIncrements");
// cerr << "calculateIncrements" << endl; // cerr << "calculateIncrements" << endl;
// Calculate the next upcoming phase and shift increment, on the // Calculate the next upcoming phase and shift increment, on the
@@ -342,6 +428,8 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
} }
} }
const int hs = m_windowSize/2 + 1;
// Normally we would mix down the time-domain signal and apply a // Normally we would mix down the time-domain signal and apply a
// single FFT, or else mix down the Cartesian form of the // single FFT, or else mix down the Cartesian form of the
// frequency-domain signal. Both of those would be inefficient // frequency-domain signal. Both of those would be inefficient
@@ -352,22 +440,30 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
// phases to cancel each other, and broadband effects will still // phases to cancel each other, and broadband effects will still
// be apparent. // be apparent.
for (size_t i = 0; i <= m_windowSize/2; ++i) { float df = 0.f;
cd.fltbuf[i] = 0.0;
}
for (size_t c = 0; c < m_channels; ++c) { if (m_channels == 1) {
for (size_t i = 0; i <= m_windowSize/2; ++i) {
cd.fltbuf[i] += m_channelData[c]->mag[i]; df = m_phaseResetAudioCurve->process(cd.mag, m_increment);
} else {
double *tmp = (double *)alloca(hs * sizeof(double));
for (int i = 0; i < hs; ++i) {
tmp[i] = 0.0;
}
for (size_t c = 0; c < m_channels; ++c) {
for (int i = 0; i < hs; ++i) {
tmp[i] += m_channelData[c]->mag[i];
}
} }
}
float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment); df = m_phaseResetAudioCurve->process(tmp, m_increment);
}
int incr = m_stretchCalculator->calculateSingle int incr = m_stretchCalculator->calculateSingle
(getEffectiveRatio(), (getEffectiveRatio(), df, m_increment);
m_inputDuration, //!!! no, totally wrong... fortunately it doesn't matter atm
df);
m_lastProcessPhaseResetDf.write(&df, 1); m_lastProcessPhaseResetDf.write(&df, 1);
m_lastProcessOutputIncrements.write(&incr, 1); m_lastProcessOutputIncrements.write(&incr, 1);
@@ -407,6 +503,8 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
size_t &shiftIncrementRtn, size_t &shiftIncrementRtn,
bool &phaseReset) bool &phaseReset)
{ {
Profiler profiler("RubberBandStretcher::Impl::getIncrements");
if (channel >= m_channels) { if (channel >= m_channels) {
phaseIncrementRtn = m_increment; phaseIncrementRtn = m_increment;
shiftIncrementRtn = m_increment; shiftIncrementRtn = m_increment;
@@ -478,39 +576,78 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
void void
RubberBandStretcher::Impl::analyseChunk(size_t channel) RubberBandStretcher::Impl::analyseChunk(size_t channel)
{ {
size_t i; Profiler profiler("RubberBandStretcher::Impl::analyseChunk");
int i;
ChannelData &cd = *m_channelData[channel]; ChannelData &cd = *m_channelData[channel];
double *const R__ dblbuf = cd.dblbuf;
float *const R__ fltbuf = cd.fltbuf;
int sz = m_windowSize;
int hs = m_windowSize/2;
// cd.fltbuf is known to contain m_windowSize samples // cd.fltbuf is known to contain m_windowSize samples
m_window->cut(cd.fltbuf); m_window->cut(fltbuf);
for (i = 0; i < m_windowSize/2; ++i) { if (cd.oversample > 1) {
cd.dblbuf[i] = cd.fltbuf[i + m_windowSize/2];
cd.dblbuf[i + m_windowSize/2] = cd.fltbuf[i]; int bufsiz = sz * cd.oversample;
int offset = (bufsiz - sz) / 2;
// eek
for (i = 0; i < offset; ++i) {
dblbuf[i] = 0.0;
}
for (i = 0; i < offset; ++i) {
dblbuf[bufsiz - i - 1] = 0.0;
}
for (i = 0; i < sz; ++i) {
dblbuf[offset + i] = fltbuf[i];
}
for (i = 0; i < bufsiz / 2; ++i) {
double tmp = dblbuf[i];
dblbuf[i] = dblbuf[i + bufsiz/2];
dblbuf[i + bufsiz/2] = tmp;
}
} else {
for (i = 0; i < hs; ++i) {
dblbuf[i] = fltbuf[i + hs];
dblbuf[i + hs] = fltbuf[i];
}
} }
cd.fft->forwardPolar(cd.dblbuf, cd.mag, cd.phase); cd.fft->forwardPolar(dblbuf, cd.mag, cd.phase);
} }
double mod(double x, double y) { return x - (y * floor(x / y)); } static inline double mod(double x, double y) { return x - (y * floor(x / y)); }
double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; } static inline double princarg(double a) { return mod(a + M_PI, -2.0 * M_PI) + M_PI; }
void void
RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement, RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
bool phaseReset) bool phaseReset)
{ {
Profiler profiler("RubberBandStretcher::Impl::modifyChunk");
ChannelData &cd = *m_channelData[channel]; ChannelData &cd = *m_channelData[channel];
if (phaseReset && m_debugLevel > 1) { if (phaseReset && m_debugLevel > 1) {
cerr << "phase reset: leaving phases unmodified" << endl; cerr << "phase reset: leaving phases unmodified" << endl;
} }
size_t count = m_windowSize/2; int pfp = 0;
size_t pfp = 0;
double rate = m_stretcher->m_sampleRate; double rate = m_stretcher->m_sampleRate;
int sz = m_windowSize;
int count = (sz * cd.oversample) / 2;
bool unchanged = cd.unchanged && (outputIncrement == m_increment);
bool fullReset = phaseReset;
if (!(m_options & OptionPhaseIndependent)) { if (!(m_options & OptionPhaseIndependent)) {
cd.freqPeak[0] = 0; cd.freqPeak[0] = 0;
@@ -539,11 +676,11 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
} }
} }
size_t limit0 = lrint((freq0 * m_windowSize) / rate); int limit0 = lrint((freq0 * sz * cd.oversample) / rate);
size_t limit1 = lrint((freq1 * m_windowSize) / rate); int limit1 = lrint((freq1 * sz * cd.oversample) / rate);
size_t limit2 = lrint((freq2 * m_windowSize) / rate); int limit2 = lrint((freq2 * sz * cd.oversample) / rate);
size_t range = 0; int range = 0;
if (limit1 < limit0) limit1 = limit0; if (limit1 < limit0) limit1 = limit0;
if (limit2 < limit1) limit2 = limit1; if (limit2 < limit1) limit2 = limit1;
@@ -552,12 +689,12 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
int peakCount = 0; int peakCount = 0;
for (size_t i = 0; i <= count; ++i) { for (int i = 0; i <= count; ++i) {
double mag = cd.mag[i]; double mag = cd.mag[i];
bool isPeak = true; bool isPeak = true;
for (size_t j = 1; j <= range; ++j) { for (int j = 1; j <= range; ++j) {
if (mag < cd.mag[i-j]) { if (mag < cd.mag[i-j]) {
isPeak = false; isPeak = false;
@@ -578,13 +715,13 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
// from pfp to half-way between pfp and i point at pfp, and // from pfp to half-way between pfp and i point at pfp, and
// those from the half-way mark to i point at i. // those from the half-way mark to i point at i.
size_t halfway = (pfp + i) / 2; int halfway = (pfp + i) / 2;
if (halfway == pfp) halfway = pfp + 1; if (halfway == pfp) halfway = pfp + 1;
for (size_t j = pfp + 1; j < halfway; ++j) { for (int j = pfp + 1; j < halfway; ++j) {
cd.freqPeak[j] = pfp; cd.freqPeak[j] = pfp;
} }
for (size_t j = halfway; j <= i; ++j) { for (int j = halfway; j <= i; ++j) {
cd.freqPeak[j] = i; cd.freqPeak[j] = i;
} }
@@ -607,27 +744,33 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
cd.freqPeak[count] = count; cd.freqPeak[count] = count;
} }
Profiler profiler2("RubberBandStretcher::Impl::modifyChunk part 2");
double peakInPhase = 0.0; double peakInPhase = 0.0;
double peakOutPhase = 0.0; double peakOutPhase = 0.0;
int p = -1, pp = -1; int p = -1, pp = -1;
for (size_t i = 0; i <= count; ++i) {
for (int i = 0; i <= count; ++i) {
if (m_options & OptionPhaseIndependent) { if (m_options & OptionPhaseIndependent) {
p = i; p = i;
pp = int(i)-1; pp = i-1;
} else { } else {
p = cd.freqPeak[i]; p = cd.freqPeak[i];
if (i > 0) pp = int(cd.freqPeak[i-1]); if (i > 0) pp = cd.freqPeak[i-1];
} }
bool resetThis = phaseReset; bool resetThis = phaseReset;
if (m_options & OptionTransientsMixed) { if (m_options & OptionTransientsMixed) {
size_t low = lrint((150 * m_windowSize) / rate); int low = lrint((150 * sz * cd.oversample) / rate);
size_t high = lrint((1000 * m_windowSize) / rate); int high = lrint((1000 * sz * cd.oversample) / rate);
if (resetThis) { if (resetThis) {
if (i > low && i < high) resetThis = false; if (i > low && i < high) {
resetThis = false;
fullReset = false;
}
} }
} }
@@ -635,7 +778,9 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
if (i == 0 || p != pp) { if (i == 0 || p != pp) {
double omega = (2 * M_PI * m_increment * p) / m_windowSize;
double omega = (2 * M_PI * m_increment * p) /
(sz * cd.oversample);
double expectedPhase = cd.prevPhase[p] + omega; double expectedPhase = cd.prevPhase[p] + omega;
double phaseError = princarg(cd.phase[p] - expectedPhase); double phaseError = princarg(cd.phase[p] - expectedPhase);
double phaseIncrement = (omega + phaseError) / m_increment; double phaseIncrement = (omega + phaseError) / m_increment;
@@ -649,10 +794,13 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
peakInPhase = cd.prevPhase[p]; peakInPhase = cd.prevPhase[p];
peakOutPhase = unwrappedPhase; peakOutPhase = unwrappedPhase;
} }
if (i != p) { if (i != p) {
// cd.phase[i] = atan2(cd.imag[i], cd.real[i]);//!!!
double diffToPeak = peakInPhase - cd.phase[i]; double diffToPeak = peakInPhase - cd.phase[i];
double unwrappedPhase = peakOutPhase - diffToPeak; double unwrappedPhase = peakOutPhase - diffToPeak;
@@ -662,57 +810,186 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
} }
} else { } else {
// resetThis == true
cd.prevPhase[i] = cd.phase[i]; cd.prevPhase[i] = cd.phase[i];
cd.unwrappedPhase[i] = cd.phase[i]; cd.unwrappedPhase[i] = cd.phase[i];
} }
} }
if (fullReset) unchanged = true;
cd.unchanged = unchanged;
if (unchanged && m_debugLevel > 1) {
cerr << "frame unchanged on channel " << channel << endl;
}
}
void
RubberBandStretcher::Impl::formantShiftChunk(size_t channel)
{
Profiler profiler("RubberBandStretcher::Impl::formantShiftChunk");
ChannelData &cd = *m_channelData[channel];
double *const R__ mag = cd.mag;
double *const R__ envelope = cd.envelope;
double *const R__ dblbuf = cd.dblbuf;
const int sz = m_windowSize;
const int hs = m_windowSize/2;
cd.fft->inverseCepstral(mag, dblbuf);
double denom = sz;
for (int i = 0; i < sz; ++i) {
dblbuf[i] /= denom;
}
//!!! calculate this value -- the divisor should be the highest fundamental frequency we expect to find, plus a bit
const int cutoff = m_stretcher->m_sampleRate / 700;
dblbuf[0] /= 2;
dblbuf[cutoff-1] /= 2;
for (int i = cutoff; i < sz; ++i) {
dblbuf[i] = 0.0;
}
cd.fft->forward(dblbuf, envelope, 0);
for (int i = 0; i <= hs; ++i) {
envelope[i] = exp(envelope[i]);
}
for (int i = 0; i <= hs; ++i) {
mag[i] /= envelope[i];
}
if (m_pitchScale > 1.0) {
// scaling up, we want a new envelope that is lower by the pitch factor
for (int target = 0; target <= hs; ++target) {
int source = lrint(target * m_pitchScale);
if (source > m_windowSize) {
envelope[target] = 0.0;
} else {
envelope[target] = envelope[source];
}
}
} else {
// scaling down, we want a new envelope that is higher by the pitch factor
for (int target = hs; target > 0; ) {
--target;
int source = lrint(target * m_pitchScale);
envelope[target] = envelope[source];
}
}
for (int i = 0; i <= hs; ++i) {
mag[i] *= envelope[i];
}
cd.unchanged = false;
} }
void void
RubberBandStretcher::Impl::synthesiseChunk(size_t channel) RubberBandStretcher::Impl::synthesiseChunk(size_t channel)
{ {
Profiler profiler("RubberBandStretcher::Impl::synthesiseChunk");
if ((m_options & OptionFormantPreserved) &&
(m_pitchScale != 1.0)) {
formantShiftChunk(channel);
}
ChannelData &cd = *m_channelData[channel]; ChannelData &cd = *m_channelData[channel];
cd.fft->inversePolar(cd.mag, cd.phase, cd.dblbuf); double *const R__ dblbuf = cd.dblbuf;
float *const R__ fltbuf = cd.fltbuf;
float *const R__ accumulator = cd.accumulator;
float *const R__ windowAccumulator = cd.windowAccumulator;
int sz = m_windowSize;
int hs = m_windowSize/2;
int i;
for (size_t i = 0; i < m_windowSize/2; ++i) {
cd.fltbuf[i] = cd.dblbuf[i + m_windowSize/2]; if (!cd.unchanged) {
cd.fltbuf[i + m_windowSize/2] = cd.dblbuf[i];
cd.fft->inversePolar(cd.mag, cd.phase, cd.dblbuf);
if (cd.oversample > 1) {
int bufsiz = sz * cd.oversample;
int hbs = hs * cd.oversample;
int offset = (bufsiz - sz) / 2;
for (i = 0; i < hbs; ++i) {
double tmp = dblbuf[i];
dblbuf[i] = dblbuf[i + hbs];
dblbuf[i + hbs] = tmp;
}
for (i = 0; i < sz; ++i) {
fltbuf[i] = float(dblbuf[i + offset]);
}
} else {
for (i = 0; i < hs; ++i) {
fltbuf[i] = float(dblbuf[i + hs]);
}
for (i = 0; i < hs; ++i) {
fltbuf[i + hs] = float(dblbuf[i]);
}
}
float denom = float(sz * cd.oversample);
// our ffts produced unscaled results
for (i = 0; i < sz; ++i) {
fltbuf[i] = fltbuf[i] / float(sz * cd.oversample);
}
// } else {
// cerr << "unchanged on channel " << channel << endl;
} }
// our ffts produced unscaled results m_window->cut(fltbuf);
for (size_t i = 0; i < m_windowSize; ++i) {
cd.fltbuf[i] = cd.fltbuf[i] / m_windowSize;
}
m_window->cut(cd.fltbuf); for (i = 0; i < sz; ++i) {
accumulator[i] += fltbuf[i];
for (size_t i = 0; i < m_windowSize; ++i) {
cd.accumulator[i] += cd.fltbuf[i];
} }
cd.accumulatorFill = m_windowSize; cd.accumulatorFill = m_windowSize;
float fixed = m_window->getArea() * 1.5; float fixed = m_window->getArea() * 1.5f;
for (size_t i = 0; i < m_windowSize; ++i) { for (i = 0; i < sz; ++i) {
float val = m_window->getValue(i); float val = m_window->getValue(i);
cd.windowAccumulator[i] += val * fixed; windowAccumulator[i] += val * fixed;
} }
} }
void void
RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, bool last) RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, bool last)
{ {
ChannelData &cd = *m_channelData[channel]; Profiler profiler("RubberBandStretcher::Impl::writeChunk");
ChannelData &cd = *m_channelData[channel];
float *const R__ accumulator = cd.accumulator;
float *const R__ windowAccumulator = cd.windowAccumulator;
const int sz = m_windowSize;
const int si = shiftIncrement;
int i;
if (m_debugLevel > 2) { if (m_debugLevel > 2) {
cerr << "writeChunk(" << channel << ", " << shiftIncrement << ", " << last << ")" << endl; cerr << "writeChunk(" << channel << ", " << shiftIncrement << ", " << last << ")" << endl;
} }
for (int i = 0; i < shiftIncrement; ++i) { for (i = 0; i < si; ++i) {
if (cd.windowAccumulator[i] > 0.f) { if (windowAccumulator[i] > 0.f) {
cd.accumulator[i] /= cd.windowAccumulator[i]; accumulator[i] /= windowAccumulator[i];
} }
} }
@@ -723,9 +1000,11 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
theoreticalOut = lrint(cd.inputSize * m_timeRatio); theoreticalOut = lrint(cd.inputSize * m_timeRatio);
} }
if (m_pitchScale != 1.0 && cd.resampler) { bool resampledAlready = resampleBeforeStretching();
size_t reqSize = int(ceil(shiftIncrement / m_pitchScale)); if (!resampledAlready && m_pitchScale != 1.0 && cd.resampler) {
size_t reqSize = int(ceil(si / m_pitchScale));
if (reqSize > cd.resamplebufSize) { if (reqSize > cd.resamplebufSize) {
// This shouldn't normally happen -- the buffer is // This shouldn't normally happen -- the buffer is
// supposed to be initialised with enough space in the // supposed to be initialised with enough space in the
@@ -734,15 +1013,13 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
// calculator has gone mad, or something. // calculator has gone mad, or something.
cerr << "WARNING: RubberBandStretcher::Impl::writeChunk: resizing resampler buffer from " cerr << "WARNING: RubberBandStretcher::Impl::writeChunk: resizing resampler buffer from "
<< cd.resamplebufSize << " to " << reqSize << endl; << cd.resamplebufSize << " to " << reqSize << endl;
cd.resamplebufSize = reqSize; cd.setResampleBufSize(reqSize);
if (cd.resamplebuf) delete[] cd.resamplebuf;
cd.resamplebuf = new float[cd.resamplebufSize];
} }
size_t outframes = cd.resampler->resample(&cd.accumulator, size_t outframes = cd.resampler->resample(&cd.accumulator,
&cd.resamplebuf, &cd.resamplebuf,
shiftIncrement, si,
1.0 / m_pitchScale, 1.0 / m_pitchScale,
last); last);
@@ -751,28 +1028,28 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
outframes, cd.outCount, theoreticalOut); outframes, cd.outCount, theoreticalOut);
} else { } else {
writeOutput(*cd.outbuf, cd.accumulator, writeOutput(*cd.outbuf, accumulator,
shiftIncrement, cd.outCount, theoreticalOut); si, cd.outCount, theoreticalOut);
} }
for (size_t i = 0; i < m_windowSize - shiftIncrement; ++i) { for (i = 0; i < sz - si; ++i) {
cd.accumulator[i] = cd.accumulator[i + shiftIncrement]; accumulator[i] = accumulator[i + si];
} }
for (size_t i = m_windowSize - shiftIncrement; i < m_windowSize; ++i) { for (i = sz - si; i < sz; ++i) {
cd.accumulator[i] = 0.0f; accumulator[i] = 0.0f;
} }
for (size_t i = 0; i < m_windowSize - shiftIncrement; ++i) { for (i = 0; i < sz - si; ++i) {
cd.windowAccumulator[i] = cd.windowAccumulator[i + shiftIncrement]; windowAccumulator[i] = windowAccumulator[i + si];
} }
for (size_t i = m_windowSize - shiftIncrement; i < m_windowSize; ++i) { for (i = sz - si; i < sz; ++i) {
cd.windowAccumulator[i] = 0.0f; windowAccumulator[i] = 0.0f;
} }
if (cd.accumulatorFill > shiftIncrement) { if (cd.accumulatorFill > si) {
cd.accumulatorFill -= shiftIncrement; cd.accumulatorFill -= si;
} else { } else {
cd.accumulatorFill = 0; cd.accumulatorFill = 0;
if (cd.draining) { if (cd.draining) {
@@ -787,6 +1064,8 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
void void
RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t &outCount, size_t theoreticalOut) RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_t qty, size_t &outCount, size_t theoreticalOut)
{ {
Profiler profiler("RubberBandStretcher::Impl::writeOutput");
// In non-RT mode, we don't want to write the first startSkip // 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 // samples, because the first chunk is centred on the start of the
// output. In RT mode we didn't apply any pre-padding in // output. In RT mode we didn't apply any pre-padding in
@@ -859,6 +1138,8 @@ RubberBandStretcher::Impl::writeOutput(RingBuffer<float> &to, float *from, size_
int int
RubberBandStretcher::Impl::available() const RubberBandStretcher::Impl::available() const
{ {
Profiler profiler("RubberBandStretcher::Impl::available");
if (m_threaded) { if (m_threaded) {
MutexLocker locker(&m_threadSetMutex); MutexLocker locker(&m_threadSetMutex);
if (m_channelData.empty()) return 0; if (m_channelData.empty()) return 0;
@@ -906,6 +1187,8 @@ RubberBandStretcher::Impl::available() const
size_t size_t
RubberBandStretcher::Impl::retrieve(float *const *output, size_t samples) const RubberBandStretcher::Impl::retrieve(float *const *output, size_t samples) const
{ {
Profiler profiler("RubberBandStretcher::Impl::retrieve");
size_t got = samples; size_t got = samples;
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -15,14 +15,11 @@
#include "Thread.h" #include "Thread.h"
#include <iostream> #include <iostream>
#include <cstdlib>
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
//#define DEBUG_THREAD 1
//#define DEBUG_MUTEX 1
//#define DEBUG_CONDITION 1
using std::cerr; using std::cerr;
using std::endl; using std::endl;
using std::string; using std::string;
@@ -107,8 +104,11 @@ Thread::staticRun(LPVOID arg)
return 0; return 0;
} }
Mutex::Mutex() : Mutex::Mutex()
m_locked(false) #ifndef NO_THREAD_CHECKS
:
m_lockedBy(-1)
#endif
{ {
m_mutex = CreateMutex(NULL, FALSE, NULL); m_mutex = CreateMutex(NULL, FALSE, NULL);
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
@@ -127,50 +127,71 @@ Mutex::~Mutex()
void void
Mutex::lock() Mutex::lock()
{ {
if (m_locked) { #ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
if (m_lockedBy == tid) {
cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
} }
#endif
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Want to lock mutex " << &m_mutex << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
#endif #endif
WaitForSingleObject(m_mutex, INFINITE); WaitForSingleObject(m_mutex, INFINITE);
m_locked = true; #ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
#endif
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Locked mutex " << &m_mutex << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
#endif #endif
} }
void void
Mutex::unlock() Mutex::unlock()
{ {
#ifdef DEBUG_MUTEX #ifndef NO_THREAD_CHECKS
cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Unlocking mutex " << &m_mutex << endl; DWORD tid = GetCurrentThreadId();
if (m_lockedBy != tid) {
cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
return;
}
#endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
#endif
#ifndef NO_THREAD_CHECKS
m_lockedBy = -1;
#endif #endif
m_locked = false;
ReleaseMutex(m_mutex); ReleaseMutex(m_mutex);
} }
bool bool
Mutex::trylock() Mutex::trylock()
{ {
#ifndef NO_THREAD_CHECKS
DWORD tid = GetCurrentThreadId();
#endif
DWORD result = WaitForSingleObject(m_mutex, 0); DWORD result = WaitForSingleObject(m_mutex, 0);
if (result == WAIT_TIMEOUT || result == WAIT_FAILED) { if (result == WAIT_TIMEOUT || result == WAIT_FAILED) {
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Mutex " << &m_mutex << " unavailable" << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
#endif #endif
return false; return false;
} else { } else {
m_locked = true; #ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
#endif
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)GetCurrentThreadId() << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
#endif #endif
return true; return true;
} }
} }
Condition::Condition(string name) : Condition::Condition(string name) :
m_name(name),
m_locked(false) m_locked(false)
#ifdef DEBUG_CONDITION
, m_name(name)
#endif
{ {
m_mutex = CreateMutex(NULL, FALSE, NULL); m_mutex = CreateMutex(NULL, FALSE, NULL);
m_condition = CreateEvent(NULL, FALSE, FALSE, NULL); m_condition = CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -343,8 +364,12 @@ Thread::staticRun(void *arg)
return 0; return 0;
} }
Mutex::Mutex() : Mutex::Mutex()
#ifndef NO_THREAD_CHECKS
:
m_lockedBy(0),
m_locked(false) m_locked(false)
#endif
{ {
pthread_mutex_init(&m_mutex, 0); pthread_mutex_init(&m_mutex, 0);
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
@@ -363,49 +388,75 @@ Mutex::~Mutex()
void void
Mutex::lock() Mutex::lock()
{ {
if (m_locked) { #ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
if (m_locked && m_lockedBy == tid) {
cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl; cerr << "ERROR: Deadlock on mutex " << &m_mutex << endl;
} }
#endif
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Want to lock mutex " << &m_mutex << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Want to lock mutex " << &m_mutex << endl;
#endif #endif
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
m_locked = true; m_locked = true;
#endif
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Locked mutex " << &m_mutex << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << endl;
#endif #endif
} }
void void
Mutex::unlock() Mutex::unlock()
{ {
#ifdef DEBUG_MUTEX #ifndef NO_THREAD_CHECKS
cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Unlocking mutex " << &m_mutex << endl; pthread_t tid = pthread_self();
if (!m_locked) {
cerr << "ERROR: Mutex " << &m_mutex << " not locked in unlock" << endl;
return;
} else if (m_lockedBy != tid) {
cerr << "ERROR: Mutex " << &m_mutex << " not owned by unlocking thread" << endl;
return;
}
#endif #endif
#ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)tid << ": Unlocking mutex " << &m_mutex << endl;
#endif
#ifndef NO_THREAD_CHECKS
m_locked = false; m_locked = false;
#endif
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
} }
bool bool
Mutex::trylock() Mutex::trylock()
{ {
#ifndef NO_THREAD_CHECKS
pthread_t tid = pthread_self();
#endif
if (pthread_mutex_trylock(&m_mutex)) { if (pthread_mutex_trylock(&m_mutex)) {
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Mutex " << &m_mutex << " unavailable" << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Mutex " << &m_mutex << " unavailable" << endl;
#endif #endif
return false; return false;
} else { } else {
#ifndef NO_THREAD_CHECKS
m_lockedBy = tid;
m_locked = true; m_locked = true;
#endif
#ifdef DEBUG_MUTEX #ifdef DEBUG_MUTEX
cerr << "MUTEX DEBUG: " << (void *)pthread_self() << ": Locked mutex " << &m_mutex << " (from trylock)" << endl; cerr << "MUTEX DEBUG: " << (void *)tid << ": Locked mutex " << &m_mutex << " (from trylock)" << endl;
#endif #endif
return true; return true;
} }
} }
Condition::Condition(string name) : Condition::Condition(string name) :
m_locked(false), m_locked(false)
m_name(name) #ifdef DEBUG_CONDITION
, m_name(name)
#endif
{ {
pthread_mutex_init(&m_mutex, 0); pthread_mutex_init(&m_mutex, 0);
pthread_cond_init(&m_condition, 0); pthread_cond_init(&m_condition, 0);

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -23,6 +23,10 @@
#include <string> #include <string>
//#define DEBUG_THREAD 1
//#define DEBUG_MUTEX 1
//#define DEBUG_CONDITION 1
namespace RubberBand namespace RubberBand
{ {
@@ -73,11 +77,16 @@ public:
private: private:
#ifdef _WIN32 #ifdef _WIN32
HANDLE m_mutex; HANDLE m_mutex;
bool m_locked; #ifndef NO_THREAD_CHECKS
DWORD m_lockedBy;
#endif
#else #else
pthread_mutex_t m_mutex; pthread_mutex_t m_mutex;
#ifndef NO_THREAD_CHECKS
pthread_t m_lockedBy;
bool m_locked; bool m_locked;
#endif #endif
#endif
}; };
class MutexLocker class MutexLocker
@@ -113,15 +122,17 @@ public:
void signal(); void signal();
private: private:
#ifdef _WIN32 #ifdef _WIN32
HANDLE m_mutex; HANDLE m_mutex;
bool m_locked;
HANDLE m_condition; HANDLE m_condition;
std::string m_name; bool m_locked;
#else #else
pthread_mutex_t m_mutex; pthread_mutex_t m_mutex;
bool m_locked;
pthread_cond_t m_condition; pthread_cond_t m_condition;
bool m_locked;
#endif
#ifdef DEBUG_CONDITION
std::string m_name; std::string m_name;
#endif #endif
}; };

17
src/Window.cpp Normal file
View File

@@ -0,0 +1,17 @@
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
/*
Rubber Band
An audio time-stretching and pitch-shifting library.
Copyright 2007-2008 Chris Cannam.
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.
*/
#include "Window.h"

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -17,8 +17,11 @@
#include <cmath> #include <cmath>
#include <iostream> #include <iostream>
#include <cstdlib>
#include <map> #include <map>
#include "sysutils.h"
namespace RubberBand { namespace RubberBand {
enum WindowType { enum WindowType {
@@ -40,7 +43,7 @@ public:
/** /**
* Construct a windower of the given type. * Construct a windower of the given type.
*/ */
Window(WindowType type, size_t size) : m_type(type), m_size(size) { encache(); } Window(WindowType type, int size) : m_type(type), m_size(size) { encache(); }
Window(const Window &w) : m_type(w.m_type), m_size(w.m_size) { encache(); } Window(const Window &w) : m_type(w.m_type), m_size(w.m_size) { encache(); }
Window &operator=(const Window &w) { Window &operator=(const Window &w) {
if (&w == this) return *this; if (&w == this) return *this;
@@ -51,21 +54,34 @@ public:
} }
virtual ~Window() { delete[] m_cache; } virtual ~Window() { delete[] m_cache; }
void cut(T *src) const { cut(src, src); } void cut(T *R__ src) const
void cut(T *src, T *dst) const { {
for (size_t i = 0; i < m_size; ++i) dst[i] = src[i] * m_cache[i]; const int sz = m_size;
for (int i = 0; i < sz; ++i) {
src[i] *= m_cache[i];
}
}
void cut(T *R__ src, T *dst) const {
const int sz = m_size;
for (int i = 0; i < sz; ++i) {
dst[i] = src[i];
}
for (int i = 0; i < sz; ++i) {
dst[i] *= m_cache[i];
}
} }
T getArea() { return m_area; } T getArea() { return m_area; }
T getValue(size_t i) { return m_cache[i]; } T getValue(int i) { return m_cache[i]; }
WindowType getType() const { return m_type; } WindowType getType() const { return m_type; }
size_t getSize() const { return m_size; } int getSize() const { return m_size; }
protected: protected:
WindowType m_type; WindowType m_type;
size_t m_size; int m_size;
T *m_cache; T *R__ m_cache;
T m_area; T m_area;
void encache(); void encache();

View File

@@ -0,0 +1,73 @@
/*
** 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.
*/
/* Version 1.1 */
/*============================================================================
** On Intel Pentium processors (especially PIII and probably P4), converting
** from float to int is very slow. To meet the C specs, the code produced by
** most C compilers targeting Pentium needs to change the FPU rounding mode
** before the float to int conversion is performed.
**
** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
** is this flushing of the pipeline which is so slow.
**
** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
** llrint and llrintf which fix this problem as a side effect.
**
** On Unix-like systems, the configure process should have detected the
** presence of these functions. If they weren't found we have to replace them
** here with a standard C cast.
*/
/*
** The C99 prototypes for lrint and lrintf are as follows:
**
** long int lrintf (float x) ;
** long int lrint (double x) ;
*/
#if (defined (WIN32) || defined (_WIN32))
#include <math.h>
/* Win32 doesn't seem to have these functions.
** Therefore implement inline versions of these functions here.
*/
__inline long int
lrint (double flt)
{ int intgr;
_asm
{ fld flt
fistp intgr
} ;
return intgr ;
}
__inline long int
lrintf (float flt)
{ int intgr;
_asm
{ fld flt
fistp intgr
} ;
return intgr ;
}
#endif

122
src/bsd-3rdparty/getopt/getopt.c vendored Normal file
View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 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 University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University 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 REGENTS 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 REGENTS 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.
*/
/*#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
#endif /* LIBC_SCCS and not lint
#include <sys/cdefs.h>
//__FBSDID("$FreeBSD: src/lib/libc/stdlib/getopt.c,v 1.6 2002/03/29 22:43:42 markm Exp $");
#include "namespace.h"*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*#include "un-namespace.h"*/
/*#include "libc_private.h"*/
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(nargc, nargv, ostr)
int nargc;
char * const *nargv;
const char *ostr;
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':' && optopt != BADCH)
(void)fprintf(stderr, "%s: illegal option -- %c\n",
"progname", optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
"progname", optopt);
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}

110
src/bsd-3rdparty/getopt/getopt.h vendored Normal file
View File

@@ -0,0 +1,110 @@
/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */
/* $FreeBSD: src/include/getopt.h,v 1.1 2002/09/29 04:14:30 eric Exp $ */
/*-
* 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.
*/
#ifndef _GETOPT_H_
#define _GETOPT_H_
#ifdef _WIN32
/* from <sys/cdefs.h> */
# ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
# else
# define __BEGIN_DECLS
# define __END_DECLS
# endif
# define __P(args) args
#endif
/*#ifndef _WIN32
#include <sys/cdefs.h>
#include <unistd.h>
#endif*/
#ifdef _WIN32
# if !defined(GETOPT_API)
# define GETOPT_API __declspec(dllimport)
# endif
#endif
/*
* Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
*/
#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
#define no_argument 0
#define required_argument 1
#define optional_argument 2
struct option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
};
__BEGIN_DECLS
GETOPT_API int getopt_long __P((int, char * const *, const char *,
const struct option *, int *));
__END_DECLS
#endif
#ifdef _WIN32
/* These are global getopt variables */
__BEGIN_DECLS
GETOPT_API extern int opterr, /* if error message should be printed */
optind, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
GETOPT_API extern char* optarg; /* argument associated with option */
/* Original getopt */
GETOPT_API int getopt __P((int, char * const *, const char *));
__END_DECLS
#endif
#endif /* !_GETOPT_H_ */

547
src/bsd-3rdparty/getopt/getopt_long.c vendored Normal file
View File

@@ -0,0 +1,547 @@
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/* $FreeBSD: src/lib/libc/stdlib/getopt_long.c,v 1.2 2002/10/16 22:18:42 alfred Exp $ */
/*-
* 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.
*/
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
/* Windows needs warnx(). We change the definition though:
* 1. (another) global is defined, opterrmsg, which holds the error message
* 2. errors are always printed out on stderr w/o the program name
* Note that opterrmsg always gets set no matter what opterr is set to. The
* error message will not be printed if opterr is 0 as usual.
*/
#include "getopt.h"
#include <stdio.h>
#include <stdarg.h>
GETOPT_API extern char opterrmsg[128];
char opterrmsg[128]; /* last error message is stored here */
static void warnx(int print_error, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
if (fmt != NULL)
_vsnprintf(opterrmsg, 128, fmt, ap);
else
opterrmsg[0]='\0';
va_end(ap);
if (print_error) {
fprintf(stderr, opterrmsg);
fprintf(stderr, "\n");
}
}
#endif /*_WIN32*/
/* not part of the original file */
#ifndef _DIAGASSERT
#define _DIAGASSERT(X)
#endif
#if HAVE_CONFIG_H && !HAVE_GETOPT_LONG && !HAVE_DECL_OPTIND
#define REPLACE_GETOPT
#endif
#ifdef REPLACE_GETOPT
#ifdef __weak_alias
__weak_alias(getopt,_getopt)
#endif
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#elif HAVE_CONFIG_H && !HAVE_DECL_OPTRESET
static int optreset;
#endif
#ifdef __weak_alias
__weak_alias(getopt_long,_getopt_long)
#endif
#if !HAVE_GETOPT_LONG
#define IGNORE_FIRST (*options == '-' || *options == '+')
#define PRINT_ERROR ((opterr) && ((*options != ':') \
|| (IGNORE_FIRST && options[1] != ':')))
#define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL)
#define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST)
/* XXX: GNU ignores PC if *options == '-' */
#define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-')
/* return values */
#define BADCH (int)'?'
#define BADARG ((IGNORE_FIRST && options[1] == ':') \
|| (*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
static int getopt_internal(int, char * const *, const char *);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(a, b)
int a;
int b;
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return b;
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(panonopt_start, panonopt_end, opt_end, nargv)
int panonopt_start;
int panonopt_end;
int opt_end;
char * const *nargv;
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
_DIAGASSERT(nargv != NULL);
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
* Returns -2 if -- is found (can be long option or end of options marker).
*/
static int
getopt_internal(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
char *oli; /* option letter list index */
int optchar;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
optarg = NULL;
/*
* XXX Some programs (like rsyncd) expect to be able to
* XXX re-initialize optind to 0 and have getopt_long(3)
* XXX properly function again. Work around this braindamage.
*/
if (optind == 0)
optind = 1;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((*(place = nargv[optind]) != '-')
|| (place[1] == '\0')) { /* found non-option */
place = EMSG;
if (IN_ORDER) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return INORDER;
}
if (!PERMUTE) {
/*
* if no permutation wanted, stop parsing
* at first non-option
*/
return -1;
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
if (place[1] && *++place == '-') { /* found "--" */
place++;
return -2;
}
}
if ((optchar = (int)*place++) == (int)':' ||
(oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) {
/* option letter unknown or ':' */
if (!*place)
++optind;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(illoptchar, optchar);
#else
warnx(PRINT_ERROR, illoptchar, optchar);
#endif
optopt = optchar;
return BADCH;
}
if (optchar == 'W' && oli[1] == ';') { /* -W long-option */
/* XXX: what if no long options provided (called by getopt)? */
if (*place)
return -2;
if (++optind >= nargc) { /* no arg */
place = EMSG;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargchar, optchar);
#else
warnx(PRINT_ERROR, recargchar, optchar);
#endif
optopt = optchar;
return BADARG;
} else /* white space */
place = nargv[optind];
/*
* Handle -W arg the same as --arg (which causes getopt to
* stop parsing).
*/
return -2;
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
/* XXX: disable test for :: if PC? (GNU doesn't) */
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargchar, optchar);
#else
warnx(PRINT_ERROR, recargchar, optchar);
#endif
optopt = optchar;
return BADARG;
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return optchar;
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the real getopt]
*/
int
getopt(nargc, nargv, options)
int nargc;
char * const *nargv;
const char *options;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
++optind;
/*
* We found an option (--), so if we skipped non-options,
* we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind,
nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
retval = -1;
}
return retval;
}
#endif
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(nargc, nargv, options, long_options, idx)
int nargc;
char * const *nargv;
const char *options;
const struct option *long_options;
int *idx;
{
int retval;
_DIAGASSERT(nargv != NULL);
_DIAGASSERT(options != NULL);
_DIAGASSERT(long_options != NULL);
/* idx may be NULL */
if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = place;
match = -1;
optind++;
place = EMSG;
if (*current_argv == '\0') { /* found "--" */
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return -1;
}
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) ==
(unsigned)current_argv_len) {
/* exact match */
match = i;
break;
}
if (match == -1) /* partial match */
match = i;
else {
/* ambiguous abbreviation */
#ifndef _WIN32
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
#else
warnx(PRINT_ERROR, ambig, (int)current_argv_len,
current_argv);
#endif
optopt = 0;
return BADCH;
}
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
#ifndef _WIN32
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
#else
warnx(PRINT_ERROR, noarg, (int)current_argv_len,
current_argv);
#endif
/*
* XXX: GNU sets optopt to val regardless of
* flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return BADARG;
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use
* next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':'
* indicates no error should be generated
*/
#ifndef _WIN32
if (PRINT_ERROR)
warnx(recargstring, current_argv);
#else
warnx(PRINT_ERROR, recargstring, current_argv);
#endif
/*
* XXX: GNU sets optopt to val regardless
* of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return BADARG;
}
} else { /* unknown option */
#ifndef _WIN32
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
#else
warnx(PRINT_ERROR, illoptstring, current_argv);
#endif
optopt = 0;
return BADCH;
}
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
retval = 0;
} else
retval = long_options[match].val;
if (idx)
*idx = match;
}
return retval;
}
#endif /* !GETOPT_LONG */

0
src/bsd-3rdparty/getopt/unistd.h vendored Normal file
View File

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -55,6 +55,7 @@ RubberBandPitchShifter::portsMono[PortCountMono] =
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_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO
}; };
@@ -67,6 +68,7 @@ RubberBandPitchShifter::portsStereo[PortCountStereo] =
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_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_CONTROL,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO, LADSPA_PORT_OUTPUT | LADSPA_PORT_AUDIO,
LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO, LADSPA_PORT_INPUT | LADSPA_PORT_AUDIO,
@@ -96,6 +98,11 @@ RubberBandPitchShifter::hintsMono[PortCountMono] =
LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER, LADSPA_HINT_INTEGER,
0.0, 3.0 }, 0.0, 3.0 },
{ LADSPA_HINT_DEFAULT_0 |
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 } { 0, 0, 0 }
}; };
@@ -123,6 +130,11 @@ RubberBandPitchShifter::hintsStereo[PortCountStereo] =
LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_INTEGER, LADSPA_HINT_INTEGER,
0.0, 3.0 }, 0.0, 3.0 },
{ LADSPA_HINT_DEFAULT_0 |
LADSPA_HINT_BOUNDED_BELOW |
LADSPA_HINT_BOUNDED_ABOVE |
LADSPA_HINT_TOGGLED,
0.0, 1.0 },
{ 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 },
@@ -247,7 +259,7 @@ RubberBandPitchShifter::connectPort(LADSPA_Handle handle,
&shifter->m_semitones, &shifter->m_semitones,
&shifter->m_octaves, &shifter->m_octaves,
&shifter->m_crispness, &shifter->m_crispness,
&shifter->m_input[0], &shifter->m_input[0],
&shifter->m_output[0], &shifter->m_output[0],
&shifter->m_input[1], &shifter->m_input[1],
&shifter->m_output[1] &shifter->m_output[1]
@@ -326,7 +338,7 @@ RubberBandPitchShifter::runImpl(unsigned long insamples)
} }
if (m_latency) { if (m_latency) {
*m_latency = m_stretcher->getLatency() + m_extraLatency; *m_latency = float(m_stretcher->getLatency() + m_extraLatency);
// std::cerr << "latency = " << *m_latency << std::endl; // std::cerr << "latency = " << *m_latency << std::endl;
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -15,7 +15,7 @@
#ifndef _RUBBERBAND_PITCH_SHIFTER_H_ #ifndef _RUBBERBAND_PITCH_SHIFTER_H_
#define _RUBBERBAND_PITCH_SHIFTER_H_ #define _RUBBERBAND_PITCH_SHIFTER_H_
#include "ladspa.h" #include <ladspa.h>
#include "RingBuffer.h" #include "RingBuffer.h"
@@ -38,11 +38,11 @@ protected:
SemitonesPort = 2, SemitonesPort = 2,
CentsPort = 3, CentsPort = 3,
CrispnessPort = 4, CrispnessPort = 4,
InputPort1 = 5, InputPort1 = 6,
OutputPort1 = 6, OutputPort1 = 7,
PortCountMono = OutputPort1 + 1, PortCountMono = OutputPort1 + 1,
InputPort2 = 7, InputPort2 = 8,
OutputPort2 = 8, OutputPort2 = 9,
PortCountStereo = OutputPort2 + 1 PortCountStereo = OutputPort2 + 1
}; };

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -17,14 +17,19 @@
#include <iostream> #include <iostream>
#include <sndfile.h> #include <sndfile.h>
#include <cmath> #include <cmath>
#include <sys/time.h>
#include <time.h> #include <time.h>
#include <cstdlib>
#include <cstring>
#include "sysutils.h" #include "sysutils.h"
#ifdef _WIN32
#include "bsd-3rdparty/getopt/getopt.h"
#else
#include <getopt.h> #include <getopt.h>
#include <sys/time.h>
#endif
// for import and export of FFTW wisdom #include "Profiler.h"
#include <fftw3.h>
using namespace std; using namespace std;
using namespace RubberBand; using namespace RubberBand;
@@ -48,7 +53,9 @@ int main(int argc, char **argv)
bool peaklock = true; bool peaklock = true;
bool longwin = false; bool longwin = false;
bool shortwin = false; bool shortwin = false;
bool hqpitch = false;
bool softening = true; bool softening = true;
bool formant = false;
int crispness = -1; int crispness = -1;
bool help = false; bool help = false;
bool quiet = false; bool quiet = false;
@@ -79,6 +86,7 @@ int main(int argc, char **argv)
{ "debug", 1, 0, 'd' }, { "debug", 1, 0, 'd' },
{ "realtime", 0, 0, 'R' }, { "realtime", 0, 0, 'R' },
{ "precise", 0, 0, 'P' }, { "precise", 0, 0, 'P' },
{ "formant", 0, 0, 'F' },
{ "no-threads", 0, 0, '0' }, { "no-threads", 0, 0, '0' },
{ "no-transients", 0, 0, '1' }, { "no-transients", 0, 0, '1' },
{ "no-peaklock", 0, 0, '2' }, { "no-peaklock", 0, 0, '2' },
@@ -89,12 +97,13 @@ int main(int argc, char **argv)
{ "thresh2", 1, 0, '7' }, { "thresh2", 1, 0, '7' },
{ "bl-transients", 0, 0, '8' }, { "bl-transients", 0, 0, '8' },
{ "no-softening", 0, 0, '9' }, { "no-softening", 0, 0, '9' },
{ "pitch-hq", 0, 0, '%' },
{ "threads", 0, 0, '@' }, { "threads", 0, 0, '@' },
{ "quiet", 0, 0, 'q' }, { "quiet", 0, 0, 'q' },
{ 0, 0, 0 } { 0, 0, 0 }
}; };
c = getopt_long(argc, argv, "t:p:d:RPc:f:T:qh", longOpts, &optionIndex); c = getopt_long(argc, argv, "t:p:d:RPFc:f:T:qh", longOpts, &optionIndex);
if (c == -1) break; if (c == -1) break;
switch (c) { switch (c) {
@@ -106,6 +115,7 @@ int main(int argc, char **argv)
case 'd': debug = atoi(optarg); break; case 'd': debug = atoi(optarg); break;
case 'R': realtime = true; break; case 'R': realtime = true; break;
case 'P': precise = true; break; case 'P': precise = true; break;
case 'F': formant = true; break;
case '0': threading = 1; break; case '0': threading = 1; break;
case '@': threading = 2; break; case '@': threading = 2; break;
case '1': transients = NoTransients; break; case '1': transients = NoTransients; break;
@@ -117,6 +127,7 @@ int main(int argc, char **argv)
case '7': fthresh2 = atof(optarg); break; case '7': fthresh2 = atof(optarg); break;
case '8': transients = BandLimitedTransients; break; case '8': transients = BandLimitedTransients; break;
case '9': softening = false; break; case '9': softening = false; break;
case '%': hqpitch = true; break;
case 'c': crispness = atoi(optarg); break; case 'c': crispness = atoi(optarg); break;
case 'q': quiet = true; break; case 'q': quiet = true; break;
default: help = true; break; default: help = true; break;
@@ -127,7 +138,7 @@ int main(int argc, char **argv)
cerr << endl; cerr << endl;
cerr << "Rubber Band" << endl; cerr << "Rubber Band" << endl;
cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl; cerr << "An audio time-stretching and pitch-shifting library and utility program." << endl;
cerr << "Copyright 2007 Chris Cannam. Distributed under the GNU General Public License." << endl; cerr << "Copyright 2008 Chris Cannam. Distributed under the GNU General Public License." << endl;
cerr << endl; cerr << endl;
cerr << " Usage: " << argv[0] << " [options] <infile.wav> <outfile.wav>" << endl; cerr << " Usage: " << argv[0] << " [options] <infile.wav> <outfile.wav>" << endl;
cerr << endl; cerr << endl;
@@ -139,15 +150,16 @@ int main(int argc, char **argv)
cerr << " -p<X>, --pitch <X> Raise pitch by X semitones, or" << endl; cerr << " -p<X>, --pitch <X> Raise pitch by X semitones, or" << endl;
cerr << " -f<X>, --frequency <X> Change frequency by multiple X" << endl; cerr << " -f<X>, --frequency <X> Change frequency by multiple X" << endl;
cerr << endl; cerr << endl;
cerr << "The following option provides a simple way to adjust the sound. See below" << endl; cerr << "The following options provide a simple way to adjust the sound. See below" << endl;
cerr << "for more details." << endl; cerr << "for more details." << endl;
cerr << endl; cerr << endl;
cerr << " -c<N>, --crisp <N> Crispness (N = 0,1,2,3,4,5); default 4 (see below)" << endl; cerr << " -c<N>, --crisp <N> Crispness (N = 0,1,2,3,4,5); default 4 (see below)" << endl;
cerr << " -F, --formant Enable formant preservation when pitch shifting" << endl;
cerr << endl; cerr << endl;
cerr << "The remaining options fine-tune the processing mode and stretch algorithm." << endl; 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 << "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 << "crispness parameter are intended to provide the best sounding set of options" << endl;
cerr << "for most situations." << endl; cerr << "for most situations. The default is to use none of these options." << endl;
cerr << endl; cerr << endl;
cerr << " -P, --precise Aim for minimal time distortion (implied by -R)" << endl; cerr << " -P, --precise Aim for minimal time distortion (implied by -R)" << endl;
cerr << " -R, --realtime Select realtime mode (implies -P --no-threads)" << endl; cerr << " -R, --realtime Select realtime mode (implies -P --no-threads)" << endl;
@@ -159,6 +171,7 @@ int main(int argc, char **argv)
cerr << " --no-softening Disable large-ratio softening of phase locking" << endl; cerr << " --no-softening Disable large-ratio softening of phase locking" << endl;
cerr << " --window-long Use longer processing window (actual size may vary)" << endl; cerr << " --window-long Use longer processing window (actual size may vary)" << endl;
cerr << " --window-short Use shorter processing window" << endl; cerr << " --window-short Use shorter processing window" << endl;
cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl;
cerr << " --thresh<N> <F> Set internal freq threshold N (N = 0,1,2) to F Hz" << endl; cerr << " --thresh<N> <F> Set internal freq threshold N (N = 0,1,2) to F Hz" << endl;
cerr << endl; cerr << endl;
cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl; cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl;
@@ -203,7 +216,7 @@ int main(int argc, char **argv)
char *fileName = strdup(argv[optind++]); char *fileName = strdup(argv[optind++]);
char *fileNameOut = strdup(argv[optind++]); char *fileNameOut = strdup(argv[optind++]);
SNDFILE *sndfile; SNDFILE *sndfile;
SNDFILE *sndfileOut; SNDFILE *sndfileOut;
SF_INFO sfinfo; SF_INFO sfinfo;
@@ -226,8 +239,8 @@ int main(int argc, char **argv)
sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut) ; sndfileOut = sf_open(fileNameOut, SFM_WRITE, &sfinfoOut) ;
if (!sndfileOut) { if (!sndfileOut) {
cerr << "ERROR: Failed to open output file \"" << fileName << "\" for writing: " cerr << "ERROR: Failed to open output file \"" << fileNameOut << "\" for writing: "
<< sf_strerror(sndfile) << endl; << sf_strerror(sndfileOut) << endl;
return 1; return 1;
} }
@@ -241,6 +254,8 @@ int main(int argc, char **argv)
if (!softening) options |= RubberBandStretcher::OptionPhasePeakLocked; if (!softening) options |= RubberBandStretcher::OptionPhasePeakLocked;
if (longwin) options |= RubberBandStretcher::OptionWindowLong; if (longwin) options |= RubberBandStretcher::OptionWindowLong;
if (shortwin) options |= RubberBandStretcher::OptionWindowShort; if (shortwin) options |= RubberBandStretcher::OptionWindowShort;
if (formant) options |= RubberBandStretcher::OptionFormantPreserved;
if (hqpitch) options |= RubberBandStretcher::OptionPitchHighQuality;
switch (threading) { switch (threading) {
case 0: case 0:
@@ -474,6 +489,8 @@ int main(int argc, char **argv)
cerr << "elapsed time: " << sec << " sec, in frames/sec: " << countIn/sec << ", out frames/sec: " << countOut/sec << endl; cerr << "elapsed time: " << sec << " sec, in frames/sec: " << countIn/sec << ", out frames/sec: " << countOut/sec << endl;
} }
Profiler::dump();
return 0; return 0;
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -81,7 +81,7 @@ system_is_multiprocessor()
#ifdef _WIN32 #ifdef _WIN32
void gettimeofday(struct timeval *tv, void *tz) int gettimeofday(struct timeval *tv, void *tz)
{ {
union { union {
long long ns100; long long ns100;
@@ -91,6 +91,7 @@ void gettimeofday(struct timeval *tv, void *tz)
::GetSystemTimeAsFileTime(&now.ft); ::GetSystemTimeAsFileTime(&now.ft);
tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); tv->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL);
tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL); tv->tv_sec = (long)((now.ns100 - 116444736000000000LL) / 10000000LL);
return 0;
} }
void usleep(unsigned long usec) void usleep(unsigned long usec)

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -15,14 +15,29 @@
#ifndef _RUBBERBAND_SYSINFO_H_ #ifndef _RUBBERBAND_SYSINFO_H_
#define _RUBBERBAND_SYSINFO_H_ #define _RUBBERBAND_SYSINFO_H_
#ifdef _WIN32
#include "bsd-3rdparty/float_cast/float_cast.h"
#endif
namespace RubberBand { namespace RubberBand {
extern bool system_is_multiprocessor(); extern bool system_is_multiprocessor();
#ifdef _WIN32 #ifdef _WIN32
#define R__ __restrict
struct timeval { long tv_sec; long tv_usec; }; struct timeval { long tv_sec; long tv_usec; };
void gettimeofday(struct timeval *p, void *tz); int gettimeofday(struct timeval *p, void *tz);
void usleep(unsigned long); void usleep(unsigned long);
#define alloca _alloca
#else
#define R__ __restrict__
#endif #endif
} }

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as
@@ -18,6 +18,10 @@
#include <cmath> #include <cmath>
#ifdef _WIN32
#include "bsd-3rdparty/float_cast/float_cast.h"
#endif
using std::string; using std::string;
using std::vector; using std::vector;
using std::cerr; using std::cerr;
@@ -159,7 +163,7 @@ RubberBandVampPlugin::getOutputDescriptors() const
d.isQuantized = true; d.isQuantized = true;
d.quantizeStep = 1.0; d.quantizeStep = 1.0;
d.sampleType = OutputDescriptor::VariableSampleRate; d.sampleType = OutputDescriptor::VariableSampleRate;
d.sampleRate = rate; d.sampleRate = float(rate);
m_d->m_incrementsOutput = list.size(); m_d->m_incrementsOutput = list.size();
list.push_back(d); list.push_back(d);
@@ -182,7 +186,7 @@ RubberBandVampPlugin::getOutputDescriptors() const
d.name = "Phase Reset Detection Function"; d.name = "Phase Reset Detection Function";
d.description = "Curve whose peaks are used to identify transients for phase reset points"; d.description = "Curve whose peaks are used to identify transients for phase reset points";
d.unit = ""; d.unit = "";
d.sampleRate = rate; d.sampleRate = float(rate);
m_d->m_phaseResetDfOutput = list.size(); m_d->m_phaseResetDfOutput = list.size();
list.push_back(d); list.push_back(d);
@@ -326,11 +330,11 @@ RubberBandVampPlugin::getParameter(std::string id) const
{ {
if (id == "timeratio") return m_d->m_timeRatio * 100.f; if (id == "timeratio") return m_d->m_timeRatio * 100.f;
if (id == "pitchratio") return m_d->m_pitchRatio * 100.f; if (id == "pitchratio") return m_d->m_pitchRatio * 100.f;
if (id == "mode") return m_d->m_realtime ? 1 : 0; if (id == "mode") return m_d->m_realtime ? 1.f : 0.f;
if (id == "stretchtype") return m_d->m_elasticTiming ? 0 : 1; if (id == "stretchtype") return m_d->m_elasticTiming ? 0.f : 1.f;
if (id == "transientmode") return m_d->m_transientMode; if (id == "transientmode") return float(m_d->m_transientMode);
if (id == "phasemode") return m_d->m_phaseIndependent ? 1 : 0; if (id == "phasemode") return m_d->m_phaseIndependent ? 1.f : 0.f;
if (id == "windowmode") return m_d->m_windowLength; if (id == "windowmode") return float(m_d->m_windowLength);
return 0.f; return 0.f;
} }
@@ -565,12 +569,12 @@ RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement,
Feature feature; Feature feature;
feature.hasTimestamp = true; feature.hasTimestamp = true;
feature.timestamp = t; feature.timestamp = t;
feature.values.push_back(oi); feature.values.push_back(float(oi));
feature.label = Vamp::RealTime::frame2RealTime(oi, rate).toText(); feature.label = Vamp::RealTime::frame2RealTime(oi, rate).toText();
features[m_incrementsOutput].push_back(feature); features[m_incrementsOutput].push_back(feature);
feature.values.clear(); feature.values.clear();
feature.values.push_back(actual); feature.values.push_back(float(actual));
feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText(); feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText();
features[m_aggregateIncrementsOutput].push_back(feature); features[m_aggregateIncrementsOutput].push_back(feature);
@@ -594,7 +598,7 @@ RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement,
if (i < phaseResetDf.size()) { if (i < phaseResetDf.size()) {
feature.values.clear(); feature.values.clear();
feature.values.push_back(phaseResetDf[i]); feature.values.push_back(phaseResetDf[i]);
sprintf(buf, "%d", baseCount + i); sprintf(buf, "%d", int(baseCount + i));
feature.label = buf; feature.label = buf;
features[m_phaseResetDfOutput].push_back(feature); features[m_phaseResetDfOutput].push_back(feature);
} }
@@ -626,7 +630,7 @@ RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement,
feature.timestamp = t; feature.timestamp = t;
feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText(); feature.label = Vamp::RealTime::frame2RealTime(actual, rate).toText();
feature.values.clear(); feature.values.clear();
feature.values.push_back(actual); feature.values.push_back(float(actual));
features[m_aggregateIncrementsOutput].push_back(feature); features[m_aggregateIncrementsOutput].push_back(feature);
float linear = ((baseCount + outputIncrements.size()) float linear = ((baseCount + outputIncrements.size())

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/* /*
Rubber Band Rubber Band
An audio time-stretching and pitch-shifting library. An audio time-stretching and pitch-shifting library.
Copyright 2007 Chris Cannam. Copyright 2007-2008 Chris Cannam.
This program is free software; you can redistribute it and/or This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as modify it under the terms of the GNU General Public License as