From 87dc72024365decd1f9278db9f70e61dba7fe53b Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Wed, 24 Mar 2010 09:44:51 +0000 Subject: [PATCH] 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 --- CHANGELOG | 18 +- Makefile.in | 11 +- README.txt | 4 +- ladspa/RubberBandPitchShifter.cpp | 2 +- ladspa/RubberBandPitchShifter.h | 2 +- ladspa/libmain.cpp | 2 +- main/main.cpp | 127 ++++++++-- rubberband/RubberBandStretcher.h | 73 +++++- rubberband/rubberband-c.h | 12 +- src/RubberBandStretcher.cpp | 14 +- src/StretchCalculator.cpp | 294 +++++++++++++++++++---- src/StretchCalculator.h | 32 ++- src/StretcherChannelData.cpp | 2 +- src/StretcherChannelData.h | 6 +- src/StretcherImpl.cpp | 79 +++++- src/StretcherImpl.h | 12 +- src/StretcherProcess.cpp | 82 ++++--- src/base/Profiler.cpp | 2 +- src/base/Profiler.h | 2 +- src/base/RingBuffer.h | 2 +- src/base/Scavenger.h | 2 +- src/dsp/AudioCurveCalculator.cpp | 40 ++- src/dsp/AudioCurveCalculator.h | 41 +++- src/dsp/CompoundAudioCurve.cpp | 164 +++++++++++++ src/dsp/CompoundAudioCurve.h | 65 +++++ src/dsp/ConstantAudioCurve.cpp | 17 +- src/dsp/ConstantAudioCurve.h | 10 +- src/dsp/FFT.cpp | 2 +- src/dsp/FFT.h | 2 +- src/dsp/HighFrequencyAudioCurve.cpp | 21 +- src/dsp/HighFrequencyAudioCurve.h | 11 +- src/dsp/MovingMedian.h | 95 ++++++++ src/dsp/PercussiveAudioCurve.cpp | 39 +-- src/dsp/PercussiveAudioCurve.h | 11 +- src/dsp/Resampler.cpp | 67 +++++- src/dsp/Resampler.h | 19 +- src/dsp/SampleFilter.h | 50 ++++ src/dsp/SilentAudioCurve.cpp | 21 +- src/dsp/SilentAudioCurve.h | 11 +- src/dsp/SpectralDifferenceAudioCurve.cpp | 31 +-- src/dsp/SpectralDifferenceAudioCurve.h | 11 +- src/dsp/Window.h | 4 +- src/rubberband-c.cpp | 16 +- src/system/Allocators.cpp | 2 +- src/system/Allocators.h | 25 +- src/system/Thread.cpp | 2 +- src/system/Thread.h | 2 +- src/system/VectorOps.h | 2 +- src/system/sysutils.cpp | 2 +- src/system/sysutils.h | 4 +- vamp/RubberBandVampPlugin.cpp | 10 +- vamp/RubberBandVampPlugin.h | 2 +- vamp/libmain.cpp | 2 +- 53 files changed, 1287 insertions(+), 294 deletions(-) create mode 100644 src/dsp/CompoundAudioCurve.cpp create mode 100644 src/dsp/CompoundAudioCurve.h create mode 100644 src/dsp/MovingMedian.h create mode 100644 src/dsp/SampleFilter.h diff --git a/CHANGELOG b/CHANGELOG index 9b57693..60565ba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/Makefile.in b/Makefile.in index 01f2ab4..7ab25ff 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 \ diff --git a/README.txt b/README.txt index ba292d5..880be5d 100644 --- a/README.txt +++ b/README.txt @@ -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 where is from 0 to 5). +"crispness" options (-c where is from 0 to 6). Using the Rubber Band library diff --git a/ladspa/RubberBandPitchShifter.cpp b/ladspa/RubberBandPitchShifter.cpp index 88a9a1e..6380da7 100644 --- a/ladspa/RubberBandPitchShifter.cpp +++ b/ladspa/RubberBandPitchShifter.cpp @@ -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 diff --git a/ladspa/RubberBandPitchShifter.h b/ladspa/RubberBandPitchShifter.h index 6cdc615..b129086 100644 --- a/ladspa/RubberBandPitchShifter.h +++ b/ladspa/RubberBandPitchShifter.h @@ -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 diff --git a/ladspa/libmain.cpp b/ladspa/libmain.cpp index 59597d5..eef89af 100644 --- a/ladspa/libmain.cpp +++ b/ladspa/libmain.cpp @@ -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 diff --git a/main/main.cpp b/main/main.cpp index 0323bd6..cd193ed 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -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 #include #include +#include + +#include #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] " << endl; cerr << endl; @@ -174,10 +193,17 @@ int main(int argc, char **argv) cerr << " -p, --pitch Raise pitch by X semitones, or" << endl; cerr << " -f, --frequency Change frequency by multiple X" << endl; cerr << endl; + cerr << " -M, --timemap 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, --crisp Crispness (N = 0,1,2,3,4,5); default 4 (see below)" << endl; + cerr << " -c, --crisp 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, --debug 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 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); } @@ -389,6 +470,10 @@ int main(int argc, char **argv) frame = 0; percent = 0; + + if (!mapping.empty()) { + ts.setKeyFrameMap(mapping); + } size_t countIn = 0, countOut = 0; diff --git a/rubberband/RubberBandStretcher.h b/rubberband/RubberBandStretcher.h index fae5838..2cac4d1 100644 --- a/rubberband/RubberBandStretcher.h +++ b/rubberband/RubberBandStretcher.h @@ -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 +#include /** * @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 &); + /** * Provide a block of "samples" sample frames for the stretcher to * study and calculate a stretch profile from. diff --git a/rubberband/rubberband-c.h b/rubberband/rubberband-c.h index 95db61d..bd45601 100644 --- a/rubberband/rubberband-c.h +++ b/rubberband/rubberband-c.h @@ -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); diff --git a/src/RubberBandStretcher.cpp b/src/RubberBandStretcher.cpp index 2e66259..7115c97 100644 --- a/src/RubberBandStretcher.cpp +++ b/src/RubberBandStretcher.cpp @@ -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 &mapping) +{ + m_d->setKeyFrameMap(mapping); +} + size_t RubberBandStretcher::getSamplesRequired() const { diff --git a/src/StretchCalculator.cpp b/src/StretchCalculator.cpp index 5ccb7bd..015459d 100644 --- a/src/StretchCalculator.cpp +++ b/src/StretchCalculator.cpp @@ -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 &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 StretchCalculator::calculate(double ratio, size_t inputDuration, const std::vector &phaseResetDf, @@ -52,11 +67,9 @@ StretchCalculator::calculate(double ratio, size_t inputDuration, { assert(phaseResetDf.size() == stretchDf.size()); - m_lastPeaks = findPeaks(phaseResetDf); - std::vector &peaks = m_lastPeaks; - size_t totalCount = phaseResetDf.size(); + m_peaks = findPeaks(phaseResetDf); - std::vector 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 fixedAudioChunks; - for (size_t i = 0; i < peaks.size(); ++i) { - fixedAudioChunks.push_back - (lrint((double(peaks[i].chunk) * outputDuration) / totalCount)); - } + std::vector peaks; // peak position (in chunks) and hardness + std::vector 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 increments; + for (size_t i = 0; i <= peaks.size(); ++i) { size_t regionStart, regionStartChunk, regionEnd, regionEndChunk; @@ -103,17 +117,23 @@ 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 &peaks, + std::vector &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::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 <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 &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 &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; - - while (!acceptableSquashRange && iteration < acceptableIterations) { + int prevExtreme = 0; + bool better = false; + + 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 &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 &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 &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 &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) { diff --git a/src/StretchCalculator.h b/src/StretchCalculator.h index f0a5c19..c645ee6 100644 --- a/src/StretchCalculator.h +++ b/src/StretchCalculator.h @@ -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 #include +#include 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 &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 calculate(double ratio, size_t inputDuration, - const std::vector &lockAudioCurve, - const std::vector &stretchAudioCurve); + std::vector calculate(double ratio, size_t inputDuration, + const std::vector &lockAudioCurve, + const std::vector &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 getLastCalculatedPeaks() const { return m_lastPeaks; } + std::vector getLastCalculatedPeaks() const { return m_peaks; } std::vector smoothDF(const std::vector &df); protected: std::vector findPeaks(const std::vector &audioCurve); + void mapPeaks(std::vector &peaks, std::vector &targets, + size_t outputDuration, size_t totalCount); + std::vector distributeRegion(const std::vector ®ionCurve, size_t outputDuration, float ratio, bool phaseReset); @@ -89,8 +102,9 @@ protected: int m_transientAmnesty; // only in RT mode; handled differently offline int m_debugLevel; bool m_useHardPeaks; - - std::vector m_lastPeaks; + + std::map m_keyFrameMap; + std::vector m_peaks; }; } diff --git a/src/StretcherChannelData.cpp b/src/StretcherChannelData.cpp index 6b66e58..332a6c1 100644 --- a/src/StretcherChannelData.cpp +++ b/src/StretcherChannelData.cpp @@ -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 diff --git a/src/StretcherChannelData.h b/src/StretcherChannelData.h index 594e893..6f44aee 100644 --- a/src/StretcherChannelData.h +++ b/src/StretcherChannelData.h @@ -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: diff --git a/src/StretcherImpl.cpp b/src/StretcherImpl.cpp index a501318..88b6843 100644 --- a/src/StretcherImpl.cpp +++ b/src/StretcherImpl.cpp @@ -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()); + } + 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 & + 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 increments = m_stretchCalculator->calculate (getEffectiveRatio(), inputDuration, diff --git a/src/StretcherImpl.h b/src/StretcherImpl.h index abaf8ab..26bba32 100644 --- a/src/StretcherImpl.h +++ b/src/StretcherImpl.h @@ -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 getSamplesRequired() const; @@ -168,6 +170,7 @@ protected: size_t m_inputDuration; + CompoundAudioCurve::Type m_detectorType; std::vector m_phaseResetDf; std::vector m_stretchDf; std::vector m_silence; @@ -180,8 +183,9 @@ protected: mutable RingBuffer m_lastProcessOutputIncrements; mutable RingBuffer m_lastProcessPhaseResetDf; + Scavenger > m_emergencyScavenger; - AudioCurveCalculator *m_phaseResetAudioCurve; + CompoundAudioCurve *m_phaseResetAudioCurve; AudioCurveCalculator *m_stretchAudioCurve; AudioCurveCalculator *m_silentAudioCurve; StretchCalculator *m_stretchCalculator; diff --git a/src/StretcherProcess.cpp b/src/StretcherProcess.cpp index 1715baa..4e0a5df 100644 --- a/src/StretcherProcess.cpp +++ b/src/StretcherProcess.cpp @@ -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,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 (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. - - } + 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; + } + + // 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 *oldbuf = cd.outbuf; + cd.outbuf = oldbuf->resized(oldbuf->getSize() + (required - ws)); + m_emergencyScavenger.claim(oldbuf); + } + writeChunk(c, shiftIncrement, last); return 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; } diff --git a/src/base/Profiler.cpp b/src/base/Profiler.cpp index 216001b..d85f3ed 100644 --- a/src/base/Profiler.cpp +++ b/src/base/Profiler.cpp @@ -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 diff --git a/src/base/Profiler.h b/src/base/Profiler.h index d24153b..6b6d56e 100644 --- a/src/base/Profiler.h +++ b/src/base/Profiler.h @@ -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 diff --git a/src/base/RingBuffer.h b/src/base/RingBuffer.h index 330e3f7..40b5f0a 100644 --- a/src/base/RingBuffer.h +++ b/src/base/RingBuffer.h @@ -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 diff --git a/src/base/Scavenger.h b/src/base/Scavenger.h index c0b0bbb..1b9f311 100644 --- a/src/base/Scavenger.h +++ b/src/base/Scavenger.h @@ -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 diff --git a/src/dsp/AudioCurveCalculator.cpp b/src/dsp/AudioCurveCalculator.cpp index 62c1dd0..dde6dba 100644 --- a/src/dsp/AudioCurveCalculator.cpp +++ b/src/dsp/AudioCurveCalculator.cpp @@ -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 + 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; + } +} + } diff --git a/src/dsp/AudioCurveCalculator.h b/src/dsp/AudioCurveCalculator.h index fd74d08..0c0d6cc 100644 --- a/src/dsp/AudioCurveCalculator.h +++ b/src/dsp/AudioCurveCalculator.h @@ -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 diff --git a/src/dsp/CompoundAudioCurve.cpp b/src/dsp/CompoundAudioCurve.cpp new file mode 100644 index 0000000..cb44506 --- /dev/null +++ b/src/dsp/CompoundAudioCurve.cpp @@ -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 + +namespace RubberBand +{ + + +CompoundAudioCurve::CompoundAudioCurve(Parameters parameters) : + AudioCurveCalculator(parameters), + m_percussive(parameters), + m_hf(parameters), + m_hfFilter(new MovingMedian(19, 85)), + m_hfDerivFilter(new MovingMedian(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; +} + + +} + diff --git a/src/dsp/CompoundAudioCurve.h b/src/dsp/CompoundAudioCurve.h new file mode 100644 index 0000000..e7cebfc --- /dev/null +++ b/src/dsp/CompoundAudioCurve.h @@ -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 *m_hfFilter; + SampleFilter *m_hfDerivFilter; + + Type m_type; + + double m_lastHf; + double m_lastResult; + int m_risingCount; + + double processFiltering(double percussive, double hf); +}; + +} + +#endif diff --git a/src/dsp/ConstantAudioCurve.cpp b/src/dsp/ConstantAudioCurve.cpp index 5058c28..e723fd1 100644 --- a/src/dsp/ConstantAudioCurve.cpp +++ b/src/dsp/ConstantAudioCurve.cpp @@ -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; } diff --git a/src/dsp/ConstantAudioCurve.h b/src/dsp/ConstantAudioCurve.h index d710ff9..9617174 100644 --- a/src/dsp/ConstantAudioCurve.h +++ b/src/dsp/ConstantAudioCurve.h @@ -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(); }; diff --git a/src/dsp/FFT.cpp b/src/dsp/FFT.cpp index b0ca34d..eef575c 100644 --- a/src/dsp/FFT.cpp +++ b/src/dsp/FFT.cpp @@ -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 diff --git a/src/dsp/FFT.h b/src/dsp/FFT.h index 4c89afc..d90624f 100644 --- a/src/dsp/FFT.h +++ b/src/dsp/FFT.h @@ -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 diff --git a/src/dsp/HighFrequencyAudioCurve.cpp b/src/dsp/HighFrequencyAudioCurve.cpp index caf4c62..bf59b68 100644 --- a/src/dsp/HighFrequencyAudioCurve.cpp +++ b/src/dsp/HighFrequencyAudioCurve.cpp @@ -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; diff --git a/src/dsp/HighFrequencyAudioCurve.h b/src/dsp/HighFrequencyAudioCurve.h index 797e3c3..3fa7dee 100644 --- a/src/dsp/HighFrequencyAudioCurve.h +++ b/src/dsp/HighFrequencyAudioCurve.h @@ -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"; } }; } diff --git a/src/dsp/MovingMedian.h b/src/dsp/MovingMedian.h new file mode 100644 index 0000000..6e3142f --- /dev/null +++ b/src/dsp/MovingMedian.h @@ -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 + +namespace RubberBand +{ + +template +class MovingMedian : public SampleFilter +{ + typedef SampleFilter P; + +public: + MovingMedian(int size, float percentile = 50.f) : + SampleFilter(size), + m_frame(allocate_and_zero(size)), + m_sorted(allocate_and_zero(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 + diff --git a/src/dsp/PercussiveAudioCurve.cpp b/src/dsp/PercussiveAudioCurve.cpp index c4df212..113b879 100644 --- a/src/dsp/PercussiveAudioCurve.cpp +++ b/src/dsp/PercussiveAudioCurve.cpp @@ -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 - +#include namespace RubberBand { -PercussiveAudioCurve::PercussiveAudioCurve(size_t sampleRate, size_t windowSize) : - AudioCurveCalculator(sampleRate, windowSize) + +PercussiveAudioCurve::PercussiveAudioCurve(Parameters parameters) : + AudioCurveCalculator(parameters) { m_prevMag = allocate_and_zero(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; } diff --git a/src/dsp/PercussiveAudioCurve.h b/src/dsp/PercussiveAudioCurve.h index ec6c280..6028683 100644 --- a/src/dsp/PercussiveAudioCurve.h +++ b/src/dsp/PercussiveAudioCurve.h @@ -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; diff --git a/src/dsp/Resampler.cpp b/src/dsp/Resampler.cpp index de8bf90..97314a1 100644 --- a/src/dsp/Resampler.cpp +++ b/src/dsp/Resampler.cpp @@ -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 @@ -39,6 +39,12 @@ public: int incount, 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; @@ -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(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(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 { diff --git a/src/dsp/Resampler.h b/src/dsp/Resampler.h index db3026a..50645f9 100644 --- a/src/dsp/Resampler.h +++ b/src/dsp/Resampler.h @@ -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(); diff --git a/src/dsp/SampleFilter.h b/src/dsp/SampleFilter.h new file mode 100644 index 0000000..cb7d472 --- /dev/null +++ b/src/dsp/SampleFilter.h @@ -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 + +namespace RubberBand +{ + +template +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 + diff --git a/src/dsp/SilentAudioCurve.cpp b/src/dsp/SilentAudioCurve.cpp index 35f0d96..6b10e26 100644 --- a/src/dsp/SilentAudioCurve.cpp +++ b/src/dsp/SilentAudioCurve.cpp @@ -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) { diff --git a/src/dsp/SilentAudioCurve.h b/src/dsp/SilentAudioCurve.h index 4732788..bf6a8a8 100644 --- a/src/dsp/SilentAudioCurve.h +++ b/src/dsp/SilentAudioCurve.h @@ -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"; } }; } diff --git a/src/dsp/SpectralDifferenceAudioCurve.cpp b/src/dsp/SpectralDifferenceAudioCurve.cpp index 9d59c7e..4eb531e 100644 --- a/src/dsp/SpectralDifferenceAudioCurve.cpp +++ b/src/dsp/SpectralDifferenceAudioCurve.cpp @@ -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(m_windowSize/2 + 1); - m_tmpbuf = allocate(m_windowSize/2 + 1); - v_zero(m_mag, m_windowSize/2 + 1); + m_mag = allocate(m_lastPerceivedBin + 1); + m_tmpbuf = allocate(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(m_windowSize/2 + 1); - m_tmpbuf = allocate(m_windowSize/2 + 1); + AudioCurveCalculator::setWindowSize(newSize); + m_mag = allocate(m_lastPerceivedBin + 1); + m_tmpbuf = allocate(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); diff --git a/src/dsp/SpectralDifferenceAudioCurve.h b/src/dsp/SpectralDifferenceAudioCurve.h index b3956b2..8a88f5b 100644 --- a/src/dsp/SpectralDifferenceAudioCurve.h +++ b/src/dsp/SpectralDifferenceAudioCurve.h @@ -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; diff --git a/src/dsp/Window.h b/src/dsp/Window.h index 385ce6a..eb8313f 100644 --- a/src/dsp/Window.h +++ b/src/dsp/Window.h @@ -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::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; diff --git a/src/rubberband-c.cpp b/src/rubberband-c.cpp index 8ffea54..045c084 100644 --- a/src/rubberband-c.cpp +++ b/src/rubberband-c.cpp @@ -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 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); diff --git a/src/system/Allocators.cpp b/src/system/Allocators.cpp index 6df8282..294b584 100644 --- a/src/system/Allocators.cpp +++ b/src/system/Allocators.cpp @@ -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 diff --git a/src/system/Allocators.h b/src/system/Allocators.h index 092f3cc..af84840 100644 --- a/src/system/Allocators.h +++ b/src/system/Allocators.h @@ -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(channels, count); } catch (std::bad_alloc) { - if (ptr) deallocate_channels(ptr); + if (ptr) deallocate_channels(ptr, channels); throw; } if (oldcount && ptr) { v_copy_channels(newptr, ptr, channels, oldcount < count ? oldcount : count); } - if (ptr) deallocate_channels(ptr); + if (ptr) deallocate_channels(ptr, channels); + return newptr; +} + +template +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(channels, count); + } catch (std::bad_alloc) { + if (ptr) deallocate_channels(ptr, channels); + throw; + } + if (oldcount && ptr) { + v_copy_channels(newptr, ptr, channels, oldcount < count ? oldcount : count); + } + if (ptr) deallocate_channels(ptr, channels); return newptr; } diff --git a/src/system/Thread.cpp b/src/system/Thread.cpp index df8f8bc..2fa5649 100644 --- a/src/system/Thread.cpp +++ b/src/system/Thread.cpp @@ -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 diff --git a/src/system/Thread.h b/src/system/Thread.h index 2bdcb59..94194a8 100644 --- a/src/system/Thread.h +++ b/src/system/Thread.h @@ -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 diff --git a/src/system/VectorOps.h b/src/system/VectorOps.h index fec0de0..3a1d10c 100644 --- a/src/system/VectorOps.h +++ b/src/system/VectorOps.h @@ -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 diff --git a/src/system/sysutils.cpp b/src/system/sysutils.cpp index 8fb10c1..941c98f 100644 --- a/src/system/sysutils.cpp +++ b/src/system/sysutils.cpp @@ -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 diff --git a/src/system/sysutils.h b/src/system/sysutils.h index ae48a64..7c0d5be 100644 --- a/src/system/sysutils.h +++ b/src/system/sysutils.h @@ -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 -#include #include +#include #define MLOCK(a,b) ::mlock((char *)(a),(b)) #define MUNLOCK(a,b) (::munlock((char *)(a),(b)) ? (::perror("munlock failed"), 0) : 0) diff --git a/vamp/RubberBandVampPlugin.cpp b/vamp/RubberBandVampPlugin.cpp index c3ffa52..fb0b053 100644 --- a/vamp/RubberBandVampPlugin.cpp +++ b/vamp/RubberBandVampPlugin.cpp @@ -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 outputIncrements = m_stretcher->getOutputIncrements(); diff --git a/vamp/RubberBandVampPlugin.h b/vamp/RubberBandVampPlugin.h index 9033f76..751758d 100644 --- a/vamp/RubberBandVampPlugin.h +++ b/vamp/RubberBandVampPlugin.h @@ -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 diff --git a/vamp/libmain.cpp b/vamp/libmain.cpp index 1a15b70..d383477 100644 --- a/vamp/libmain.cpp +++ b/vamp/libmain.cpp @@ -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