Update from main repo.

* Add a more reliable transient detection mode, and make the mode
   selectable using OptionDetectorXXX flags -- the new method is
   the default
 * Band-limit transient detectors to avoid being distracted by
   inaudible garbage
 * Add a key-frame mapping facility for variable stretch ratio
   management during offline stretches
This commit is contained in:
Chris Cannam
2010-03-24 09:44:51 +00:00
parent 45a7ec1868
commit 87dc720243
53 changed files with 1287 additions and 294 deletions

View File

@@ -1,4 +1,20 @@
Changed in Rubber Band v1.5
* Add a more reliable transient detection mode, and make the mode
selectable using OptionDetectorXXX flags -- the new method is
the default
* Band-limit transient detectors to avoid being distracted by
inaudible garbage
* Add a key-frame mapping facility for variable stretch ratio
management during offline stretches
The library is binary compatible with version 1.4 for forward
compatibility (a function and an enum have been added, but no existing
entry points have changed). Code written to use 1.5 is not
necessarily compatible with 1.4.
Changes in Rubber Band v1.4 Changes in Rubber Band v1.4
* Fix a hang when faced with some very peculiar stretch factors * Fix a hang when faced with some very peculiar stretch factors
@@ -20,7 +36,7 @@ The library is binary compatible with version 1.2.
Changes in Rubber Band v1.2 Changes in Rubber Band v1.2
* Added an initial "formant preservation" option when pitch shifting * Add an initial "formant preservation" option when pitch shifting
* Real-time pitch shifting now uses a faster method by default, with * Real-time pitch shifting now uses a faster method by default, with
less variation in CPU usage less variation in CPU usage
* The code is more amenable to compiler auto-vectorization (through * The code is more amenable to compiler auto-vectorization (through

View File

@@ -56,13 +56,15 @@ LIBRARY_INCLUDES := \
src/base/RingBuffer.h \ src/base/RingBuffer.h \
src/base/Scavenger.h \ src/base/Scavenger.h \
src/dsp/AudioCurveCalculator.h \ src/dsp/AudioCurveCalculator.h \
src/dsp/CompoundAudioCurve.h \
src/dsp/ConstantAudioCurve.h \
src/dsp/HighFrequencyAudioCurve.h \
src/dsp/PercussiveAudioCurve.h \
src/dsp/SilentAudioCurve.h \
src/dsp/SpectralDifferenceAudioCurve.h \ src/dsp/SpectralDifferenceAudioCurve.h \
src/dsp/Resampler.h \ src/dsp/Resampler.h \
src/dsp/HighFrequencyAudioCurve.h \
src/dsp/SilentAudioCurve.h \
src/dsp/FFT.h \ src/dsp/FFT.h \
src/dsp/PercussiveAudioCurve.h \ src/dsp/MovingMedian.h \
src/dsp/ConstantAudioCurve.h \
src/dsp/Window.h \ src/dsp/Window.h \
src/system/Allocators.h \ src/system/Allocators.h \
src/system/Thread.h \ src/system/Thread.h \
@@ -76,6 +78,7 @@ LIBRARY_SOURCES := \
src/StretchCalculator.cpp \ src/StretchCalculator.cpp \
src/base/Profiler.cpp \ src/base/Profiler.cpp \
src/dsp/AudioCurveCalculator.cpp \ src/dsp/AudioCurveCalculator.cpp \
src/dsp/CompoundAudioCurve.cpp \
src/dsp/SpectralDifferenceAudioCurve.cpp \ src/dsp/SpectralDifferenceAudioCurve.cpp \
src/dsp/HighFrequencyAudioCurve.cpp \ src/dsp/HighFrequencyAudioCurve.cpp \
src/dsp/SilentAudioCurve.cpp \ src/dsp/SilentAudioCurve.cpp \

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 2008-2009 Chris Cannam, cannam@all-day-breakfast.com. Copyright 2007-2010 Chris Cannam, cannam@all-day-breakfast.com.
Distributed under the GNU General Public License. Distributed under the GNU General Public License.
@@ -131,7 +131,7 @@ shifts it up in pitch by one octave, and writes the output to output.wav.
Several further options are available: run "rubberband -h" for help. Several further options are available: run "rubberband -h" for help.
In particular, different types of music may benefit from different In particular, different types of music may benefit from different
"crispness" options (-c <n> where <n> is from 0 to 5). "crispness" options (-c <n> where <n> is from 0 to 6).
Using the Rubber Band library Using the Rubber Band library

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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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,9 @@
#include <time.h> #include <time.h>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <string>
#include <fstream>
#include "system/sysutils.h" #include "system/sysutils.h"
@@ -87,12 +90,20 @@ int main(int argc, char **argv)
bool haveRatio = false; bool haveRatio = false;
std::string mapfile;
enum { enum {
NoTransients, NoTransients,
BandLimitedTransients, BandLimitedTransients,
Transients Transients
} transients = Transients; } transients = Transients;
enum {
CompoundDetector,
PercussiveDetector,
SoftDetector
} detector = CompoundDetector;
while (1) { while (1) {
int optionIndex = 0; int optionIndex = 0;
@@ -116,13 +127,18 @@ int main(int argc, char **argv)
{ "window-long", 0, 0, '3' }, { "window-long", 0, 0, '3' },
{ "window-short", 0, 0, '4' }, { "window-short", 0, 0, '4' },
{ "bl-transients", 0, 0, '8' }, { "bl-transients", 0, 0, '8' },
{ "detector-perc", 0, 0, '5' },
{ "detector-soft", 0, 0, '6' },
{ "pitch-hq", 0, 0, '%' }, { "pitch-hq", 0, 0, '%' },
{ "threads", 0, 0, '@' }, { "threads", 0, 0, '@' },
{ "quiet", 0, 0, 'q' }, { "quiet", 0, 0, 'q' },
{ "timemap", 1, 0, 'M' },
{ 0, 0, 0, 0 } { 0, 0, 0, 0 }
}; };
c = getopt_long(argc, argv, "t:p:d:RPFc:f:T:D:qhV", longOpts, &optionIndex); c = getopt_long(argc, argv,
"t:p:d:RPFc:f:T:D:qhVM:",
longOpts, &optionIndex);
if (c == -1) break; if (c == -1) break;
switch (c) { switch (c) {
@@ -143,10 +159,13 @@ int main(int argc, char **argv)
case '2': lamination = false; crispchanged = true; break; case '2': lamination = false; crispchanged = true; break;
case '3': longwin = true; crispchanged = true; break; case '3': longwin = true; crispchanged = true; break;
case '4': shortwin = true; crispchanged = true; break; case '4': shortwin = true; crispchanged = true; break;
case '5': detector = PercussiveDetector; crispchanged = true; break;
case '6': detector = SoftDetector; crispchanged = true; break;
case '8': transients = BandLimitedTransients; crispchanged = true; break; case '8': transients = BandLimitedTransients; crispchanged = true; break;
case '%': hqpitch = true; 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;
case 'M': mapfile = optarg; break;
default: help = true; break; default: help = true; break;
} }
} }
@@ -160,7 +179,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 2009 Chris Cannam. Distributed under the GNU General Public License." << endl; cerr << "Copyright 2010 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;
@@ -174,10 +193,17 @@ 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 << " -M<F>, --timemap <F> Use file F as the source for key frame map" << endl;
cerr << endl;
cerr << "A map file consists of a series of lines each having two numbers separated" << endl;
cerr << "by a single space. These are source and target sample frame numbers for fixed" << endl;
cerr << "time points within the audio data, defining a varying stretch factor through" << endl;
cerr << "the audio. You must specify an overall stretch factor using e.g. -t as well." << endl;
cerr << endl;
cerr << "The following options provide 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,6); default 5 (see below)" << endl;
cerr << " -F, --formant Enable formant preservation when pitch shifting" << 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;
@@ -194,6 +220,8 @@ int main(int argc, char **argv)
cerr << " --no-lamination Disable phase lamination" << endl; cerr << " --no-lamination Disable phase lamination" << 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 << " --detector-perc Use percussive transient detector (as in pre-1.5)" << endl;
cerr << " --detector-soft Use soft transient detector" << endl;
cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl; cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << 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;
@@ -205,11 +233,12 @@ int main(int argc, char **argv)
cerr << endl; cerr << endl;
cerr << "\"Crispness\" levels:" << endl; cerr << "\"Crispness\" levels:" << endl;
cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl; cerr << " -c 0 equivalent to --no-transients --no-lamination --window-long" << endl;
cerr << " -c 1 equivalent to --no-transients --no-lamination" << endl; cerr << " -c 1 equivalent to --detector-soft --no-lamination --window-long (for piano)" << endl;
cerr << " -c 2 equivalent to --no-transients" << endl; cerr << " -c 2 equivalent to --no-transients --no-lamination" << endl;
cerr << " -c 3 equivalent to --bl-transients" << endl; cerr << " -c 3 equivalent to --no-transients" << endl;
cerr << " -c 4 default processing options" << endl; cerr << " -c 4 equivalent to --bl-transients" << endl;
cerr << " -c 5 equivalent to --no-lamination --window-short (may be good for drums)" << endl; cerr << " -c 5 default processing options" << endl;
cerr << " -c 6 equivalent to --no-lamination --window-short (may be good for drums)" << endl;
cerr << endl; cerr << endl;
return 2; return 2;
} }
@@ -220,28 +249,68 @@ int main(int argc, char **argv)
} }
switch (crispness) { switch (crispness) {
case -1: crispness = 4; break; case -1: crispness = 5; break;
case 0: transients = NoTransients; lamination = false; longwin = true; shortwin = false; break; case 0: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
case 1: transients = NoTransients; lamination = false; longwin = false; shortwin = false; break; case 1: detector = SoftDetector; transients = Transients; lamination = false; longwin = true; shortwin = false; break;
case 2: transients = NoTransients; lamination = true; longwin = false; shortwin = false; break; case 2: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = false; shortwin = false; break;
case 3: transients = BandLimitedTransients; lamination = true; longwin = false; shortwin = false; break; case 3: detector = CompoundDetector; transients = NoTransients; lamination = true; longwin = false; shortwin = false; break;
case 4: transients = Transients; lamination = true; longwin = false; shortwin = false; break; case 4: detector = CompoundDetector; transients = BandLimitedTransients; lamination = true; longwin = false; shortwin = false; break;
case 5: transients = Transients; lamination = false; longwin = false; shortwin = true; break; case 5: detector = CompoundDetector; transients = Transients; lamination = true; longwin = false; shortwin = false; break;
case 6: detector = CompoundDetector; transients = Transients; lamination = false; longwin = false; shortwin = true; break;
}; };
if (!quiet) { if (!quiet) {
cerr << "Using crispness level: " << crispness << " ("; cerr << "Using crispness level: " << crispness << " (";
switch (crispness) { switch (crispness) {
case 0: cerr << "Mushy"; break; case 0: cerr << "Mushy"; break;
case 1: cerr << "Smooth"; break; case 1: cerr << "Piano"; break;
case 2: cerr << "Balanced multitimbral mixture"; break; case 2: cerr << "Smooth"; break;
case 3: cerr << "Unpitched percussion with stable notes"; break; case 3: cerr << "Balanced multitimbral mixture"; break;
case 4: cerr << "Crisp monophonic instrumental"; break; case 4: cerr << "Unpitched percussion with stable notes"; break;
case 5: cerr << "Unpitched solo percussion"; break; case 5: cerr << "Crisp monophonic instrumental"; break;
case 6: cerr << "Unpitched solo percussion"; break;
} }
cerr << ")" << endl; cerr << ")" << endl;
} }
std::map<size_t, size_t> mapping;
if (mapfile != "") {
std::ifstream ifile(mapfile.c_str());
if (!ifile.is_open()) {
cerr << "ERROR: Failed to open time map file \"" << mapfile << "\""
<< endl;
return 1;
}
std::string line;
int lineno = 0;
while (!ifile.eof()) {
std::getline(ifile, line);
while (line.length() > 0 && line[0] == ' ') line = line.substr(1);
if (line == "") {
++lineno;
continue;
}
std::string::size_type i = line.find_first_of(" ");
if (i == std::string::npos) {
cerr << "ERROR: Time map file \"" << mapfile
<< "\" is malformed at line " << lineno << endl;
return 1;
}
size_t source = atoi(line.substr(0, i).c_str());
while (i < line.length() && line[i] == ' ') ++i;
size_t target = atoi(line.substr(i).c_str());
mapping[source] = target;
cerr << "adding mapping from " << source << " to " << target << endl;
++lineno;
}
ifile.close();
if (!quiet) {
cerr << "Read " << mapping.size() << " line(s) from map file" << endl;
}
}
char *fileName = strdup(argv[optind++]); char *fileName = strdup(argv[optind++]);
char *fileNameOut = strdup(argv[optind++]); char *fileNameOut = strdup(argv[optind++]);
@@ -317,6 +386,18 @@ int main(int argc, char **argv)
break; break;
} }
switch (detector) {
case CompoundDetector:
options |= RubberBandStretcher::OptionDetectorCompound;
break;
case PercussiveDetector:
options |= RubberBandStretcher::OptionDetectorPercussive;
break;
case SoftDetector:
options |= RubberBandStretcher::OptionDetectorSoft;
break;
}
if (pitchshift != 0.0) { if (pitchshift != 0.0) {
frequencyshift *= pow(2.0, pitchshift / 12); frequencyshift *= pow(2.0, pitchshift / 12);
} }
@@ -389,6 +470,10 @@ int main(int argc, char **argv)
frame = 0; frame = 0;
percent = 0; percent = 0;
if (!mapping.empty()) {
ts.setKeyFrameMap(mapping);
}
size_t countIn = 0, countOut = 0; size_t countIn = 0, countOut = 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-2009 Chris Cannam. Copyright 2007-2010 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,11 +15,12 @@
#ifndef _RUBBERBANDSTRETCHER_H_ #ifndef _RUBBERBANDSTRETCHER_H_
#define _RUBBERBANDSTRETCHER_H_ #define _RUBBERBANDSTRETCHER_H_
#define RUBBERBAND_VERSION "1.4.0-gpl" #define RUBBERBAND_VERSION "1.5.0-gpl"
#define RUBBERBAND_API_MAJOR_VERSION 2 #define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 1 #define RUBBERBAND_API_MINOR_VERSION 3
#include <vector> #include <vector>
#include <map>
/** /**
* @mainpage RubberBand * @mainpage RubberBand
@@ -123,7 +124,25 @@ public:
* but may be less clear than with either of the other * but may be less clear than with either of the other
* transients flags. * transients flags.
* *
* 4. Flags prefixed \c OptionPhase control the adjustment of * 4. Flags prefixed \c OptionDetector control the type of
* transient detector used. These options may be changed
* after construction when running in real-time mode, but not when
* running in offline mode.
*
* \li \c OptionDetectorCompound - Use a general-purpose
* transient detector which is likely to be good for most
* situations.
*
* \li \c OptionDetectorPercussive - Detect percussive
* transients. Note that this was the default and only option
* in Rubber Band versions prior to 1.5.
*
* \li \c OptionDetectorSoft - Use an onset detector with less
* of a bias toward percussive transients. This may give better
* results with certain material (e.g. relatively monophonic
* piano music).
*
* 5. Flags prefixed \c OptionPhase control the adjustment of
* component frequency phases from one analysis window to the next * component frequency phases from one analysis window to the next
* during non-transient segments. These options may be changed at * during non-transient segments. These options may be changed at
* any time. * any time.
@@ -138,7 +157,7 @@ public:
* frequency bin independently from its neighbours. This * frequency bin independently from its neighbours. This
* usually results in a slightly softer, phasier sound. * usually results in a slightly softer, phasier sound.
* *
* 5. Flags prefixed \c OptionThreading control the threading * 6. Flags prefixed \c OptionThreading control the threading
* model of the stretcher. These options may not be changed after * model of the stretcher. These options may not be changed after
* construction. * construction.
* *
@@ -154,7 +173,7 @@ public:
* situation where \c OptionThreadingAuto would do so, except omit * situation where \c OptionThreadingAuto would do so, except omit
* the check for multiple CPUs and instead assume it to be true. * the check for multiple CPUs and instead assume it to be true.
* *
* 6. Flags prefixed \c OptionWindow control the window size for * 7. Flags prefixed \c OptionWindow control the window size for
* FFT processing. The window size actually used will depend on * FFT processing. The window size actually used will depend on
* many factors, but it can be influenced. These options may not * many factors, but it can be influenced. These options may not
* be changed after construction. * be changed after construction.
@@ -172,7 +191,7 @@ public:
* 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 * 8. Flags prefixed \c OptionFormant control the handling of
* formant shape (spectral envelope) when pitch-shifting. These * formant shape (spectral envelope) when pitch-shifting. These
* options may be changed at any time. * options may be changed at any time.
* *
@@ -185,7 +204,7 @@ public:
* note frequency without so substantially affecting the * note frequency without so substantially affecting the
* perceived pitch profile of the voice or instrument. * perceived pitch profile of the voice or instrument.
* *
* 8. Flags prefixed \c OptionPitch control the method used for * 9. Flags prefixed \c OptionPitch control the method used for
* pitch shifting. These options may be changed at any time. * pitch shifting. These options may be changed at any time.
* They are only effective in realtime mode; in offline mode, the * They are only effective in realtime mode; in offline mode, the
* pitch-shift method is fixed. * pitch-shift method is fixed.
@@ -219,6 +238,10 @@ public:
OptionTransientsMixed = 0x00000100, OptionTransientsMixed = 0x00000100,
OptionTransientsSmooth = 0x00000200, OptionTransientsSmooth = 0x00000200,
OptionDetectorCompound = 0x00000000,
OptionDetectorPercussive = 0x00000400,
OptionDetectorSoft = 0x00000800,
OptionPhaseLaminar = 0x00000000, OptionPhaseLaminar = 0x00000000,
OptionPhaseIndependent = 0x00002000, OptionPhaseIndependent = 0x00002000,
@@ -348,6 +371,14 @@ public:
*/ */
void setTransientsOption(Options options); void setTransientsOption(Options options);
/**
* Change an OptionDetector configuration setting. This may be
* called at any time in RealTime mode. It may not be called in
* Offline mode (for which the detector option is fixed on
* construction).
*/
void setDetectorOption(Options options);
/** /**
* Change an OptionPhase configuration setting. This may be * Change an OptionPhase configuration setting. This may be
* called at any time in any mode. * called at any time in any mode.
@@ -416,6 +447,32 @@ public:
*/ */
void setMaxProcessSize(size_t samples); void setMaxProcessSize(size_t samples);
/**
* Provide a set of mappings from "before" to "after" sample
* numbers so as to enforce a particular stretch profile. The
* argument is a map from audio sample frame number in the source
* material, to the corresponding sample frame number in the
* stretched output. The mapping should be for key frames only,
* with a "reasonable" gap between mapped samples.
*
* This function cannot be used in RealTime mode.
*
* This function may not be called after the first call to
* process(). It should be called after the time and pitch ratios
* have been set; the results of changing the time and pitch
* ratios after calling this function are undefined. Calling
* reset() will clear this mapping.
*
* The key frame map only affects points within the material; it
* does not determine the overall stretch ratio (that is, the
* ratio between the output material's duration and the source
* material's duration). You need to provide this ratio
* separately to setTimeRatio(), otherwise the results may be
* truncated or extended in unexpected ways regardless of the
* extent of the frame numbers found in the key frame map.
*/
void setKeyFrameMap(const std::map<size_t, size_t> &);
/** /**
* Provide a block of "samples" sample frames for the stretcher to * Provide a block of "samples" sample frames for the stretcher to
* study and calculate a stretch profile from. * study and calculate a stretch profile from.

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-2009 Chris Cannam. Copyright 2007-2010 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,9 +19,9 @@
extern "C" { extern "C" {
#endif #endif
#define RUBBERBAND_VERSION "1.4.0-gpl" #define RUBBERBAND_VERSION "1.5.0-gpl"
#define RUBBERBAND_API_MAJOR_VERSION 2 #define RUBBERBAND_API_MAJOR_VERSION 2
#define RUBBERBAND_API_MINOR_VERSION 1 #define RUBBERBAND_API_MINOR_VERSION 3
/** /**
* This is a C-linkage interface to the Rubber Band time stretcher. * This is a C-linkage interface to the Rubber Band time stretcher.
@@ -48,6 +48,10 @@ enum RubberBandOption {
RubberBandOptionTransientsMixed = 0x00000100, RubberBandOptionTransientsMixed = 0x00000100,
RubberBandOptionTransientsSmooth = 0x00000200, RubberBandOptionTransientsSmooth = 0x00000200,
RubberBandOptionDetectorCompound = 0x00000000,
RubberBandOptionDetectorPercussive = 0x00000400,
RubberBandOptionDetectorSoft = 0x00000800,
RubberBandOptionPhaseLaminar = 0x00000000, RubberBandOptionPhaseLaminar = 0x00000000,
RubberBandOptionPhaseIndependent = 0x00002000, RubberBandOptionPhaseIndependent = 0x00002000,
@@ -91,6 +95,7 @@ extern double rubberband_get_pitch_scale(const RubberBandState);
extern unsigned int rubberband_get_latency(const RubberBandState); extern unsigned int rubberband_get_latency(const RubberBandState);
extern void rubberband_set_transients_option(RubberBandState, RubberBandOptions options); extern void rubberband_set_transients_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_detector_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_phase_option(RubberBandState, RubberBandOptions options); extern void rubberband_set_phase_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_formant_option(RubberBandState, RubberBandOptions options); extern void rubberband_set_formant_option(RubberBandState, RubberBandOptions options);
extern void rubberband_set_pitch_option(RubberBandState, RubberBandOptions options); extern void rubberband_set_pitch_option(RubberBandState, RubberBandOptions options);
@@ -100,6 +105,7 @@ extern void rubberband_set_expected_input_duration(RubberBandState, unsigned int
extern unsigned int rubberband_get_samples_required(const RubberBandState); extern unsigned int rubberband_get_samples_required(const RubberBandState);
extern void rubberband_set_max_process_size(RubberBandState, unsigned int samples); extern void rubberband_set_max_process_size(RubberBandState, unsigned int samples);
extern void rubberband_set_key_frame_map(RubberBandState, unsigned int keyframecount, unsigned int *from, unsigned int *to);
extern void rubberband_study(RubberBandState, const float *const *input, unsigned int samples, int final); extern void rubberband_study(RubberBandState, const float *const *input, unsigned int samples, int final);
extern void rubberband_process(RubberBandState, const float *const *input, unsigned int samples, int final); extern void rubberband_process(RubberBandState, const float *const *input, unsigned int samples, int final);

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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -74,6 +74,12 @@ RubberBandStretcher::setTransientsOption(Options options)
m_d->setTransientsOption(options); m_d->setTransientsOption(options);
} }
void
RubberBandStretcher::setDetectorOption(Options options)
{
m_d->setDetectorOption(options);
}
void void
RubberBandStretcher::setPhaseOption(Options options) RubberBandStretcher::setPhaseOption(Options options)
{ {
@@ -104,6 +110,12 @@ RubberBandStretcher::setMaxProcessSize(size_t samples)
m_d->setMaxProcessSize(samples); m_d->setMaxProcessSize(samples);
} }
void
RubberBandStretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
{
m_d->setKeyFrameMap(mapping);
}
size_t size_t
RubberBandStretcher::getSamplesRequired() const RubberBandStretcher::getSamplesRequired() const
{ {

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-2009 Chris Cannam. Copyright 2007-2010 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,6 +45,21 @@ StretchCalculator::~StretchCalculator()
{ {
} }
void
StretchCalculator::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
{
m_keyFrameMap = mapping;
// Ensure we always have a 0 -> 0 mapping. If there's nothing in
// the map at all, don't need to worry about this (empty map is
// handled separately anyway)
if (!m_keyFrameMap.empty()) {
if (m_keyFrameMap.find(0) == m_keyFrameMap.end()) {
m_keyFrameMap[0] = 0;
}
}
}
std::vector<int> std::vector<int>
StretchCalculator::calculate(double ratio, size_t inputDuration, StretchCalculator::calculate(double ratio, size_t inputDuration,
const std::vector<float> &phaseResetDf, const std::vector<float> &phaseResetDf,
@@ -52,11 +67,9 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
{ {
assert(phaseResetDf.size() == stretchDf.size()); assert(phaseResetDf.size() == stretchDf.size());
m_lastPeaks = findPeaks(phaseResetDf); m_peaks = findPeaks(phaseResetDf);
std::vector<Peak> &peaks = m_lastPeaks;
size_t totalCount = phaseResetDf.size();
std::vector<int> increments; size_t totalCount = phaseResetDf.size();
size_t outputDuration = lrint(inputDuration * ratio); size_t outputDuration = lrint(inputDuration * ratio);
@@ -68,14 +81,13 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
if (m_debugLevel > 0) { if (m_debugLevel > 0) {
std::cerr << " (rounded up to " << outputDuration << ")"; std::cerr << " (rounded up to " << outputDuration << ")";
std::cerr << ", df size " << phaseResetDf.size() << std::endl; std::cerr << ", df size " << phaseResetDf.size() << ", increment "
<< m_increment << std::endl;
} }
std::vector<size_t> fixedAudioChunks; std::vector<Peak> peaks; // peak position (in chunks) and hardness
for (size_t i = 0; i < peaks.size(); ++i) { std::vector<size_t> targets; // targets for mapping peaks (in samples)
fixedAudioChunks.push_back mapPeaks(peaks, targets, outputDuration, totalCount);
(lrint((double(peaks[i].chunk) * outputDuration) / totalCount));
}
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
std::cerr << "have " << peaks.size() << " fixed positions" << std::endl; std::cerr << "have " << peaks.size() << " fixed positions" << std::endl;
@@ -93,6 +105,8 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
size_t regionTotalChunks = 0; size_t regionTotalChunks = 0;
std::vector<int> increments;
for (size_t i = 0; i <= peaks.size(); ++i) { for (size_t i = 0; i <= peaks.size(); ++i) {
size_t regionStart, regionStartChunk, regionEnd, regionEndChunk; size_t regionStart, regionStartChunk, regionEnd, regionEndChunk;
@@ -103,17 +117,23 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
regionStart = 0; regionStart = 0;
} else { } else {
regionStartChunk = peaks[i-1].chunk; regionStartChunk = peaks[i-1].chunk;
regionStart = fixedAudioChunks[i-1]; regionStart = targets[i-1];
phaseReset = peaks[i-1].hard; phaseReset = peaks[i-1].hard;
} }
if (i == peaks.size()) { if (i == peaks.size()) {
// std::cerr << "note: i (=" << i << ") == peaks.size(); regionEndChunk " << regionEndChunk << " -> " << totalCount << ", regionEnd " << regionEnd << " -> " << outputDuration << std::endl;
regionEndChunk = totalCount; regionEndChunk = totalCount;
regionEnd = outputDuration; regionEnd = outputDuration;
} else { } else {
regionEndChunk = peaks[i].chunk; regionEndChunk = peaks[i].chunk;
regionEnd = fixedAudioChunks[i]; regionEnd = targets[i];
} }
if (regionStartChunk > totalCount) regionStartChunk = totalCount;
if (regionStart > outputDuration) regionStart = outputDuration;
if (regionEndChunk > totalCount) regionEndChunk = totalCount;
if (regionEnd > outputDuration) regionEnd = outputDuration;
size_t regionDuration = regionEnd - regionStart; size_t regionDuration = regionEnd - regionStart;
regionTotalChunks += regionDuration; regionTotalChunks += regionDuration;
@@ -125,7 +145,7 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
} }
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
std::cerr << "distributeRegion from " << regionStartChunk << " to " << regionEndChunk << " (chunks " << regionStart << " to " << regionEnd << ")" << std::endl; std::cerr << "distributeRegion from " << regionStartChunk << " to " << regionEndChunk << " (samples " << regionStart << " to " << regionEnd << ")" << std::endl;
} }
dfRegion = smoothDF(dfRegion); dfRegion = smoothDF(dfRegion);
@@ -149,7 +169,7 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
} }
if (totalForRegion != regionDuration) { if (totalForRegion != regionDuration) {
std::cerr << "*** WARNING: distributeRegion returned wrong duration " << totalForRegion << ", expected " << regionDuration << std::endl; std::cerr << "*** ERROR: distributeRegion returned wrong duration " << totalForRegion << ", expected " << regionDuration << std::endl;
} }
totalOutput += totalForRegion; totalOutput += totalForRegion;
@@ -163,6 +183,131 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
return increments; return increments;
} }
void
StretchCalculator::mapPeaks(std::vector<Peak> &peaks,
std::vector<size_t> &targets,
size_t outputDuration,
size_t totalCount)
{
// outputDuration is in audio samples; totalCount is in chunks
if (m_keyFrameMap.empty()) {
// "normal" behaviour -- fixed points are strictly in
// proportion
peaks = m_peaks;
for (size_t i = 0; i < peaks.size(); ++i) {
targets.push_back
(lrint((double(peaks[i].chunk) * outputDuration) / totalCount));
}
return;
}
// We have been given a set of source -> target sample frames in
// m_keyFrameMap. We want to ensure that (to the nearest chunk) these
// are followed exactly, and any fixed points that we calculated
// ourselves are interpolated in linear proportion in between.
size_t peakidx = 0;
std::map<size_t, size_t>::const_iterator mi = m_keyFrameMap.begin();
// NB we know for certain we have a mapping from 0 -> 0 (or at
// least, some mapping for source sample 0) because that is
// enforced in setLockPoints above. However, we aren't guaranteed
// to have a mapping for the total duration -- we will usually
// need to assume it maps to the normal duration * ratio sample
while (mi != m_keyFrameMap.end()) {
// std::cerr << "mi->first is " << mi->first << ", second is " << mi->second <<std::endl;
// The map we've been given is from sample to sample, but
// we can only map from chunk to sample. We should perhaps
// adjust the target sample to compensate for the discrepancy
// between the chunk position and the exact requested source
// sample. But we aren't doing that yet.
size_t sourceStartChunk = mi->first / m_increment;
size_t sourceEndChunk = totalCount;
size_t targetStartSample = mi->second;
size_t targetEndSample = outputDuration;
++mi;
if (mi != m_keyFrameMap.end()) {
sourceEndChunk = mi->first / m_increment;
targetEndSample = mi->second;
}
if (sourceStartChunk >= totalCount ||
sourceStartChunk >= sourceEndChunk ||
targetStartSample >= outputDuration ||
targetStartSample >= targetEndSample) {
std::cerr << "NOTE: ignoring mapping from chunk " << sourceStartChunk << " to sample " << targetStartSample << "\n(source or target chunk exceeds total count, or end is not later than start)" << std::endl;
continue;
}
// one peak and target for the mapping, then one for each of
// the computed peaks that appear before the following mapping
Peak p;
p.chunk = sourceStartChunk;
p.hard = false; // mappings are in time only, not phase reset points
peaks.push_back(p);
targets.push_back(targetStartSample);
if (m_debugLevel > 1) {
std::cerr << "mapped chunk " << sourceStartChunk << " (frame " << sourceStartChunk * m_increment << ") -> " << targetStartSample << std::endl;
}
while (peakidx < m_peaks.size()) {
size_t pchunk = m_peaks[peakidx].chunk;
if (pchunk < sourceStartChunk) {
// shouldn't happen, should have been dealt with
// already -- but no harm in ignoring it explicitly
++peakidx;
continue;
}
if (pchunk == sourceStartChunk) {
// convert that last peak to a hard one, after all
peaks[peaks.size()-1].hard = true;
++peakidx;
continue;
}
if (pchunk >= sourceEndChunk) {
// leave the rest for after the next mapping
break;
}
p.chunk = pchunk;
p.hard = m_peaks[peakidx].hard;
double proportion =
double(pchunk - sourceStartChunk) /
double(sourceEndChunk - sourceStartChunk);
size_t target =
targetStartSample +
lrint(proportion *
(targetEndSample - targetStartSample));
if (target <= targets[targets.size()-1] + m_increment) {
// peaks will become too close together afterwards, ignore
++peakidx;
continue;
}
if (m_debugLevel > 1) {
std::cerr << " peak chunk " << pchunk << " (frame " << pchunk * m_increment << ") -> " << target << std::endl;
}
peaks.push_back(p);
targets.push_back(target);
++peakidx;
}
}
}
int int
StretchCalculator::calculateSingle(double ratio, StretchCalculator::calculateSingle(double ratio,
float df, float df,
@@ -182,7 +327,7 @@ StretchCalculator::calculateSingle(double ratio,
// works well in common situations. // works well in common situations.
float transientThreshold = 0.35f; float transientThreshold = 0.35f;
if (ratio > 1) transientThreshold = 0.25f; // if (ratio > 1) transientThreshold = 0.25f;
if (m_useHardPeaks && df > m_prevDf * 1.1f && df > transientThreshold) { if (m_useHardPeaks && df > m_prevDf * 1.1f && df > transientThreshold) {
isTransient = true; isTransient = true;
@@ -200,8 +345,7 @@ 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" std::cerr << "StretchCalculator::calculateSingle: transient (df " << df << ", threshold " << transientThreshold << ")" << std::endl;
<< std::endl;
} }
m_divergence += increment - (increment * ratio); m_divergence += increment - (increment * ratio);
@@ -626,7 +770,7 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
long toAllot = long(duration) - long(m_increment * df.size()); long toAllot = long(duration) - long(m_increment * df.size());
if (m_debugLevel > 1) { if (m_debugLevel > 1) {
std::cerr << "region of " << df.size() << " chunks, output duration " << duration << ", toAllot " << toAllot << std::endl; std::cerr << "region of " << df.size() << " chunks, output duration " << duration << ", increment " << m_increment << ", toAllot " << toAllot << std::endl;
} }
size_t totalIncrement = 0; size_t totalIncrement = 0;
@@ -651,22 +795,24 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
// then we need to adjust and accommodate // then we need to adjust and accommodate
bool acceptableSquashRange = false;
double totalDisplacement = 0; double totalDisplacement = 0;
double maxDisplacement = 0; // min displacement will be 0 by definition double maxDisplacement = 0; // min displacement will be 0 by definition
maxDf = 0; maxDf = 0;
float adj = 0; float adj = 0;
bool tooShort = true, tooLong = true;
const int acceptableIterations = 10; const int acceptableIterations = 10;
int iteration = 0; int iteration = 0;
int prevExtreme = 0;
while (!acceptableSquashRange && iteration < acceptableIterations) { bool better = false;
while ((tooLong || tooShort) && iteration < acceptableIterations) {
++iteration; ++iteration;
acceptableSquashRange = true; tooLong = false;
tooShort = false;
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement, calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
adj); adj);
@@ -678,35 +824,61 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
// Not usually a problem, in fact // Not usually a problem, in fact
// std::cerr << "WARNING: totalDisplacement == 0 (duration " << duration << ", " << df.size() << " values in df)" << std::endl; // std::cerr << "WARNING: totalDisplacement == 0 (duration " << duration << ", " << df.size() << " values in df)" << std::endl;
if (!df.empty() && adj == 0) { if (!df.empty() && adj == 0) {
acceptableSquashRange = false; tooLong = true; tooShort = true;
adj = 1; adj = 1;
} }
continue; continue;
} }
int extremeIncrement = m_increment + lrint((toAllot * maxDisplacement) / totalDisplacement); int extremeIncrement = m_increment +
if (ratio < 1.0) { lrint((toAllot * maxDisplacement) / totalDisplacement);
if (extremeIncrement > lrint(ceil(m_increment * ratio))) {
std::cerr << "WARNING: extreme increment " << extremeIncrement << " > " << m_increment * ratio << std::endl;
} else if (extremeIncrement < (m_increment * ratio) / 2) {
if (m_debugLevel > 0) {
std::cerr << "NOTE: extreme increment " << extremeIncrement << " < " << (m_increment * ratio) / 2 << ", adjusting" << std::endl;
}
acceptableSquashRange = false;
}
} else {
if (extremeIncrement > m_increment * ratio * 2) {
if (m_debugLevel > 0) {
std::cerr << "NOTE: extreme increment " << extremeIncrement << " > " << m_increment * ratio * 2 << ", adjusting" << std::endl;
if (extremeIncrement < 0) {
if (m_debugLevel > 0) {
std::cerr << "NOTE: extreme increment " << extremeIncrement << " < 0, adjusting" << std::endl;
}
tooShort = true;
} else {
if (ratio < 1.0) {
if (extremeIncrement > lrint(ceil(m_increment * ratio))) {
std::cerr << "WARNING: extreme increment "
<< extremeIncrement << " > "
<< m_increment * ratio << std::endl;
} else if (extremeIncrement < (m_increment * ratio) / 2) {
if (m_debugLevel > 0) {
std::cerr << "NOTE: extreme increment "
<< extremeIncrement << " < "
<< (m_increment * ratio) / 2
<< ", adjusting" << std::endl;
}
tooShort = true;
if (iteration > 0) {
better = (extremeIncrement > prevExtreme);
}
prevExtreme = extremeIncrement;
}
} else {
if (extremeIncrement > m_increment * ratio * 2) {
if (m_debugLevel > 0) {
std::cerr << "NOTE: extreme increment "
<< extremeIncrement << " > "
<< m_increment * ratio * 2
<< ", adjusting" << std::endl;
}
tooLong = true;
if (iteration > 0) {
better = (extremeIncrement < prevExtreme);
}
prevExtreme = extremeIncrement;
} else if (extremeIncrement < lrint(floor(m_increment * ratio))) {
std::cerr << "WARNING: extreme increment "
<< extremeIncrement << " < "
<< m_increment * ratio << std::endl;
} }
acceptableSquashRange = false;
} else if (extremeIncrement < lrint(floor(m_increment * ratio))) {
std::cerr << "WARNING: extreme increment " << extremeIncrement << " < " << m_increment * ratio << std::endl;
} }
} }
if (!acceptableSquashRange) { if (tooLong || tooShort) {
// Need to make maxDisplacement smaller as a proportion of // Need to make maxDisplacement smaller as a proportion of
// the total displacement, yet ensure that the // the total displacement, yet ensure that the
// displacements still sum to the total. // displacements still sum to the total.
@@ -714,9 +886,24 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
} }
} }
if (!acceptableSquashRange) { if (tooLong) {
std::cerr << "WARNING: No acceptable displacement adjustment found, using defaults:\nthis region will probably sound bad" << std::endl; if (better) {
adj = 0; // we were iterating in the right direction, so
// leave things as they are (and undo that last tweak)
std::cerr << "WARNING: No acceptable displacement adjustment found, using latest values:\nthis region could sound bad" << std::endl;
adj -= maxDf/10;
} else {
std::cerr << "WARNING: No acceptable displacement adjustment found, using defaults:\nthis region could sound bad" << std::endl;
adj = 1;
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
adj);
}
} else if (tooShort) {
std::cerr << "WARNING: No acceptable displacement adjustment found, using flat distribution:\nthis region could sound bad" << std::endl;
adj = 1;
for (size_t i = 0; i < df.size(); ++i) {
df[i] = 1.f;
}
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement, calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
adj); adj);
} }
@@ -728,6 +915,9 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
else displacement += adj; else displacement += adj;
if (i == 0 && phaseReset) { if (i == 0 && phaseReset) {
if (m_debugLevel > 2) {
std::cerr << "Phase reset at first chunk" << std::endl;
}
if (df.size() == 1) { if (df.size() == 1) {
increments.push_back(duration); increments.push_back(duration);
totalIncrement += duration; totalIncrement += duration;
@@ -749,19 +939,23 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
int increment = m_increment + allotment; int increment = m_increment + allotment;
if (increment <= 0) { if (increment < 0) {
// this is a serious problem, the allocation is quite // this is a serious problem, the allocation is quite
// wrong if it allows increment to diverge so far from the // wrong if it allows increment to diverge so far from the
// input increment // input increment (though it can happen legitimately if
// asked to squash very violently)
std::cerr << "*** WARNING: increment " << increment << " <= 0, rounding to zero" << std::endl; std::cerr << "*** WARNING: increment " << increment << " <= 0, rounding to zero" << std::endl;
toAllot += m_increment;
increment = 0; increment = 0;
allotment = increment - m_increment;
} else {
toAllot -= allotment;
} }
increments.push_back(increment); increments.push_back(increment);
totalIncrement += increment; totalIncrement += increment;
toAllot -= allotment;
totalDisplacement -= displacement; totalDisplacement -= displacement;
if (m_debugLevel > 2) { if (m_debugLevel > 2) {

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-2009 Chris Cannam. Copyright 2007-2010 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,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <vector> #include <vector>
#include <map>
namespace RubberBand namespace RubberBand
{ {
@@ -28,6 +29,15 @@ public:
StretchCalculator(size_t sampleRate, size_t inputIncrement, bool useHardPeaks); StretchCalculator(size_t sampleRate, size_t inputIncrement, bool useHardPeaks);
virtual ~StretchCalculator(); virtual ~StretchCalculator();
/**
* Provide a set of mappings from "before" to "after" sample
* numbers so as to enforce a particular stretch profile. This
* must be called before calculate(). The argument is a map from
* audio sample frame number in the source material to the
* corresponding sample frame number in the stretched output.
*/
void setKeyFrameMap(const std::map<size_t, size_t> &mapping);
/** /**
* Calculate phase increments for a region of audio, given the * Calculate phase increments for a region of audio, given the
* overall target stretch ratio, input duration in audio samples, * overall target stretch ratio, input duration in audio samples,
@@ -35,9 +45,9 @@ public:
* (lockAudioCurve) and for allocating stretches to relatively * (lockAudioCurve) and for allocating stretches to relatively
* less prominent points (stretchAudioCurve). * less prominent points (stretchAudioCurve).
*/ */
virtual std::vector<int> calculate(double ratio, size_t inputDuration, std::vector<int> calculate(double ratio, size_t inputDuration,
const std::vector<float> &lockAudioCurve, const std::vector<float> &lockAudioCurve,
const std::vector<float> &stretchAudioCurve); const std::vector<float> &stretchAudioCurve);
/** /**
* Calculate the phase increment for a single audio block, given * Calculate the phase increment for a single audio block, given
@@ -49,8 +59,8 @@ public:
* If increment is non-zero, use it for the input increment for * If increment is non-zero, use it for the input increment for
* this block in preference to m_increment. * this block in preference to m_increment.
*/ */
virtual int calculateSingle(double ratio, float curveValue, int calculateSingle(double ratio, float curveValue,
size_t increment = 0); size_t increment = 0);
void setUseHardPeaks(bool use) { m_useHardPeaks = use; } void setUseHardPeaks(bool use) { m_useHardPeaks = use; }
@@ -62,13 +72,16 @@ public:
size_t chunk; size_t chunk;
bool hard; bool hard;
}; };
std::vector<Peak> getLastCalculatedPeaks() const { return m_lastPeaks; } std::vector<Peak> getLastCalculatedPeaks() const { return m_peaks; }
std::vector<float> smoothDF(const std::vector<float> &df); std::vector<float> smoothDF(const std::vector<float> &df);
protected: protected:
std::vector<Peak> findPeaks(const std::vector<float> &audioCurve); std::vector<Peak> findPeaks(const std::vector<float> &audioCurve);
void mapPeaks(std::vector<Peak> &peaks, std::vector<size_t> &targets,
size_t outputDuration, size_t totalCount);
std::vector<int> distributeRegion(const std::vector<float> &regionCurve, std::vector<int> distributeRegion(const std::vector<float> &regionCurve,
size_t outputDuration, float ratio, size_t outputDuration, float ratio,
bool phaseReset); bool phaseReset);
@@ -89,8 +102,9 @@ protected:
int m_transientAmnesty; // only in RT mode; handled differently offline int m_transientAmnesty; // only in RT mode; handled differently offline
int m_debugLevel; int m_debugLevel;
bool m_useHardPeaks; bool m_useHardPeaks;
std::vector<Peak> m_lastPeaks; std::map<size_t, size_t> m_keyFrameMap;
std::vector<Peak> m_peaks;
}; };
} }

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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -21,11 +21,11 @@
//#define EXPERIMENT 1 //#define EXPERIMENT 1
namespace RubberBand { class Resampler; }
namespace RubberBand namespace RubberBand
{ {
class Resampler;
class RubberBandStretcher::Impl::ChannelData class RubberBandStretcher::Impl::ChannelData
{ {
public: public:

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-2009 Chris Cannam. Copyright 2007-2010 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,7 @@
#include "dsp/SpectralDifferenceAudioCurve.h" #include "dsp/SpectralDifferenceAudioCurve.h"
#include "dsp/SilentAudioCurve.h" #include "dsp/SilentAudioCurve.h"
#include "dsp/ConstantAudioCurve.h" #include "dsp/ConstantAudioCurve.h"
#include "dsp/CompoundAudioCurve.h"
#include "dsp/Resampler.h" #include "dsp/Resampler.h"
#include "StretchCalculator.h" #include "StretchCalculator.h"
@@ -81,9 +82,11 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_studyFFT(0), m_studyFFT(0),
m_spaceAvailable("space"), m_spaceAvailable("space"),
m_inputDuration(0), m_inputDuration(0),
m_detectorType(CompoundAudioCurve::CompoundDetector),
m_silentHistory(0), m_silentHistory(0),
m_lastProcessOutputIncrements(16), m_lastProcessOutputIncrements(16),
m_lastProcessPhaseResetDf(16), m_lastProcessPhaseResetDf(16),
m_emergencyScavenger(10, 4),
m_phaseResetAudioCurve(0), m_phaseResetAudioCurve(0),
m_stretchAudioCurve(0), m_stretchAudioCurve(0),
m_silentAudioCurve(0), m_silentAudioCurve(0),
@@ -105,7 +108,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
// Window size will vary according to the audio sample rate, but // Window size will vary according to the audio sample rate, but
// we don't let it drop below the 48k default // we don't let it drop below the 48k default
m_rateMultiple = float(m_sampleRate) / 48000.f; m_rateMultiple = float(m_sampleRate) / 48000.f;
if (m_rateMultiple < 1.f) m_rateMultiple = 1.f; // if (m_rateMultiple < 1.f) m_rateMultiple = 1.f;
m_baseWindowSize = roundUp(int(m_defaultWindowSize * m_rateMultiple)); m_baseWindowSize = roundUp(int(m_defaultWindowSize * m_rateMultiple));
if ((options & OptionWindowShort) || (options & OptionWindowLong)) { if ((options & OptionWindowShort) || (options & OptionWindowLong)) {
@@ -205,6 +208,12 @@ RubberBandStretcher::Impl::reset()
m_threadSet.clear(); m_threadSet.clear();
} }
m_emergencyScavenger.scavenge();
if (m_stretchCalculator) {
m_stretchCalculator->setKeyFrameMap(std::map<size_t, size_t>());
}
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
m_channelData[c]->reset(); m_channelData[c]->reset();
} }
@@ -299,6 +308,24 @@ RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
reconfigure(); reconfigure();
} }
void
RubberBandStretcher::Impl::setKeyFrameMap(const std::map<size_t, size_t> &
mapping)
{
if (m_realtime) {
cerr << "RubberBandStretcher::Impl::setKeyFrameMap: Cannot specify key frame map in RT mode" << endl;
return;
}
if (m_mode == Processing) {
cerr << "RubberBandStretcher::Impl::setKeyFrameMap: Cannot specify key frame map after process() has begun" << endl;
return;
}
if (m_stretchCalculator) {
m_stretchCalculator->setKeyFrameMap(mapping);
}
}
float float
RubberBandStretcher::Impl::getFrequencyCutoff(int n) const RubberBandStretcher::Impl::getFrequencyCutoff(int n) const
{ {
@@ -399,7 +426,7 @@ RubberBandStretcher::Impl::calculateSizes()
float windowIncrRatio = 4.5; float windowIncrRatio = 4.5;
if (r == 1.0) windowIncrRatio = 4; if (r == 1.0) windowIncrRatio = 4;
else if (rsb) windowIncrRatio = 4.5; else if (rsb) windowIncrRatio = 4.5;
else windowIncrRatio = 6; else windowIncrRatio = 8;
outputIncrement = int(windowSize / windowIncrRatio); outputIncrement = int(windowSize / windowIncrRatio);
inputIncrement = int(outputIncrement / r); inputIncrement = int(outputIncrement / r);
@@ -598,21 +625,22 @@ RubberBandStretcher::Impl::configure()
// modes // modes
delete m_phaseResetAudioCurve; delete m_phaseResetAudioCurve;
m_phaseResetAudioCurve = new PercussiveAudioCurve m_phaseResetAudioCurve = new CompoundAudioCurve
(m_sampleRate, m_windowSize); (CompoundAudioCurve::Parameters(m_sampleRate, m_windowSize));
m_phaseResetAudioCurve->setType(m_detectorType);
delete m_silentAudioCurve; delete m_silentAudioCurve;
m_silentAudioCurve = new SilentAudioCurve m_silentAudioCurve = new SilentAudioCurve
(m_sampleRate, m_windowSize); (SilentAudioCurve::Parameters(m_sampleRate, m_windowSize));
if (!m_realtime) { if (!m_realtime) {
delete m_stretchAudioCurve; delete m_stretchAudioCurve;
if (!(m_options & OptionStretchPrecise)) { if (!(m_options & OptionStretchPrecise)) {
m_stretchAudioCurve = new SpectralDifferenceAudioCurve m_stretchAudioCurve = new SpectralDifferenceAudioCurve
(m_sampleRate, m_windowSize); (SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_windowSize));
} else { } else {
m_stretchAudioCurve = new ConstantAudioCurve m_stretchAudioCurve = new ConstantAudioCurve
(m_sampleRate, m_windowSize); (ConstantAudioCurve::Parameters(m_sampleRate, m_windowSize));
} }
} }
@@ -735,6 +763,30 @@ RubberBandStretcher::Impl::setTransientsOption(Options options)
(!(m_options & OptionTransientsSmooth)); (!(m_options & OptionTransientsSmooth));
} }
void
RubberBandStretcher::Impl::setDetectorOption(Options options)
{
if (!m_realtime) {
cerr << "RubberBandStretcher::Impl::setDetectorOption: Not permissible in non-realtime mode" << endl;
return;
}
int mask = (OptionDetectorPercussive | OptionDetectorCompound | OptionDetectorSoft);
m_options &= ~mask;
options &= mask;
m_options |= options;
CompoundAudioCurve::Type dt = CompoundAudioCurve::CompoundDetector;
if (m_options & OptionDetectorPercussive) dt = CompoundAudioCurve::PercussiveDetector;
else if (m_options & OptionDetectorSoft) dt = CompoundAudioCurve::SoftDetector;
if (dt == m_detectorType) return;
m_detectorType = dt;
if (m_phaseResetAudioCurve) {
m_phaseResetAudioCurve->setType(m_detectorType);
}
}
void void
RubberBandStretcher::Impl::setPhaseOption(Options options) RubberBandStretcher::Impl::setPhaseOption(Options options)
{ {
@@ -955,6 +1007,17 @@ RubberBandStretcher::Impl::calculateStretch()
} }
} }
double prdm = 0, sdm = 0;
if (!m_phaseResetDf.empty()) {
for (int i = 0; i < m_phaseResetDf.size(); ++i) prdm += m_phaseResetDf[i];
prdm /= m_phaseResetDf.size();
}
if (!m_stretchDf.empty()) {
for (int i = 0; i < m_stretchDf.size(); ++i) sdm += m_stretchDf[i];
sdm /= m_stretchDf.size();
}
// std::cerr << "phase reset df mean = " << prdm << ", stretch df mean = " << sdm << std::endl;
std::vector<int> increments = m_stretchCalculator->calculate std::vector<int> increments = m_stretchCalculator->calculate
(getEffectiveRatio(), (getEffectiveRatio(),
inputDuration, inputDuration,

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-2009 Chris Cannam. Copyright 2007-2010 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,7 @@
#include "dsp/Window.h" #include "dsp/Window.h"
#include "dsp/FFT.h" #include "dsp/FFT.h"
#include "dsp/CompoundAudioCurve.h"
#include "base/RingBuffer.h" #include "base/RingBuffer.h"
#include "system/Thread.h" #include "system/Thread.h"
@@ -28,11 +29,10 @@
using namespace RubberBand; using namespace RubberBand;
namespace RubberBand { class AudioCurveCalculator; }
namespace RubberBand namespace RubberBand
{ {
class AudioCurveCalculator;
class StretchCalculator; class StretchCalculator;
class RubberBandStretcher::Impl class RubberBandStretcher::Impl
@@ -52,12 +52,14 @@ public:
size_t getLatency() const; size_t getLatency() const;
void setTransientsOption(Options); void setTransientsOption(Options);
void setDetectorOption(Options);
void setPhaseOption(Options); void setPhaseOption(Options);
void setFormantOption(Options); void setFormantOption(Options);
void setPitchOption(Options); void setPitchOption(Options);
void setExpectedInputDuration(size_t samples); void setExpectedInputDuration(size_t samples);
void setMaxProcessSize(size_t samples); void setMaxProcessSize(size_t samples);
void setKeyFrameMap(const std::map<size_t, size_t> &);
size_t getSamplesRequired() const; size_t getSamplesRequired() const;
@@ -168,6 +170,7 @@ protected:
size_t m_inputDuration; size_t m_inputDuration;
CompoundAudioCurve::Type m_detectorType;
std::vector<float> m_phaseResetDf; std::vector<float> m_phaseResetDf;
std::vector<float> m_stretchDf; std::vector<float> m_stretchDf;
std::vector<bool> m_silence; std::vector<bool> m_silence;
@@ -180,8 +183,9 @@ protected:
mutable RingBuffer<int> m_lastProcessOutputIncrements; mutable RingBuffer<int> m_lastProcessOutputIncrements;
mutable RingBuffer<float> m_lastProcessPhaseResetDf; mutable RingBuffer<float> m_lastProcessPhaseResetDf;
Scavenger<RingBuffer<float> > m_emergencyScavenger;
AudioCurveCalculator *m_phaseResetAudioCurve; CompoundAudioCurve *m_phaseResetAudioCurve;
AudioCurveCalculator *m_stretchAudioCurve; AudioCurveCalculator *m_stretchAudioCurve;
AudioCurveCalculator *m_silentAudioCurve; AudioCurveCalculator *m_silentAudioCurve;
StretchCalculator *m_stretchCalculator; StretchCalculator *m_stretchCalculator;

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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -198,6 +198,8 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
// 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.
// This is the normal process method in offline mode.
ChannelData &cd = *m_channelData[c]; ChannelData &cd = *m_channelData[c];
last = false; last = false;
@@ -216,14 +218,36 @@ RubberBandStretcher::Impl::processChunks(size_t c, bool &any, bool &last)
size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize); size_t got = cd.inbuf->peek(cd.fltbuf, m_windowSize);
assert(got == m_windowSize || cd.inputSize >= 0); assert(got == m_windowSize || cd.inputSize >= 0);
cd.inbuf->skip(m_increment); cd.inbuf->skip(m_increment);
analyseChunk(c);
} }
bool phaseReset = false; bool phaseReset = false;
size_t phaseIncrement, shiftIncrement; size_t phaseIncrement, shiftIncrement;
getIncrements(c, phaseIncrement, shiftIncrement, phaseReset); getIncrements(c, phaseIncrement, shiftIncrement, phaseReset);
last = processChunkForChannel(c, phaseIncrement, shiftIncrement, phaseReset); if (shiftIncrement <= m_windowSize) {
analyseChunk(c);
last = processChunkForChannel
(c, phaseIncrement, shiftIncrement, phaseReset);
} else {
size_t bit = m_windowSize/4;
if (m_debugLevel > 1) {
cerr << "channel " << c << " breaking down overlong increment " << shiftIncrement << " into " << bit << "-size bits" << endl;
}
analyseChunk(c);
float *tmp = (float *)alloca(m_windowSize * sizeof(float));
v_copy(tmp, cd.fltbuf, m_windowSize);
for (size_t i = 0; i < shiftIncrement; i += bit) {
v_copy(cd.fltbuf, tmp, m_windowSize);
size_t thisIncrement = bit;
if (i + thisIncrement > shiftIncrement) {
thisIncrement = shiftIncrement - i;
}
last = processChunkForChannel
(c, phaseIncrement + i, thisIncrement, phaseReset);
phaseReset = false;
}
}
cd.chunkCount++; cd.chunkCount++;
if (m_debugLevel > 2) { if (m_debugLevel > 2) {
cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl; cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl;
@@ -240,6 +264,8 @@ RubberBandStretcher::Impl::processOneChunk()
// 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.
// This is the normal process method in RT mode.
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
if (!testInbufReadSpace(c)) return false; if (!testInbufReadSpace(c)) return false;
ChannelData &cd = *m_channelData[c]; ChannelData &cd = *m_channelData[c];
@@ -383,29 +409,31 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
} }
} }
if (m_threaded) { int required = shiftIncrement;
int required = shiftIncrement; if (m_pitchScale != 1.0) {
required = int(required / m_pitchScale) + 1;
if (m_pitchScale != 1.0) {
required = int(required / m_pitchScale) + 1;
}
if (cd.outbuf->getWriteSpace() < required) {
if (m_debugLevel > 0) {
cerr << "Buffer overrun on output for channel " << c << endl;
}
//!!! The only correct thing we can do here is resize the
// buffer. We can't wait for the client thread to read
// some data out from the buffer so as to make more space,
// because the client thread is probably stuck in a
// process() call waiting for us to stow away enough input
// increments to allow the process() call to complete.
}
} }
int ws = cd.outbuf->getWriteSpace();
if (ws < required) {
if (m_debugLevel > 0) {
cerr << "Buffer overrun on output for channel " << c << endl;
}
// The only correct thing we can do here is resize the buffer.
// We can't wait for the client thread to read some data out
// from the buffer so as to make more space, because the
// client thread (if we are threaded at all) is probably stuck
// in a process() call waiting for us to stow away enough
// input increments to allow the process() call to complete.
// This is an unhappy situation.
RingBuffer<float> *oldbuf = cd.outbuf;
cd.outbuf = oldbuf->resized(oldbuf->getSize() + (required - ws));
m_emergencyScavenger.claim(oldbuf);
}
writeChunk(c, shiftIncrement, last); writeChunk(c, shiftIncrement, last);
return last; return last;
} }
@@ -589,12 +617,12 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
if (shiftIncrement < 0) { if (shiftIncrement < 0) {
shiftIncrement = -shiftIncrement; shiftIncrement = -shiftIncrement;
} }
/*
if (shiftIncrement >= int(m_windowSize)) { if (shiftIncrement >= int(m_windowSize)) {
cerr << "*** ERROR: RubberBandStretcher::Impl::processChunks: shiftIncrement " << shiftIncrement << " >= windowSize " << m_windowSize << " at " << cd.chunkCount << " (of " << m_outputIncrements.size() << ")" << endl; cerr << "*** ERROR: RubberBandStretcher::Impl::processChunks: shiftIncrement " << shiftIncrement << " >= windowSize " << m_windowSize << " at " << cd.chunkCount << " (of " << m_outputIncrements.size() << ")" << endl;
shiftIncrement = m_windowSize; shiftIncrement = m_windowSize;
} }
*/
phaseIncrementRtn = phaseIncrement; phaseIncrementRtn = phaseIncrement;
shiftIncrementRtn = shiftIncrement; shiftIncrementRtn = shiftIncrement;
if (cd.chunkCount == 0) phaseReset = true; // don't mess with the first chunk if (cd.chunkCount == 0) phaseReset = true; // don't mess with the first chunk
@@ -781,7 +809,7 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel,
cd.unwrappedPhase[i] = outphase; cd.unwrappedPhase[i] = outphase;
} }
if (m_debugLevel > 1) { if (m_debugLevel > 2) {
cerr << "mean inheritance distance = " << distacc / count << endl; cerr << "mean inheritance distance = " << distacc / count << 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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,18 +14,50 @@
#include "AudioCurveCalculator.h" #include "AudioCurveCalculator.h"
#include <iostream>
namespace RubberBand namespace RubberBand
{ {
AudioCurveCalculator::AudioCurveCalculator(size_t sampleRate, size_t windowSize) : static const int MaxPerceivedFreq = 16000;
m_sampleRate(sampleRate),
m_windowSize(windowSize) AudioCurveCalculator::AudioCurveCalculator(Parameters parameters) :
m_sampleRate(parameters.sampleRate),
m_windowSize(parameters.windowSize)
{ {
recalculateLastPerceivedBin();
} }
AudioCurveCalculator::~AudioCurveCalculator() AudioCurveCalculator::~AudioCurveCalculator()
{ {
} }
void
AudioCurveCalculator::setSampleRate(int newRate)
{
m_sampleRate = newRate;
recalculateLastPerceivedBin();
}
void
AudioCurveCalculator::setWindowSize(int newSize)
{
m_windowSize = newSize;
recalculateLastPerceivedBin();
}
void
AudioCurveCalculator::recalculateLastPerceivedBin()
{
if (m_sampleRate == 0) {
m_lastPerceivedBin = 0;
return;
}
m_lastPerceivedBin = ((MaxPerceivedFreq * m_windowSize) / m_sampleRate);
if (m_lastPerceivedBin > m_windowSize/2) {
m_lastPerceivedBin = m_windowSize/2;
}
}
} }

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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -26,28 +26,51 @@ namespace RubberBand
class AudioCurveCalculator class AudioCurveCalculator
{ {
public: public:
AudioCurveCalculator(size_t sampleRate, size_t windowSize); struct Parameters {
Parameters(int _sampleRate, int _windowSize) :
sampleRate(_sampleRate),
windowSize(_windowSize)
{ }
int sampleRate;
int windowSize;
};
AudioCurveCalculator(Parameters parameters);
virtual ~AudioCurveCalculator(); virtual ~AudioCurveCalculator();
size_t getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }
size_t getWindowSize() const { return m_windowSize; } int getWindowSize() const { return m_windowSize; }
virtual void setWindowSize(size_t newSize) = 0; virtual void setSampleRate(int newRate);
virtual void setWindowSize(int newSize);
Parameters getParameters() const {
return Parameters(m_sampleRate, m_windowSize);
}
void setParameters(Parameters p) {
setSampleRate(p.sampleRate);
setWindowSize(p.windowSize);
}
// You may not mix calls to the various process functions on a // You may not mix calls to the various process functions on a
// given instance // given instance
virtual float processFloat(const float *R__ mag, size_t increment) = 0; virtual float processFloat(const float *R__ mag, int increment) = 0;
virtual double processDouble(const double *R__ mag, size_t increment) = 0; virtual double processDouble(const double *R__ mag, int increment) = 0;
virtual void reset() = 0; virtual void reset() = 0;
virtual const char *getUnit() const { return ""; }
protected: protected:
size_t m_sampleRate; int m_sampleRate;
size_t m_windowSize; int m_windowSize;
int m_lastPerceivedBin;
void recalculateLastPerceivedBin();
}; };
} }
#endif #endif

