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
* 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
* 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
less variation in CPU usage
* The code is more amenable to compiler auto-vectorization (through

View File

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

View File

@@ -4,7 +4,7 @@ Rubber Band
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.
@@ -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.
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

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -20,6 +20,9 @@
#include <time.h>
#include <cstdlib>
#include <cstring>
#include <string>
#include <fstream>
#include "system/sysutils.h"
@@ -87,12 +90,20 @@ int main(int argc, char **argv)
bool haveRatio = false;
std::string mapfile;
enum {
NoTransients,
BandLimitedTransients,
Transients
} transients = Transients;
enum {
CompoundDetector,
PercussiveDetector,
SoftDetector
} detector = CompoundDetector;
while (1) {
int optionIndex = 0;
@@ -116,13 +127,18 @@ int main(int argc, char **argv)
{ "window-long", 0, 0, '3' },
{ "window-short", 0, 0, '4' },
{ "bl-transients", 0, 0, '8' },
{ "detector-perc", 0, 0, '5' },
{ "detector-soft", 0, 0, '6' },
{ "pitch-hq", 0, 0, '%' },
{ "threads", 0, 0, '@' },
{ "quiet", 0, 0, 'q' },
{ "timemap", 1, 0, 'M' },
{ 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;
switch (c) {
@@ -143,10 +159,13 @@ int main(int argc, char **argv)
case '2': lamination = false; crispchanged = true; break;
case '3': longwin = 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 '%': hqpitch = true; break;
case 'c': crispness = atoi(optarg); break;
case 'q': quiet = true; break;
case 'M': mapfile = optarg; break;
default: help = true; break;
}
}
@@ -160,7 +179,7 @@ int main(int argc, char **argv)
cerr << endl;
cerr << "Rubber Band" << 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 << " Usage: " << argv[0] << " [options] <infile.wav> <outfile.wav>" << 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 << " -f<X>, --frequency <X> Change frequency by multiple X" << 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 << "for more details." << 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 << 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 << " --window-long Use longer processing window (actual size may vary)" << 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 << 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 << "\"Crispness\" levels:" << 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 2 equivalent to --no-transients" << endl;
cerr << " -c 3 equivalent to --bl-transients" << endl;
cerr << " -c 4 default processing options" << endl;
cerr << " -c 5 equivalent to --no-lamination --window-short (may be good for drums)" << endl;
cerr << " -c 1 equivalent to --detector-soft --no-lamination --window-long (for piano)" << endl;
cerr << " -c 2 equivalent to --no-transients --no-lamination" << endl;
cerr << " -c 3 equivalent to --no-transients" << endl;
cerr << " -c 4 equivalent to --bl-transients" << 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;
return 2;
}
@@ -220,28 +249,68 @@ int main(int argc, char **argv)
}
switch (crispness) {
case -1: crispness = 4; break;
case 0: transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
case 1: transients = NoTransients; lamination = false; longwin = false; shortwin = false; break;
case 2: transients = NoTransients; lamination = true; longwin = false; shortwin = false; break;
case 3: transients = BandLimitedTransients; lamination = true; longwin = false; shortwin = false; break;
case 4: transients = Transients; lamination = true; longwin = false; shortwin = false; break;
case 5: transients = Transients; lamination = false; longwin = false; shortwin = true; break;
case -1: crispness = 5; break;
case 0: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
case 1: detector = SoftDetector; transients = Transients; lamination = false; longwin = true; shortwin = false; break;
case 2: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = false; shortwin = false; break;
case 3: detector = CompoundDetector; transients = NoTransients; lamination = true; longwin = false; shortwin = false; break;
case 4: detector = CompoundDetector; transients = BandLimitedTransients; lamination = true; longwin = false; shortwin = false; 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) {
cerr << "Using crispness level: " << crispness << " (";
switch (crispness) {
case 0: cerr << "Mushy"; break;
case 1: cerr << "Smooth"; break;
case 2: cerr << "Balanced multitimbral mixture"; break;
case 3: cerr << "Unpitched percussion with stable notes"; break;
case 4: cerr << "Crisp monophonic instrumental"; break;
case 5: cerr << "Unpitched solo percussion"; break;
case 1: cerr << "Piano"; break;
case 2: cerr << "Smooth"; break;
case 3: cerr << "Balanced multitimbral mixture"; break;
case 4: cerr << "Unpitched percussion with stable notes"; break;
case 5: cerr << "Crisp monophonic instrumental"; break;
case 6: cerr << "Unpitched solo percussion"; break;
}
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 *fileNameOut = strdup(argv[optind++]);
@@ -317,6 +386,18 @@ int main(int argc, char **argv)
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) {
frequencyshift *= pow(2.0, pitchshift / 12);
}
@@ -390,6 +471,10 @@ int main(int argc, char **argv)
frame = 0;
percent = 0;
if (!mapping.empty()) {
ts.setKeyFrameMap(mapping);
}
size_t countIn = 0, countOut = 0;
while (frame < sfinfo.frames) {

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -15,11 +15,12 @@
#ifndef _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_MINOR_VERSION 1
#define RUBBERBAND_API_MINOR_VERSION 3
#include <vector>
#include <map>
/**
* @mainpage RubberBand
@@ -123,7 +124,25 @@ public:
* but may be less clear than with either of the other
* 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
* during non-transient segments. These options may be changed at
* any time.
@@ -138,7 +157,7 @@ public:
* frequency bin independently from its neighbours. This
* 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
* construction.
*
@@ -154,7 +173,7 @@ public:
* situation where \c OptionThreadingAuto would do so, except omit
* 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
* many factors, but it can be influenced. These options may not
* be changed after construction.
@@ -172,7 +191,7 @@ public:
* likely to result in a smoother sound at the expense of
* 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
* options may be changed at any time.
*
@@ -185,7 +204,7 @@ public:
* note frequency without so substantially affecting the
* perceived pitch profile of the voice or instrument.
*
* 8. Flags prefixed \c OptionPitch control the method used for
* 9. Flags prefixed \c OptionPitch control the method used for
* pitch shifting. These options may be changed at any time.
* They are only effective in realtime mode; in offline mode, the
* pitch-shift method is fixed.
@@ -219,6 +238,10 @@ public:
OptionTransientsMixed = 0x00000100,
OptionTransientsSmooth = 0x00000200,
OptionDetectorCompound = 0x00000000,
OptionDetectorPercussive = 0x00000400,
OptionDetectorSoft = 0x00000800,
OptionPhaseLaminar = 0x00000000,
OptionPhaseIndependent = 0x00002000,
@@ -348,6 +371,14 @@ public:
*/
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
* called at any time in any mode.
@@ -416,6 +447,32 @@ public:
*/
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
* study and calculate a stretch profile from.

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -19,9 +19,9 @@
extern "C" {
#endif
#define RUBBERBAND_VERSION "1.4.0-gpl"
#define RUBBERBAND_VERSION "1.5.0-gpl"
#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.
@@ -48,6 +48,10 @@ enum RubberBandOption {
RubberBandOptionTransientsMixed = 0x00000100,
RubberBandOptionTransientsSmooth = 0x00000200,
RubberBandOptionDetectorCompound = 0x00000000,
RubberBandOptionDetectorPercussive = 0x00000400,
RubberBandOptionDetectorSoft = 0x00000800,
RubberBandOptionPhaseLaminar = 0x00000000,
RubberBandOptionPhaseIndependent = 0x00002000,
@@ -91,6 +95,7 @@ extern double rubberband_get_pitch_scale(const RubberBandState);
extern unsigned int rubberband_get_latency(const RubberBandState);
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_formant_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 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_process(RubberBandState, const float *const *input, unsigned int samples, int final);

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -74,6 +74,12 @@ RubberBandStretcher::setTransientsOption(Options options)
m_d->setTransientsOption(options);
}
void
RubberBandStretcher::setDetectorOption(Options options)
{
m_d->setDetectorOption(options);
}
void
RubberBandStretcher::setPhaseOption(Options options)
{
@@ -104,6 +110,12 @@ RubberBandStretcher::setMaxProcessSize(size_t samples)
m_d->setMaxProcessSize(samples);
}
void
RubberBandStretcher::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
{
m_d->setKeyFrameMap(mapping);
}
size_t
RubberBandStretcher::getSamplesRequired() const
{

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
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>
StretchCalculator::calculate(double ratio, size_t inputDuration,
const std::vector<float> &phaseResetDf,
@@ -52,11 +67,9 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
{
assert(phaseResetDf.size() == stretchDf.size());
m_lastPeaks = findPeaks(phaseResetDf);
std::vector<Peak> &peaks = m_lastPeaks;
size_t totalCount = phaseResetDf.size();
m_peaks = findPeaks(phaseResetDf);
std::vector<int> increments;
size_t totalCount = phaseResetDf.size();
size_t outputDuration = lrint(inputDuration * ratio);
@@ -68,14 +81,13 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
if (m_debugLevel > 0) {
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;
for (size_t i = 0; i < peaks.size(); ++i) {
fixedAudioChunks.push_back
(lrint((double(peaks[i].chunk) * outputDuration) / totalCount));
}
std::vector<Peak> peaks; // peak position (in chunks) and hardness
std::vector<size_t> targets; // targets for mapping peaks (in samples)
mapPeaks(peaks, targets, outputDuration, totalCount);
if (m_debugLevel > 1) {
std::cerr << "have " << peaks.size() << " fixed positions" << std::endl;
@@ -93,6 +105,8 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
size_t regionTotalChunks = 0;
std::vector<int> increments;
for (size_t i = 0; i <= peaks.size(); ++i) {
size_t regionStart, regionStartChunk, regionEnd, regionEndChunk;
@@ -103,18 +117,24 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
regionStart = 0;
} else {
regionStartChunk = peaks[i-1].chunk;
regionStart = fixedAudioChunks[i-1];
regionStart = targets[i-1];
phaseReset = peaks[i-1].hard;
}
if (i == peaks.size()) {
// std::cerr << "note: i (=" << i << ") == peaks.size(); regionEndChunk " << regionEndChunk << " -> " << totalCount << ", regionEnd " << regionEnd << " -> " << outputDuration << std::endl;
regionEndChunk = totalCount;
regionEnd = outputDuration;
} else {
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;
regionTotalChunks += regionDuration;
@@ -125,7 +145,7 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
}
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);
@@ -149,7 +169,7 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
}
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;
@@ -163,6 +183,131 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
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
StretchCalculator::calculateSingle(double ratio,
float df,
@@ -182,7 +327,7 @@ StretchCalculator::calculateSingle(double ratio,
// works well in common situations.
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) {
isTransient = true;
@@ -200,8 +345,7 @@ StretchCalculator::calculateSingle(double ratio,
if (isTransient && m_transientAmnesty == 0) {
if (m_debugLevel > 1) {
std::cerr << "StretchCalculator::calculateSingle: transient"
<< std::endl;
std::cerr << "StretchCalculator::calculateSingle: transient (df " << df << ", threshold " << transientThreshold << ")" << std::endl;
}
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());
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;
@@ -651,22 +795,24 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
// then we need to adjust and accommodate
bool acceptableSquashRange = false;
double totalDisplacement = 0;
double maxDisplacement = 0; // min displacement will be 0 by definition
maxDf = 0;
float adj = 0;
bool tooShort = true, tooLong = true;
const int acceptableIterations = 10;
int iteration = 0;
int prevExtreme = 0;
bool better = false;
while (!acceptableSquashRange && iteration < acceptableIterations) {
while ((tooLong || tooShort) && iteration < acceptableIterations) {
++iteration;
acceptableSquashRange = true;
tooLong = false;
tooShort = false;
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
adj);
@@ -678,35 +824,61 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
// Not usually a problem, in fact
// std::cerr << "WARNING: totalDisplacement == 0 (duration " << duration << ", " << df.size() << " values in df)" << std::endl;
if (!df.empty() && adj == 0) {
acceptableSquashRange = false;
tooLong = true; tooShort = true;
adj = 1;
}
continue;
}
int extremeIncrement = m_increment + lrint((toAllot * maxDisplacement) / totalDisplacement);
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;
}
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;
int extremeIncrement = m_increment +
lrint((toAllot * maxDisplacement) / totalDisplacement);
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
// the total displacement, yet ensure that the
// displacements still sum to the total.
@@ -714,9 +886,24 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
}
}
if (!acceptableSquashRange) {
std::cerr << "WARNING: No acceptable displacement adjustment found, using defaults:\nthis region will probably sound bad" << std::endl;
adj = 0;
if (tooLong) {
if (better) {
// 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,
adj);
}
@@ -728,6 +915,9 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
else displacement += adj;
if (i == 0 && phaseReset) {
if (m_debugLevel > 2) {
std::cerr << "Phase reset at first chunk" << std::endl;
}
if (df.size() == 1) {
increments.push_back(duration);
totalIncrement += duration;
@@ -749,19 +939,23 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
int increment = m_increment + allotment;
if (increment <= 0) {
if (increment < 0) {
// this is a serious problem, the allocation is quite
// 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;
toAllot += m_increment;
increment = 0;
allotment = increment - m_increment;
} else {
toAllot -= allotment;
}
increments.push_back(increment);
totalIncrement += increment;
toAllot -= allotment;
totalDisplacement -= displacement;
if (m_debugLevel > 2) {

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <vector>
#include <map>
namespace RubberBand
{
@@ -28,6 +29,15 @@ public:
StretchCalculator(size_t sampleRate, size_t inputIncrement, bool useHardPeaks);
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
* overall target stretch ratio, input duration in audio samples,
@@ -35,9 +45,9 @@ public:
* (lockAudioCurve) and for allocating stretches to relatively
* less prominent points (stretchAudioCurve).
*/
virtual std::vector<int> calculate(double ratio, size_t inputDuration,
const std::vector<float> &lockAudioCurve,
const std::vector<float> &stretchAudioCurve);
std::vector<int> calculate(double ratio, size_t inputDuration,
const std::vector<float> &lockAudioCurve,
const std::vector<float> &stretchAudioCurve);
/**
* 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
* this block in preference to m_increment.
*/
virtual int calculateSingle(double ratio, float curveValue,
size_t increment = 0);
int calculateSingle(double ratio, float curveValue,
size_t increment = 0);
void setUseHardPeaks(bool use) { m_useHardPeaks = use; }
@@ -62,13 +72,16 @@ public:
size_t chunk;
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);
protected:
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,
size_t outputDuration, float ratio,
bool phaseReset);
@@ -90,7 +103,8 @@ protected:
int m_debugLevel;
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
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -21,11 +21,11 @@
//#define EXPERIMENT 1
namespace RubberBand { class Resampler; }
namespace RubberBand
{
class Resampler;
class RubberBandStretcher::Impl::ChannelData
{
public:

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -19,6 +19,7 @@
#include "dsp/SpectralDifferenceAudioCurve.h"
#include "dsp/SilentAudioCurve.h"
#include "dsp/ConstantAudioCurve.h"
#include "dsp/CompoundAudioCurve.h"
#include "dsp/Resampler.h"
#include "StretchCalculator.h"
@@ -81,9 +82,11 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_studyFFT(0),
m_spaceAvailable("space"),
m_inputDuration(0),
m_detectorType(CompoundAudioCurve::CompoundDetector),
m_silentHistory(0),
m_lastProcessOutputIncrements(16),
m_lastProcessPhaseResetDf(16),
m_emergencyScavenger(10, 4),
m_phaseResetAudioCurve(0),
m_stretchAudioCurve(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
// we don't let it drop below the 48k default
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));
if ((options & OptionWindowShort) || (options & OptionWindowLong)) {
@@ -205,6 +208,12 @@ RubberBandStretcher::Impl::reset()
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) {
m_channelData[c]->reset();
}
@@ -299,6 +308,24 @@ RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
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
RubberBandStretcher::Impl::getFrequencyCutoff(int n) const
{
@@ -399,7 +426,7 @@ RubberBandStretcher::Impl::calculateSizes()
float windowIncrRatio = 4.5;
if (r == 1.0) windowIncrRatio = 4;
else if (rsb) windowIncrRatio = 4.5;
else windowIncrRatio = 6;
else windowIncrRatio = 8;
outputIncrement = int(windowSize / windowIncrRatio);
inputIncrement = int(outputIncrement / r);
@@ -598,21 +625,22 @@ RubberBandStretcher::Impl::configure()
// modes
delete m_phaseResetAudioCurve;
m_phaseResetAudioCurve = new PercussiveAudioCurve
(m_sampleRate, m_windowSize);
m_phaseResetAudioCurve = new CompoundAudioCurve
(CompoundAudioCurve::Parameters(m_sampleRate, m_windowSize));
m_phaseResetAudioCurve->setType(m_detectorType);
delete m_silentAudioCurve;
m_silentAudioCurve = new SilentAudioCurve
(m_sampleRate, m_windowSize);
(SilentAudioCurve::Parameters(m_sampleRate, m_windowSize));
if (!m_realtime) {
delete m_stretchAudioCurve;
if (!(m_options & OptionStretchPrecise)) {
m_stretchAudioCurve = new SpectralDifferenceAudioCurve
(m_sampleRate, m_windowSize);
(SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_windowSize));
} else {
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));
}
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
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
(getEffectiveRatio(),
inputDuration,

View File

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

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
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
// already been calculated.
// This is the normal process method in offline mode.
ChannelData &cd = *m_channelData[c];
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);
assert(got == m_windowSize || cd.inputSize >= 0);
cd.inbuf->skip(m_increment);
analyseChunk(c);
}
bool phaseReset = false;
size_t phaseIncrement, shiftIncrement;
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++;
if (m_debugLevel > 2) {
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
// 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) {
if (!testInbufReadSpace(c)) return false;
ChannelData &cd = *m_channelData[c];
@@ -383,27 +409,29 @@ 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;
int ws = cd.outbuf->getWriteSpace();
if (ws < required) {
if (m_debugLevel > 0) {
cerr << "Buffer overrun on output for channel " << c << endl;
}
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 (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.
//!!! 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.
}
RingBuffer<float> *oldbuf = cd.outbuf;
cd.outbuf = oldbuf->resized(oldbuf->getSize() + (required - ws));
m_emergencyScavenger.claim(oldbuf);
}
writeChunk(c, shiftIncrement, last);
@@ -589,12 +617,12 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
if (shiftIncrement < 0) {
shiftIncrement = -shiftIncrement;
}
/*
if (shiftIncrement >= int(m_windowSize)) {
cerr << "*** ERROR: RubberBandStretcher::Impl::processChunks: shiftIncrement " << shiftIncrement << " >= windowSize " << m_windowSize << " at " << cd.chunkCount << " (of " << m_outputIncrements.size() << ")" << endl;
shiftIncrement = m_windowSize;
}
*/
phaseIncrementRtn = phaseIncrement;
shiftIncrementRtn = shiftIncrement;
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;
}
if (m_debugLevel > 1) {
if (m_debugLevel > 2) {
cerr << "mean inheritance distance = " << distacc / count << endl;
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -14,18 +14,50 @@
#include "AudioCurveCalculator.h"
#include <iostream>
namespace RubberBand
{
AudioCurveCalculator::AudioCurveCalculator(size_t sampleRate, size_t windowSize) :
m_sampleRate(sampleRate),
m_windowSize(windowSize)
static const int MaxPerceivedFreq = 16000;
AudioCurveCalculator::AudioCurveCalculator(Parameters parameters) :
m_sampleRate(parameters.sampleRate),
m_windowSize(parameters.windowSize)
{
recalculateLastPerceivedBin();
}
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
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
modify it under the terms of the GNU General Public License as
@@ -26,28 +26,51 @@ namespace RubberBand
class AudioCurveCalculator
{
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();
size_t getSampleRate() const { return m_sampleRate; }
size_t getWindowSize() const { return m_windowSize; }
int getSampleRate() const { return m_sampleRate; }
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
// given instance
virtual float processFloat(const float *R__ mag, size_t increment) = 0;
virtual double processDouble(const double *R__ mag, size_t increment) = 0;
virtual float processFloat(const float *R__ mag, int increment) = 0;
virtual double processDouble(const double *R__ mag, int increment) = 0;
virtual void reset() = 0;
virtual const char *getUnit() const { return ""; }
protected:
size_t m_sampleRate;
size_t m_windowSize;
int m_sampleRate;
int m_windowSize;
int m_lastPerceivedBin;
void recalculateLastPerceivedBin();
};
}
#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
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
modify it under the terms of the GNU General Public License as
@@ -17,8 +17,9 @@
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
ConstantAudioCurve::processFloat(const float *R__, size_t)
ConstantAudioCurve::processFloat(const float *R__, int)
{
return 1.f;
}
double
ConstantAudioCurve::processDouble(const double *R__, size_t)
ConstantAudioCurve::processDouble(const double *R__, int)
{
return 1.0;
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -23,13 +23,11 @@ namespace RubberBand
class ConstantAudioCurve : public AudioCurveCalculator
{
public:
ConstantAudioCurve(size_t sampleRate, size_t windowSize);
ConstantAudioCurve(Parameters parameters);
virtual ~ConstantAudioCurve();
virtual void setWindowSize(size_t newSize);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual void reset();
};

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -17,8 +17,9 @@
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
HighFrequencyAudioCurve::processFloat(const float *R__ mag, size_t increment)
HighFrequencyAudioCurve::processFloat(const float *R__ mag, int increment)
{
float result = 0.0;
const int sz = m_windowSize / 2;
const int sz = m_lastPerceivedBin;
for (int n = 0; n <= sz; ++n) {
result = result + mag[n] * n;
@@ -52,11 +47,11 @@ HighFrequencyAudioCurve::processFloat(const float *R__ mag, size_t increment)
}
double
HighFrequencyAudioCurve::processDouble(const double *R__ mag, size_t increment)
HighFrequencyAudioCurve::processDouble(const double *R__ mag, int increment)
{
float result = 0.0;
const int sz = m_windowSize / 2;
const int sz = m_lastPerceivedBin;
for (int n = 0; n <= sz; ++n) {
result = result + mag[n] * n;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -23,15 +23,14 @@ namespace RubberBand
class HighFrequencyAudioCurve : public AudioCurveCalculator
{
public:
HighFrequencyAudioCurve(size_t sampleRate, size_t windowSize);
HighFrequencyAudioCurve(Parameters parameters);
virtual ~HighFrequencyAudioCurve();
virtual void setWindowSize(size_t newSize);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
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
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
modify it under the terms of the GNU General Public License as
@@ -18,12 +18,13 @@
#include "system/VectorOps.h"
#include <cmath>
#include <iostream>
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);
}
@@ -40,26 +41,29 @@ PercussiveAudioCurve::reset()
}
void
PercussiveAudioCurve::setWindowSize(size_t newSize)
PercussiveAudioCurve::setWindowSize(int newSize)
{
m_prevMag = reallocate(m_prevMag, m_windowSize, newSize);
m_windowSize = newSize;
AudioCurveCalculator::setWindowSize(newSize);
reset();
}
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 zeroThresh = powf(10.f, -8);
size_t count = 0;
size_t nonZeroCount = 0;
int count = 0;
int nonZeroCount = 0;
const int sz = m_windowSize / 2;
const int sz = m_lastPerceivedBin;
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 (mag[n] > zeroThresh) ++nonZeroCount;
}
@@ -71,18 +75,21 @@ PercussiveAudioCurve::processFloat(const float *R__ mag, size_t increment)
}
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 zeroThresh = powf(10., -8);
size_t count = 0;
size_t nonZeroCount = 0;
int count = 0;
int nonZeroCount = 0;
const int sz = m_windowSize / 2;
const int sz = m_lastPerceivedBin;
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 (mag[n] > zeroThresh) ++nonZeroCount;
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -23,17 +23,18 @@ namespace RubberBand
class PercussiveAudioCurve : public AudioCurveCalculator
{
public:
PercussiveAudioCurve(size_t sampleRate, size_t windowSize);
PercussiveAudioCurve(Parameters parameters);
virtual ~PercussiveAudioCurve();
virtual void setWindowSize(size_t newSize);
virtual void setWindowSize(int newSize);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual void reset();
virtual const char *getUnit() const { return "bin/total"; }
protected:
double *R__ m_prevMag;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -40,6 +40,12 @@ public:
float ratio,
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 void reset() = 0;
@@ -62,6 +68,12 @@ public:
float ratio,
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; }
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_ioutsize = outcount * m_channels;
}
for (int i = 0; i < incount; ++i) {
for (int c = 0; c < m_channels; ++c) {
m_iin[i * m_channels + c] = in[c][i];
}
}
v_interleave(m_iin, in, m_channels, incount);
data.data_in = m_iin;
data.data_out = m_iout;
}
@@ -168,11 +176,39 @@ D_SRC::resample(const float *const R__ *const R__ in,
}
if (m_channels > 1) {
for (int i = 0; i < data.output_frames_gen; ++i) {
for (int c = 0; c < m_channels; ++c) {
out[c][i] = m_iout[i * m_channels + c];
}
}
v_deinterleave(out, m_iout, m_channels, data.output_frames_gen);
}
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;
@@ -252,6 +288,15 @@ Resampler::resample(const float *const R__ *const R__ in,
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
Resampler::getChannelCount() const
{

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -37,12 +37,29 @@ public:
int debugLevel = 0);
~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,
float *const R__ *const R__ out,
int incount,
float ratio,
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;
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
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
modify it under the terms of the GNU General Public License as
@@ -19,8 +19,9 @@
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
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);
for (int i = 0; i <= hs; ++i) {
@@ -53,9 +48,9 @@ SilentAudioCurve::processFloat(const float *R__ mag, size_t)
}
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);
for (int i = 0; i <= hs; ++i) {

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -23,14 +23,13 @@ namespace RubberBand
class SilentAudioCurve : public AudioCurveCalculator
{
public:
SilentAudioCurve(size_t sampleRate, size_t windowSize);
SilentAudioCurve(Parameters parameters);
virtual ~SilentAudioCurve();
virtual void setWindowSize(size_t newSize);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual void reset();
virtual const char *getUnit() const { return "bool"; }
};
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -20,12 +20,13 @@
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_tmpbuf = allocate<double>(m_windowSize/2 + 1);
v_zero(m_mag, m_windowSize/2 + 1);
m_mag = allocate<double>(m_lastPerceivedBin + 1);
m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
v_zero(m_mag, m_lastPerceivedBin + 1);
}
SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
@@ -37,26 +38,26 @@ SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
void
SpectralDifferenceAudioCurve::reset()
{
v_zero(m_mag, m_windowSize/2 + 1);
v_zero(m_mag, m_lastPerceivedBin + 1);
}
void
SpectralDifferenceAudioCurve::setWindowSize(size_t newSize)
SpectralDifferenceAudioCurve::setWindowSize(int newSize)
{
deallocate(m_tmpbuf);
deallocate(m_mag);
m_windowSize = newSize;
m_mag = allocate<double>(m_windowSize/2 + 1);
m_tmpbuf = allocate<double>(m_windowSize/2 + 1);
AudioCurveCalculator::setWindowSize(newSize);
m_mag = allocate<double>(m_lastPerceivedBin + 1);
m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
reset();
}
float
SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, size_t increment)
SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, int increment)
{
double result = 0.0;
const int hs1 = m_windowSize/2 + 1;
const int hs1 = m_lastPerceivedBin + 1;
v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1);
@@ -73,11 +74,11 @@ SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, size_t incremen
}
double
SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, size_t increment)
SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, int increment)
{
double result = 0.0;
const int hs1 = m_windowSize/2 + 1;
const int hs1 = m_lastPerceivedBin + 1;
v_convert(m_tmpbuf, mag, hs1);
v_square(m_tmpbuf, hs1);

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -24,15 +24,16 @@ namespace RubberBand
class SpectralDifferenceAudioCurve : public AudioCurveCalculator
{
public:
SpectralDifferenceAudioCurve(size_t sampleRate, size_t windowSize);
SpectralDifferenceAudioCurve(Parameters parameters);
virtual ~SpectralDifferenceAudioCurve();
virtual void setWindowSize(size_t newSize);
virtual void setWindowSize(int newSize);
virtual float processFloat(const float *R__ mag, size_t increment);
virtual double processDouble(const double *R__ mag, size_t increment);
virtual float processFloat(const float *R__ mag, int increment);
virtual double processDouble(const double *R__ mag, int increment);
virtual void reset();
virtual const char *getUnit() const { return "V"; }
protected:
double *R__ m_mag;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -153,7 +153,7 @@ void Window<T>::encache()
m_cache = mult;
m_area = 0;
for (int i = 0; i < n; ++i) {
for (i = 0; i < n; ++i) {
m_area += m_cache[i];
}
m_area /= n;

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
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);
}
void rubberband_set_detector_option(RubberBandState state, RubberBandOptions options)
{
state->m_s->setDetectorOption(options);
}
void rubberband_set_phase_option(RubberBandState state, RubberBandOptions 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);
}
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)
{
state->m_s->study(input, samples, final != 0);

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -134,13 +134,32 @@ T **reallocate_channels(T **ptr,
try {
newptr = allocate_channels<T>(channels, count);
} catch (std::bad_alloc) {
if (ptr) deallocate_channels<T>(ptr);
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);
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;
}

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
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
#include <sys/mman.h>
#include <stdio.h>
#include <dlfcn.h>
#include <stdio.h>
#define MLOCK(a,b) ::mlock((char *)(a),(b))
#define MUNLOCK(a,b) (::munlock((char *)(a),(b)) ? (::perror("munlock failed"), 0) : 0)

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as
@@ -300,7 +300,7 @@ RubberBandVampPlugin::getParameterDescriptors() const
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Peak Locked");
d.valueNames.push_back("Laminar");
d.valueNames.push_back("Independent");
list.push_back(d);
@@ -405,8 +405,6 @@ RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockS
void
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();
}
@@ -455,9 +453,7 @@ RubberBandVampPlugin::Impl::getRemainingFeaturesOffline()
int rate = m_sampleRate;
RubberBand::StretchCalculator sc(rate,
m_stretcher->getInputIncrement(),
true);
RubberBand::StretchCalculator sc(rate, m_stretcher->getInputIncrement(), true);
size_t inputIncrement = m_stretcher->getInputIncrement();
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as

View File

@@ -3,7 +3,7 @@
/*
Rubber Band
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
modify it under the terms of the GNU General Public License as