View File

@@ -0,0 +1,164 @@
/* -*- 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-2010 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 "CompoundAudioCurve.h"
#include "MovingMedian.h"
#include <iostream>
namespace RubberBand
{
CompoundAudioCurve::CompoundAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters),
m_percussive(parameters),
m_hf(parameters),
m_hfFilter(new MovingMedian<double>(19, 85)),
m_hfDerivFilter(new MovingMedian<double>(19, 90)),
m_lastHf(0.0),
m_lastResult(0.0),
m_risingCount(0)
{
std::cerr << "CompoundAudioCurve::CompoundAudioCurve: window "
<< parameters.windowSize << ", rate " << parameters.sampleRate
<< std::endl;
}
CompoundAudioCurve::~CompoundAudioCurve()
{
delete m_hfFilter;
delete m_hfDerivFilter;
}
void
CompoundAudioCurve::setType(Type type)
{
std::cerr << "CompoundAudioCurve::setType to " << type << std::endl;
m_type = type;
}
void
CompoundAudioCurve::reset()
{
m_percussive.reset();
m_hf.reset();
m_hfFilter->reset();
m_hfDerivFilter->reset();
m_lastHf = 0.0;
m_lastResult = 0.0;
}
void
CompoundAudioCurve::setWindowSize(int newSize)
{
m_percussive.setWindowSize(newSize);
m_hf.setWindowSize(newSize);
m_windowSize = newSize;
m_lastHf = 0.0;
m_lastResult = 0.0;
}
float
CompoundAudioCurve::processFloat(const float *R__ mag, int increment)
{
float percussive = 0.f;
float hf = 0.f;
switch (m_type) {
case PercussiveDetector:
percussive = m_percussive.processFloat(mag, increment);
break;
case CompoundDetector:
percussive = m_percussive.processFloat(mag, increment);
hf = m_hf.processFloat(mag, increment);
break;
case SoftDetector:
hf = m_hf.processFloat(mag, increment);
break;
}
return processFiltering(percussive, hf);
}
double
CompoundAudioCurve::processDouble(const double *R__ mag, int increment)
{
double percussive = 0.0;
double hf = 0.0;
switch (m_type) {
case PercussiveDetector:
percussive = m_percussive.processDouble(mag, increment);
break;
case CompoundDetector:
percussive = m_percussive.processDouble(mag, increment);
hf = m_hf.processDouble(mag, increment);
break;
case SoftDetector:
hf = m_hf.processDouble(mag, increment);
break;
}
return processFiltering(percussive, hf);
}
double
CompoundAudioCurve::processFiltering(double percussive, double hf)
{
if (m_type == PercussiveDetector) {
if (percussive > 0.35) {
return 1.0;
} else {
return 0.0;
}
}
double rv = 0.f;
double hfDeriv = hf - m_lastHf;
m_hfFilter->push(hf);
m_hfDerivFilter->push(hfDeriv);
double hfFiltered = m_hfFilter->get();
double hfDerivFiltered = m_hfDerivFilter->get();
m_lastHf = hf;
double result = 0.f;
double hfExcess = hf - hfFiltered;
if (hfExcess > 0.0) {
result = hfDeriv - hfDerivFiltered;
}
if (m_type != SoftDetector && percussive > 0.35 && hfExcess > 0.0) {
rv = 1.0;
m_risingCount = 0;
} else {
if (result < m_lastResult) {
if (m_risingCount > 3 && m_lastResult > 0) rv = 0.5;
m_risingCount = 0;
} else {
m_risingCount ++;
}
}
m_lastResult = result;
return rv;
}
}

View File

@@ -0,0 +1,65 @@
/* -*- 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-2010 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 _COMPOUND_AUDIO_CURVE_H_
#define _COMPOUND_AUDIO_CURVE_H_
#include "AudioCurveCalculator.h"
#include "PercussiveAudioCurve.h"
#include "HighFrequencyAudioCurve.h"
#include "SampleFilter.h"
namespace RubberBand
{
class CompoundAudioCurve : public AudioCurveCalculator
{
public:
CompoundAudioCurve(Parameters parameters);
virtual ~CompoundAudioCurve();
enum Type {
PercussiveDetector,
CompoundDetector,
SoftDetector
};
virtual void setType(Type);
virtual void setWindowSize(int newSize);
virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual void reset();
protected:
PercussiveAudioCurve m_percussive;
HighFrequencyAudioCurve m_hf;
SampleFilter<double> *m_hfFilter;
SampleFilter<double> *m_hfDerivFilter;
Type m_type;
double m_lastHf;
double m_lastResult;
int m_risingCount;
double processFiltering(double percussive, double hf);
};
}
#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-2009 Chris Cannam. Copyright 2007-2010 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,9 @@
namespace RubberBand namespace RubberBand
{ {
ConstantAudioCurve::ConstantAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurveCalculator(sampleRate, windowSize) ConstantAudioCurve::ConstantAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters)
{ {
} }
@@ -31,20 +32,14 @@ ConstantAudioCurve::reset()
{ {
} }
void
ConstantAudioCurve::setWindowSize(size_t newSize)
{
m_windowSize = newSize;
}
float float
ConstantAudioCurve::processFloat(const float *R__, size_t) ConstantAudioCurve::processFloat(const float *R__, int)
{ {
return 1.f; return 1.f;
} }
double double
ConstantAudioCurve::processDouble(const double *R__, size_t) ConstantAudioCurve::processDouble(const double *R__, int)
{ {
return 1.0; return 1.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-2009 Chris Cannam. Copyright 2007-2010 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,13 +23,11 @@ namespace RubberBand
class ConstantAudioCurve : public AudioCurveCalculator class ConstantAudioCurve : public AudioCurveCalculator
{ {
public: public:
ConstantAudioCurve(size_t sampleRate, size_t windowSize); ConstantAudioCurve(Parameters parameters);
virtual ~ConstantAudioCurve(); virtual ~ConstantAudioCurve();
virtual void setWindowSize(size_t newSize); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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,9 @@
namespace RubberBand namespace RubberBand
{ {
HighFrequencyAudioCurve::HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurveCalculator(sampleRate, windowSize) HighFrequencyAudioCurve::HighFrequencyAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters)
{ {
} }
@@ -31,18 +32,12 @@ HighFrequencyAudioCurve::reset()
{ {
} }
void
HighFrequencyAudioCurve::setWindowSize(size_t newSize)
{
m_windowSize = newSize;
}
float float
HighFrequencyAudioCurve::processFloat(const float *R__ mag, size_t increment) HighFrequencyAudioCurve::processFloat(const float *R__ mag, int increment)
{ {
float result = 0.0; float result = 0.0;
const int sz = m_windowSize / 2; const int sz = m_lastPerceivedBin;
for (int n = 0; n <= sz; ++n) { for (int n = 0; n <= sz; ++n) {
result = result + mag[n] * n; result = result + mag[n] * n;
@@ -52,11 +47,11 @@ HighFrequencyAudioCurve::processFloat(const float *R__ mag, size_t increment)
} }
double double
HighFrequencyAudioCurve::processDouble(const double *R__ mag, size_t increment) HighFrequencyAudioCurve::processDouble(const double *R__ mag, int increment)
{ {
float result = 0.0; float result = 0.0;
const int sz = m_windowSize / 2; const int sz = m_lastPerceivedBin;
for (int n = 0; n <= sz; ++n) { for (int n = 0; n <= sz; ++n) {
result = result + mag[n] * n; result = result + mag[n] * n;

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-2009 Chris Cannam. Copyright 2007-2010 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,15 +23,14 @@ namespace RubberBand
class HighFrequencyAudioCurve : public AudioCurveCalculator class HighFrequencyAudioCurve : public AudioCurveCalculator
{ {
public: public:
HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize); HighFrequencyAudioCurve(Parameters parameters);
virtual ~HighFrequencyAudioCurve(); virtual ~HighFrequencyAudioCurve();
virtual void setWindowSize(size_t newSize); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual void reset(); virtual void reset();
virtual const char *getUnit() const { return "Vbin"; }
}; };
} }

95
src/dsp/MovingMedian.h Normal file
View File

@@ -0,0 +1,95 @@
/* -*- 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-2010 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 _MOVING_MEDIAN_H_
#define _MOVING_MEDIAN_H_
#include "SampleFilter.h"
#include "system/Allocators.h"
#include <algorithm>
namespace RubberBand
{
template <typename T>
class MovingMedian : public SampleFilter<T>
{
typedef SampleFilter<T> P;
public:
MovingMedian(int size, float percentile = 50.f) :
SampleFilter<T>(size),
m_frame(allocate_and_zero<T>(size)),
m_sorted(allocate_and_zero<T>(size)),
m_sortend(m_sorted + P::m_size - 1) {
setPercentile(percentile);
}
~MovingMedian() {
deallocate(m_frame);
deallocate(m_sorted);
}
void setPercentile(float p) {
m_index = int((P::m_size * p) / 100.f);
if (m_index >= P::m_size) m_index = P::m_size-1;
if (m_index < 0) m_index = 0;
}
void push(T value) {
drop(m_frame[0]);
v_move(m_frame, m_frame+1, P::m_size-1);
m_frame[P::m_size-1] = value;
put(value);
}
T get() const {
return m_sorted[m_index];
}
void reset() {
v_zero(m_frame, P::m_size);
v_zero(m_sorted, P::m_size);
}
private:
T *const m_frame;
T *const m_sorted;
T *const m_sortend;
int m_index;
void put(T value) {
// precondition: m_sorted contains m_size-1 values, packed at start
// postcondition: m_sorted contains m_size values, one of which is value
T *index = std::lower_bound(m_sorted, m_sortend, value);
v_move(index + 1, index, m_sortend - index);
*index = value;
}
void drop(T value) {
// precondition: m_sorted contains m_size values, one of which is value
// postcondition: m_sorted contains m_size-1 values, packed at start
T *index = std::lower_bound(m_sorted, m_sortend + 1, value);
assert(*index == value);
v_move(index, index + 1, m_sortend - index);
*m_sortend = T(0);
}
};
}
#endif

View File

@@ -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-2009 Chris Cannam. Copyright 2007-2010 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,12 +18,13 @@
#include "system/VectorOps.h" #include "system/VectorOps.h"
#include <cmath> #include <cmath>
#include <iostream>
namespace RubberBand namespace RubberBand
{ {
PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurveCalculator(sampleRate, windowSize) PercussiveAudioCurve::PercussiveAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters)
{ {
m_prevMag = allocate_and_zero<double>(m_windowSize/2 + 1); m_prevMag = allocate_and_zero<double>(m_windowSize/2 + 1);
} }
@@ -40,26 +41,29 @@ PercussiveAudioCurve::reset()
} }
void void
PercussiveAudioCurve::setWindowSize(size_t newSize) PercussiveAudioCurve::setWindowSize(int newSize)
{ {
m_prevMag = reallocate(m_prevMag, m_windowSize, newSize); m_prevMag = reallocate(m_prevMag, m_windowSize, newSize);
m_windowSize = newSize; AudioCurveCalculator::setWindowSize(newSize);
reset(); reset();
} }
float float
PercussiveAudioCurve::processFloat(const float *R__ mag, size_t increment) PercussiveAudioCurve::processFloat(const float *R__ mag, int increment)
{ {
static float threshold = powf(10.f, 0.15f); // 3dB rise in square of magnitude static float threshold = powf(10.f, 0.15f); // 3dB rise in square of magnitude
static float zeroThresh = powf(10.f, -8); static float zeroThresh = powf(10.f, -8);
size_t count = 0; int count = 0;
size_t nonZeroCount = 0; int nonZeroCount = 0;
const int sz = m_windowSize / 2; const int sz = m_lastPerceivedBin;
for (int n = 1; n <= sz; ++n) { for (int n = 1; n <= sz; ++n) {
bool above = ((mag[n] / m_prevMag[n]) >= threshold); float v = 0.f;
if (m_prevMag[n] > zeroThresh) v = mag[n] / m_prevMag[n];
else if (mag[n] > zeroThresh) v = threshold;
bool above = (v >= threshold);
if (above) ++count; if (above) ++count;
if (mag[n] > zeroThresh) ++nonZeroCount; if (mag[n] > zeroThresh) ++nonZeroCount;
} }
@@ -71,18 +75,21 @@ PercussiveAudioCurve::processFloat(const float *R__ mag, size_t increment)
} }
double double
PercussiveAudioCurve::processDouble(const double *R__ mag, size_t increment) PercussiveAudioCurve::processDouble(const double *R__ mag, int increment)
{ {
static double threshold = powf(10., 0.15); // 3dB rise in square of magnitude static double threshold = powf(10., 0.15); // 3dB rise in square of magnitude
static double zeroThresh = powf(10., -8); static double zeroThresh = powf(10., -8);
size_t count = 0; int count = 0;
size_t nonZeroCount = 0; int nonZeroCount = 0;
const int sz = m_windowSize / 2; const int sz = m_lastPerceivedBin;
for (int n = 1; n <= sz; ++n) { for (int n = 1; n <= sz; ++n) {
bool above = ((mag[n] / m_prevMag[n]) >= threshold); double v = 0.0;
if (m_prevMag[n] > zeroThresh) v = mag[n] / m_prevMag[n];
else if (mag[n] > zeroThresh) v = threshold;
bool above = (v >= threshold);
if (above) ++count; if (above) ++count;
if (mag[n] > zeroThresh) ++nonZeroCount; if (mag[n] > zeroThresh) ++nonZeroCount;
} }

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-2009 Chris Cannam. Copyright 2007-2010 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,17 +23,18 @@ namespace RubberBand
class PercussiveAudioCurve : public AudioCurveCalculator class PercussiveAudioCurve : public AudioCurveCalculator
{ {
public: public:
PercussiveAudioCurve(size_t sampleRate, size_t windowSize); PercussiveAudioCurve(Parameters parameters);
virtual ~PercussiveAudioCurve(); virtual ~PercussiveAudioCurve();
virtual void setWindowSize(size_t newSize); virtual void setWindowSize(int newSize);
virtual float processFloat(const float *R__ mag, size_t increment); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, size_t increment); virtual double processDouble(const double *R__ mag, int increment);
virtual void reset(); virtual void reset();
virtual const char *getUnit() const { return "bin/total"; }
protected: protected:
double *R__ m_prevMag; double *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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -39,6 +39,12 @@ public:
int incount, int incount,
float ratio, float ratio,
bool final) = 0; bool final) = 0;
virtual int resampleInterleaved(const float *const R__ in,
float *const R__ out,
int incount,
float ratio,
bool final) = 0;
virtual int getChannelCount() const = 0; virtual int getChannelCount() const = 0;
@@ -62,6 +68,12 @@ public:
float ratio, float ratio,
bool final); bool final);
int resampleInterleaved(const float *const R__ in,
float *const R__ out,
int incount,
float ratio,
bool final = false);
int getChannelCount() const { return m_channels; } int getChannelCount() const { return m_channels; }
void reset(); void reset();
@@ -145,11 +157,7 @@ D_SRC::resample(const float *const R__ *const R__ in,
m_iout = reallocate<float>(m_iout, m_ioutsize, outcount * m_channels); m_iout = reallocate<float>(m_iout, m_ioutsize, outcount * m_channels);
m_ioutsize = outcount * m_channels; m_ioutsize = outcount * m_channels;
} }
for (int i = 0; i < incount; ++i) { v_interleave(m_iin, in, m_channels, incount);
for (int c = 0; c < m_channels; ++c) {
m_iin[i * m_channels + c] = in[c][i];
}
}
data.data_in = m_iin; data.data_in = m_iin;
data.data_out = m_iout; data.data_out = m_iout;
} }
@@ -168,11 +176,39 @@ D_SRC::resample(const float *const R__ *const R__ in,
} }
if (m_channels > 1) { if (m_channels > 1) {
for (int i = 0; i < data.output_frames_gen; ++i) { v_deinterleave(out, m_iout, m_channels, data.output_frames_gen);
for (int c = 0; c < m_channels; ++c) { }
out[c][i] = m_iout[i * m_channels + c];
} m_lastRatio = ratio;
}
return data.output_frames_gen;
}
int
D_SRC::resampleInterleaved(const float *const R__ in,
float *const R__ out,
int incount,
float ratio,
bool final)
{
SRC_DATA data;
int outcount = lrintf(ceilf(incount * ratio));
data.data_in = const_cast<float *>(in);
data.data_out = out;
data.input_frames = incount;
data.output_frames = outcount;
data.src_ratio = ratio;
data.end_of_input = (final ? 1 : 0);
int err = src_process(m_src, &data);
if (err) {
std::cerr << "Resampler::process: libsamplerate error: "
<< src_strerror(err) << std::endl;
throw Resampler::ImplementationError; //!!! of course, need to catch this!
} }
m_lastRatio = ratio; m_lastRatio = ratio;
@@ -252,6 +288,15 @@ Resampler::resample(const float *const R__ *const R__ in,
return d->resample(in, out, incount, ratio, final); return d->resample(in, out, incount, ratio, final);
} }
int
Resampler::resampleInterleaved(const float *const R__ in,
float *const R__ out,
int incount, float ratio, bool final)
{
Profiler profiler("Resampler::resample");
return d->resampleInterleaved(in, out, incount, ratio, final);
}
int int
Resampler::getChannelCount() const Resampler::getChannelCount() const
{ {

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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -37,12 +37,29 @@ public:
int debugLevel = 0); int debugLevel = 0);
~Resampler(); ~Resampler();
/**
* Resample the given multi-channel buffers, where incount is the
* number of frames in the input buffers. Returns the number of
* frames written to the output buffers.
*/
int resample(const float *const R__ *const R__ in, int resample(const float *const R__ *const R__ in,
float *const R__ *const R__ out, float *const R__ *const R__ out,
int incount, int incount,
float ratio, float ratio,
bool final = false); bool final = false);
/**
* Resample the given interleaved buffer, where incount is the
* number of frames in the input buffer (i.e. it has incount *
* getChannelCount() samples). Returns the number of frames
* written to the output buffer.
*/
int resampleInterleaved(const float *const R__ in,
float *const R__ out,
int incount,
float ratio,
bool final = false);
int getChannelCount() const; int getChannelCount() const;
void reset(); void reset();

50
src/dsp/SampleFilter.h Normal file
View File

@@ -0,0 +1,50 @@
/* -*- 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-2010 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 _SAMPLE_FILTER_H_
#define _SAMPLE_FILTER_H_
#include <cassert>
namespace RubberBand
{
template <typename T>
class SampleFilter
{
public:
SampleFilter(int size) : m_size(size) {
assert(m_size > 0);
}
virtual ~SampleFilter() { }
int getSize() const { return m_size; }
virtual void push(T) = 0;
virtual T get() const = 0;
virtual void reset() = 0;
protected:
const int m_size;
private:
SampleFilter(const SampleFilter &);
SampleFilter &operator=(const SampleFilter &);
};
}
#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-2009 Chris Cannam. Copyright 2007-2010 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,8 +19,9 @@
namespace RubberBand namespace RubberBand
{ {
SilentAudioCurve::SilentAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurveCalculator(sampleRate, windowSize) SilentAudioCurve::SilentAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters)
{ {
} }
@@ -33,16 +34,10 @@ SilentAudioCurve::reset()
{ {
} }
void
SilentAudioCurve::setWindowSize(size_t newSize)
{
m_windowSize = newSize;
}
float float
SilentAudioCurve::processFloat(const float *R__ mag, size_t) SilentAudioCurve::processFloat(const float *R__ mag, int)
{ {
const int hs = m_windowSize / 2; const int hs = m_lastPerceivedBin;
static float threshold = powf(10.f, -6); static float threshold = powf(10.f, -6);
for (int i = 0; i <= hs; ++i) { for (int i = 0; i <= hs; ++i) {
@@ -53,9 +48,9 @@ SilentAudioCurve::processFloat(const float *R__ mag, size_t)
} }
double double
SilentAudioCurve::processDouble(const double *R__ mag, size_t) SilentAudioCurve::processDouble(const double *R__ mag, int)
{ {
const int hs = m_windowSize / 2; const int hs = m_lastPerceivedBin;
static double threshold = pow(10.0, -6); static double threshold = pow(10.0, -6);
for (int i = 0; i <= hs; ++i) { for (int i = 0; i <= hs; ++i) {

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-2009 Chris Cannam. Copyright 2007-2010 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,14 +23,13 @@ namespace RubberBand
class SilentAudioCurve : public AudioCurveCalculator class SilentAudioCurve : public AudioCurveCalculator
{ {
public: public:
SilentAudioCurve(size_t sampleRate, size_t windowSize); SilentAudioCurve(Parameters parameters);
virtual ~SilentAudioCurve(); virtual ~SilentAudioCurve();
virtual void setWindowSize(size_t newSize); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual void reset(); virtual void reset();
virtual const char *getUnit() const { return "bool"; }
}; };
} }

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-2009 Chris Cannam. Copyright 2007-2010 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,12 +20,13 @@
namespace RubberBand namespace RubberBand
{ {
SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize) :
AudioCurveCalculator(sampleRate, windowSize) SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(Parameters parameters) :
AudioCurveCalculator(parameters)
{ {
m_mag = allocate<double>(m_windowSize/2 + 1); m_mag = allocate<double>(m_lastPerceivedBin + 1);
m_tmpbuf = allocate<double>(m_windowSize/2 + 1); m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
v_zero(m_mag, m_windowSize/2 + 1); v_zero(m_mag, m_lastPerceivedBin + 1);
} }
SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve() SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
@@ -37,26 +38,26 @@ SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
void void
SpectralDifferenceAudioCurve::reset() SpectralDifferenceAudioCurve::reset()
{ {
v_zero(m_mag, m_windowSize/2 + 1); v_zero(m_mag, m_lastPerceivedBin + 1);
} }
void void
SpectralDifferenceAudioCurve::setWindowSize(size_t newSize) SpectralDifferenceAudioCurve::setWindowSize(int newSize)
{ {
deallocate(m_tmpbuf); deallocate(m_tmpbuf);
deallocate(m_mag); deallocate(m_mag);
m_windowSize = newSize; AudioCurveCalculator::setWindowSize(newSize);
m_mag = allocate<double>(m_windowSize/2 + 1); m_mag = allocate<double>(m_lastPerceivedBin + 1);
m_tmpbuf = allocate<double>(m_windowSize/2 + 1); m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
reset(); reset();
} }
float float
SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, size_t increment) SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, int increment)
{ {
double result = 0.0; double result = 0.0;
const int hs1 = m_windowSize/2 + 1; const int hs1 = m_lastPerceivedBin + 1;
v_convert(m_tmpbuf, mag, hs1); v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1); v_square(m_tmpbuf, hs1);
@@ -73,11 +74,11 @@ SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, size_t incremen
} }
double double
SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, size_t increment) SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, int increment)
{ {
double result = 0.0; double result = 0.0;
const int hs1 = m_windowSize/2 + 1; const int hs1 = m_lastPerceivedBin + 1;
v_convert(m_tmpbuf, mag, hs1); v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1); v_square(m_tmpbuf, hs1);

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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -24,15 +24,16 @@ namespace RubberBand
class SpectralDifferenceAudioCurve : public AudioCurveCalculator class SpectralDifferenceAudioCurve : public AudioCurveCalculator
{ {
public: public:
SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize); SpectralDifferenceAudioCurve(Parameters parameters);
virtual ~SpectralDifferenceAudioCurve(); virtual ~SpectralDifferenceAudioCurve();
virtual void setWindowSize(size_t newSize); virtual void setWindowSize(int newSize);
virtual float processFloat(const float *R__ mag, size_t increment); virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, size_t increment); virtual double processDouble(const double *R__ mag, int increment);
virtual void reset(); virtual void reset();
virtual const char *getUnit() const { return "V"; }
protected: protected:
double *R__ m_mag; double *R__ m_mag;

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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -153,7 +153,7 @@ void Window<T>::encache()
m_cache = mult; m_cache = mult;
m_area = 0; m_area = 0;
for (int i = 0; i < n; ++i) { for (i = 0; i < n; ++i) {
m_area += m_cache[i]; m_area += m_cache[i];
} }
m_area /= n; m_area /= n;

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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -74,6 +74,11 @@ void rubberband_set_transients_option(RubberBandState state, RubberBandOptions o
state->m_s->setTransientsOption(options); state->m_s->setTransientsOption(options);
} }
void rubberband_set_detector_option(RubberBandState state, RubberBandOptions options)
{
state->m_s->setDetectorOption(options);
}
void rubberband_set_phase_option(RubberBandState state, RubberBandOptions options) void rubberband_set_phase_option(RubberBandState state, RubberBandOptions options)
{ {
state->m_s->setPhaseOption(options); state->m_s->setPhaseOption(options);
@@ -104,6 +109,15 @@ void rubberband_set_max_process_size(RubberBandState state, unsigned int samples
state->m_s->setMaxProcessSize(samples); state->m_s->setMaxProcessSize(samples);
} }
void rubberband_set_key_frame_map(RubberBandState state, unsigned int keyframecount, unsigned int *from, unsigned int *to)
{
std::map<size_t, size_t> kfm;
for (unsigned int i = 0; i < keyframecount; ++i) {
kfm[from[i]] = to[i];
}
state->m_s->setKeyFrameMap(kfm);
}
void rubberband_study(RubberBandState state, const float *const *input, unsigned int samples, int final) void rubberband_study(RubberBandState state, const float *const *input, unsigned int samples, int final)
{ {
state->m_s->study(input, samples, final != 0); state->m_s->study(input, samples, final != 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -134,13 +134,32 @@ T **reallocate_channels(T **ptr,
try { try {
newptr = allocate_channels<T>(channels, count); newptr = allocate_channels<T>(channels, count);
} catch (std::bad_alloc) { } catch (std::bad_alloc) {
if (ptr) deallocate_channels<T>(ptr); if (ptr) deallocate_channels<T>(ptr, channels);
throw; throw;
} }
if (oldcount && ptr) { if (oldcount && ptr) {
v_copy_channels(newptr, ptr, channels, oldcount < count ? oldcount : count); v_copy_channels(newptr, ptr, channels, oldcount < count ? oldcount : count);
} }
if (ptr) deallocate_channels<T>(ptr); if (ptr) deallocate_channels<T>(ptr, channels);
return newptr;
}
template <typename T>
T **reallocate_and_zero_extend_channels(T **ptr,
size_t oldchannels, size_t oldcount,
size_t channels, size_t count)
{
T **newptr = 0;
try {
newptr = allocate_and_zero_channels<T>(channels, count);
} catch (std::bad_alloc) {
if (ptr) deallocate_channels<T>(ptr, channels);
throw;
}
if (oldcount && ptr) {
v_copy_channels(newptr, ptr, channels, oldcount < count ? oldcount : count);
}
if (ptr) deallocate_channels<T>(ptr, channels);
return newptr; return newptr;
} }

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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -80,8 +80,8 @@ inline float princargf(float a) { return modf(a + (float)M_PI, -2.f * (float)M_P
#else #else
#include <sys/mman.h> #include <sys/mman.h>
#include <stdio.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <stdio.h>
#define MLOCK(a,b) ::mlock((char *)(a),(b)) #define MLOCK(a,b) ::mlock((char *)(a),(b))
#define MUNLOCK(a,b) (::munlock((char *)(a),(b)) ? (::perror("munlock failed"), 0) : 0) #define MUNLOCK(a,b) (::munlock((char *)(a),(b)) ? (::perror("munlock failed"), 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-2009 Chris Cannam. Copyright 2007-2010 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
@@ -300,7 +300,7 @@ RubberBandVampPlugin::getParameterDescriptors() const
d.isQuantized = true; d.isQuantized = true;
d.quantizeStep = 1; d.quantizeStep = 1;
d.valueNames.clear(); d.valueNames.clear();
d.valueNames.push_back("Peak Locked"); d.valueNames.push_back("Laminar");
d.valueNames.push_back("Independent"); d.valueNames.push_back("Independent");
list.push_back(d); list.push_back(d);
@@ -405,8 +405,6 @@ RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockS
void void
RubberBandVampPlugin::reset() RubberBandVampPlugin::reset()
{ {
// delete m_stretcher; //!!! or just if (m_stretcher) m_stretcher->reset();
// m_stretcher = new RubberBand::RubberBandStretcher(lrintf(m_inputSampleRate), channels);
if (m_d->m_stretcher) m_d->m_stretcher->reset(); if (m_d->m_stretcher) m_d->m_stretcher->reset();
} }
@@ -455,9 +453,7 @@ RubberBandVampPlugin::Impl::getRemainingFeaturesOffline()
int rate = m_sampleRate; int rate = m_sampleRate;
RubberBand::StretchCalculator sc(rate, RubberBand::StretchCalculator sc(rate, m_stretcher->getInputIncrement(), true);
m_stretcher->getInputIncrement(),
true);
size_t inputIncrement = m_stretcher->getInputIncrement(); size_t inputIncrement = m_stretcher->getInputIncrement();
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements(); std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();

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-2009 Chris Cannam. Copyright 2007-2010 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-2009 Chris Cannam. Copyright 2007-2010 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