* More rationalisation -- lock becomes phase reset in most cases

* Update Vamp plugin parameters and outputs
This commit is contained in:
Chris Cannam
2007-11-19 20:13:39 +00:00
parent f327e0c415
commit e9cb6dbc37
8 changed files with 214 additions and 149 deletions

View File

@@ -89,7 +89,7 @@ public:
virtual size_t getInputIncrement() const; virtual size_t getInputIncrement() const;
virtual std::vector<int> getOutputIncrements() const; //!!! document particular meaning in RT mode virtual std::vector<int> getOutputIncrements() const; //!!! document particular meaning in RT mode
virtual std::vector<float> getLockCurve() const; //!!! document particular meaning in RT mode virtual std::vector<float> getPhaseResetCurve() const; //!!! document particular meaning in RT mode
virtual std::vector<int> getExactTimePoints() const; //!!! meaningless in RT mode virtual std::vector<int> getExactTimePoints() const; //!!! meaningless in RT mode
virtual size_t getChannelCount() const; virtual size_t getChannelCount() const;

View File

@@ -150,9 +150,9 @@ RubberBandStretcher::getOutputIncrements() const
} }
std::vector<float> std::vector<float>
RubberBandStretcher::getLockCurve() const RubberBandStretcher::getPhaseResetCurve() const
{ {
return m_d->getLockCurve(); return m_d->getPhaseResetCurve();
} }
std::vector<int> std::vector<int>

View File

@@ -44,7 +44,7 @@ StretchCalculator::~StretchCalculator()
std::vector<int> std::vector<int>
StretchCalculator::calculate(double ratio, size_t inputDuration, StretchCalculator::calculate(double ratio, size_t inputDuration,
const std::vector<float> &lockDf, const std::vector<float> &phaseResetDf,
const std::vector<float> &stretchDf) const std::vector<float> &stretchDf)
{ {
// Method: // Method:
@@ -53,14 +53,14 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
// 1. Pre-process the df array, and for each (say) one second's // 1. Pre-process the df array, and for each (say) one second's
// worth of values, calculate the number of peaks that would // worth of values, calculate the number of peaks that would
// qualify for phase locking given the default threshold. Then // qualify for phase reset given the default threshold. Then
// reduce or increase the threshold by stages until that number is // reduce or increase the threshold by stages until that number is
// in a sensible range (say 1-10 peaks per second -- the low end // in a sensible range (say 1-10 peaks per second -- the low end
// is harder to estimate than the high end, so it may be better to // is harder to estimate than the high end, so it may be better to
// start with a high sensitivity and reduce it). // start with a high sensitivity and reduce it).
// 2. Record the positions of peaks, and separately the positions // 2. Record the positions of peaks, and separately the positions
// of those peaks that qualify for locking using the sliding // of those peaks that qualify for reset using the sliding
// threshold window. Don't permit two locked peaks within a very // threshold window. Don't permit two locked peaks within a very
// short time frame (e.g. 30-50ms). // short time frame (e.g. 30-50ms).
@@ -79,11 +79,11 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
// Then divvy them up... how exactly? // Then divvy them up... how exactly?
assert(lockDf.size() == stretchDf.size()); assert(phaseResetDf.size() == stretchDf.size());
m_lastPeaks = findPeaks(lockDf); m_lastPeaks = findPeaks(phaseResetDf);
std::vector<Peak> &peaks = m_lastPeaks; std::vector<Peak> &peaks = m_lastPeaks;
size_t totalCount = lockDf.size(); size_t totalCount = phaseResetDf.size();
std::vector<int> increments; std::vector<int> increments;
@@ -96,11 +96,11 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
} }
//!!! round down? //!!! round down?
outputDuration = lrint((lockDf.size() * m_increment) * ratio); outputDuration = lrint((phaseResetDf.size() * m_increment) * ratio);
if (m_debugLevel > 0) { if (m_debugLevel > 0) {
std::cerr << " (rounded up to " << outputDuration << ")"; std::cerr << " (rounded up to " << outputDuration << ")";
std::cerr << ", df size " << lockDf.size() << std::endl; std::cerr << ", df size " << phaseResetDf.size() << std::endl;
} }
// size_t stretchable = outputDuration - lockCount * m_increment; // size_t stretchable = outputDuration - lockCount * m_increment;
@@ -329,10 +329,10 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
} }
//!!! we don't yet do the right thing with soft peaks. if //!!! we don't yet do the right thing with soft peaks. if
//!useHardPeaks, we should be locking on soft peaks; if //!useHardPeaks, we should be resetting on soft peaks; if
//useHardPeaks, we should be ignoring soft peaks if they occur //useHardPeaks, we should be ignoring soft peaks if they occur
//shortly after hard ones, otherwise either locking on them, or at //shortly after hard ones, otherwise either resetting on them, or
//least making sure they fall at the correct sample time //at least making sure they fall at the correct sample time
// int mediansize = lrint(ceil(double(m_sampleRate) / // int mediansize = lrint(ceil(double(m_sampleRate) /
// (4 * double(m_increment)))); // 0.25 sec ish // (4 * double(m_increment)))); // 0.25 sec ish
@@ -444,11 +444,11 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
//a very rapid rise in detection function prior to the //a very rapid rise in detection function prior to the
//peak (the first value after the rise is not necessarily //peak (the first value after the rise is not necessarily
//the peak itself, but it is probably where we should //the peak itself, but it is probably where we should
//locate the lock). For hard peaks we need to lock in //locate the phase reset). For hard peaks we need to
//time to preserve the shape of the transient (unless some //reset in time to preserve the shape of the transient
//option is set to soft mode), for soft peaks we just want //(unless some option is set to soft mode), for soft peaks
//to avoid poor timing positioning so we build up to the //we just want to avoid poor timing positioning so we
//lock at the exact peak moment. //build up to the reset at the exact peak moment.
// size_t peak = i + maxindex - mediansize; // size_t peak = i + maxindex - mediansize;
size_t peak = i + maxindex - middle; size_t peak = i + maxindex - middle;
@@ -563,7 +563,7 @@ StretchCalculator::smoothDF(const std::vector<float> &df)
std::vector<int> std::vector<int>
StretchCalculator::distributeRegion(const std::vector<float> &dfIn, StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
size_t duration, float ratio, bool lock) size_t duration, float ratio, bool phaseReset)
{ {
std::vector<float> df(dfIn); std::vector<float> df(dfIn);
std::vector<int> increments; std::vector<int> increments;
@@ -706,7 +706,7 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
if (displacement < 0) displacement -= adj; if (displacement < 0) displacement -= adj;
else displacement += adj; else displacement += adj;
if (i == 0 && lock) { if (i == 0 && phaseReset) {
if (df.size() == 1) { if (df.size() == 1) {
increments.push_back(duration); increments.push_back(duration);
totalIncrement += duration; totalIncrement += duration;

View File

@@ -66,7 +66,7 @@ protected:
std::vector<int> distributeRegion(const std::vector<float> &regionCurve, std::vector<int> distributeRegion(const std::vector<float> &regionCurve,
size_t outputDuration, float ratio, size_t outputDuration, float ratio,
bool lock); bool phaseReset);
void calculateDisplacements(const std::vector<float> &df, void calculateDisplacements(const std::vector<float> &df,
float &maxDf, float &maxDf,

View File

@@ -62,8 +62,8 @@ RubberBandStretcher::Impl::Impl(RubberBandStretcher *stretcher,
m_studyFFT(0), m_studyFFT(0),
m_inputDuration(0), m_inputDuration(0),
m_lastProcessOutputIncrements(16), m_lastProcessOutputIncrements(16),
m_lastProcessLockDf(16), m_lastProcessPhaseResetDf(16),
m_lockAudioCurve(0), m_phaseResetAudioCurve(0),
m_stretchAudioCurve(0), m_stretchAudioCurve(0),
m_stretchCalculator(0), m_stretchCalculator(0),
m_freq0(600), m_freq0(600),
@@ -134,7 +134,7 @@ RubberBandStretcher::Impl::~Impl()
delete m_channelData[c]; delete m_channelData[c];
} }
delete m_lockAudioCurve; delete m_phaseResetAudioCurve;
delete m_stretchAudioCurve; delete m_stretchAudioCurve;
delete m_stretchCalculator; delete m_stretchCalculator;
delete m_studyFFT; delete m_studyFFT;
@@ -157,7 +157,7 @@ RubberBandStretcher::Impl::reset()
m_channelData[c] = new ChannelData(m_windowSize, m_outbufSize); m_channelData[c] = new ChannelData(m_windowSize, m_outbufSize);
} }
m_mode = JustCreated; m_mode = JustCreated;
if (m_lockAudioCurve) m_lockAudioCurve->reset(); if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
if (m_stretchAudioCurve) m_stretchAudioCurve->reset(); if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
m_inputDuration = 0; m_inputDuration = 0;
@@ -478,11 +478,11 @@ RubberBandStretcher::Impl::configure()
} }
} }
delete m_lockAudioCurve; delete m_phaseResetAudioCurve;
m_lockAudioCurve = new PercussiveAudioCurve(m_stretcher->m_sampleRate, m_phaseResetAudioCurve = new PercussiveAudioCurve(m_stretcher->m_sampleRate,
m_windowSize); m_windowSize);
// stretchAudioCurve unused in RT mode; lockAudioCurve and // stretchAudioCurve unused in RT mode; phaseResetAudioCurve and
// stretchCalculator however are used in all modes // stretchCalculator however are used in all modes
if (!m_realtime) { if (!m_realtime) {
@@ -536,7 +536,7 @@ RubberBandStretcher::Impl::reconfigure()
// stop and calculate the stretch curve so far, then reset // stop and calculate the stretch curve so far, then reset
// the df vectors // the df vectors
calculateStretch(); calculateStretch();
m_lockDf.clear(); m_phaseResetDf.clear();
m_stretchDf.clear(); m_stretchDf.clear();
m_inputDuration = 0; m_inputDuration = 0;
} }
@@ -592,7 +592,7 @@ RubberBandStretcher::Impl::reconfigure()
} }
if (m_windowSize != prevWindowSize) { if (m_windowSize != prevWindowSize) {
m_lockAudioCurve->setWindowSize(m_windowSize); m_phaseResetAudioCurve->setWindowSize(m_windowSize);
} }
} }
@@ -705,10 +705,10 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
m_studyFFT->forwardMagnitude(cd.accumulator, cd.fltbuf); m_studyFFT->forwardMagnitude(cd.accumulator, cd.fltbuf);
float df = m_lockAudioCurve->process(cd.fltbuf, m_increment); float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment);
m_lockDf.push_back(df); m_phaseResetDf.push_back(df);
// cout << m_lockDf.size() << " [" << final << "] -> " << df << " \t: "; // cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: ";
df = m_stretchAudioCurve->process(cd.fltbuf, m_increment); df = m_stretchAudioCurve->process(cd.fltbuf, m_increment);
m_stretchDf.push_back(df); m_stretchDf.push_back(df);
@@ -756,14 +756,14 @@ RubberBandStretcher::Impl::getOutputIncrements() const
} }
vector<float> vector<float>
RubberBandStretcher::Impl::getLockCurve() const RubberBandStretcher::Impl::getPhaseResetCurve() const
{ {
if (!m_realtime) { if (!m_realtime) {
return m_lockDf; return m_phaseResetDf;
} else { } else {
vector<float> df; vector<float> df;
while (m_lastProcessLockDf.getReadSpace() > 0) { while (m_lastProcessPhaseResetDf.getReadSpace() > 0) {
df.push_back(m_lastProcessLockDf.readOne()); df.push_back(m_lastProcessPhaseResetDf.readOne());
} }
return df; return df;
} }
@@ -789,7 +789,7 @@ RubberBandStretcher::Impl::calculateStretch()
std::vector<int> increments = m_stretchCalculator->calculate std::vector<int> increments = m_stretchCalculator->calculate
(getEffectiveRatio(), (getEffectiveRatio(),
m_inputDuration, m_inputDuration,
m_lockDf, m_phaseResetDf,
m_stretchDf); m_stretchDf);
if (m_outputIncrements.empty()) m_outputIncrements = increments; if (m_outputIncrements.empty()) m_outputIncrements = increments;

View File

@@ -70,7 +70,7 @@ public:
} }
std::vector<int> getOutputIncrements() const; std::vector<int> getOutputIncrements() const;
std::vector<float> getLockCurve() const; std::vector<float> getPhaseResetCurve() const;
std::vector<int> getExactTimePoints() const; std::vector<int> getExactTimePoints() const;
size_t getChannelCount() const { size_t getChannelCount() const {
@@ -89,14 +89,14 @@ protected:
bool processChunks(size_t channel); // returns "last" bool processChunks(size_t channel); // returns "last"
bool processOneChunk(); // across all channels, for real time use bool processOneChunk(); // across all channels, for real time use
bool processChunkForChannel(size_t channel, size_t phaseIncrement, bool processChunkForChannel(size_t channel, size_t phaseIncrement,
size_t shiftIncrement, bool lock); size_t shiftIncrement, bool phaseReset);
bool testInbufReadSpace(size_t channel); bool testInbufReadSpace(size_t channel);
void calculateIncrements(size_t &phaseIncrement, void calculateIncrements(size_t &phaseIncrement,
size_t &shiftIncrement, bool &lock); size_t &shiftIncrement, bool &phaseReset);
bool getIncrements(size_t channel, size_t &phaseIncrement, bool getIncrements(size_t channel, size_t &phaseIncrement,
size_t &shiftIncrement, bool &lock); size_t &shiftIncrement, bool &phaseReset);
void analyseChunk(size_t channel); void analyseChunk(size_t channel);
void modifyChunk(size_t channel, size_t outputIncrement, bool lock); void modifyChunk(size_t channel, size_t outputIncrement, bool phaseReset);
void synthesiseChunk(size_t channel); void synthesiseChunk(size_t channel);
void writeChunk(size_t channel, size_t shiftIncrement, bool last); void writeChunk(size_t channel, size_t shiftIncrement, bool last);
@@ -154,7 +154,7 @@ protected:
size_t m_inputDuration; size_t m_inputDuration;
std::vector<float> m_lockDf; std::vector<float> m_phaseResetDf;
std::vector<float> m_stretchDf; std::vector<float> m_stretchDf;
class ChannelData; class ChannelData;
@@ -163,9 +163,9 @@ protected:
std::vector<int> m_outputIncrements; std::vector<int> m_outputIncrements;
mutable RingBuffer<int> m_lastProcessOutputIncrements; mutable RingBuffer<int> m_lastProcessOutputIncrements;
mutable RingBuffer<float> m_lastProcessLockDf; mutable RingBuffer<float> m_lastProcessPhaseResetDf;
AudioCurve *m_lockAudioCurve; AudioCurve *m_phaseResetAudioCurve;
AudioCurve *m_stretchAudioCurve; AudioCurve *m_stretchAudioCurve;
StretchCalculator *m_stretchCalculator; StretchCalculator *m_stretchCalculator;

View File

@@ -89,11 +89,11 @@ RubberBandStretcher::Impl::processChunks(size_t c)
analyseChunk(c); analyseChunk(c);
} }
bool lock = false; bool phaseReset = false;
size_t phaseIncrement, shiftIncrement; size_t phaseIncrement, shiftIncrement;
getIncrements(c, phaseIncrement, shiftIncrement, lock); getIncrements(c, phaseIncrement, shiftIncrement, phaseReset);
last = processChunkForChannel(c, phaseIncrement, shiftIncrement, lock); last = processChunkForChannel(c, phaseIncrement, shiftIncrement, phaseReset);
cd.chunkCount++; cd.chunkCount++;
if (m_debugLevel > 2) { if (m_debugLevel > 2) {
cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl; cerr << "channel " << c << ": last = " << last << ", chunkCount = " << cd.chunkCount << endl;
@@ -121,15 +121,15 @@ RubberBandStretcher::Impl::processOneChunk()
} }
} }
bool lock = false; bool phaseReset = false;
size_t phaseIncrement, shiftIncrement; size_t phaseIncrement, shiftIncrement;
if (!getIncrements(0, phaseIncrement, shiftIncrement, lock)) { if (!getIncrements(0, phaseIncrement, shiftIncrement, phaseReset)) {
calculateIncrements(phaseIncrement, shiftIncrement, lock); calculateIncrements(phaseIncrement, shiftIncrement, phaseReset);
} }
bool last = false; bool last = false;
for (size_t c = 0; c < m_channels; ++c) { for (size_t c = 0; c < m_channels; ++c) {
last = processChunkForChannel(c, phaseIncrement, shiftIncrement, lock); last = processChunkForChannel(c, phaseIncrement, shiftIncrement, phaseReset);
m_channelData[c]->chunkCount++; m_channelData[c]->chunkCount++;
} }
@@ -187,15 +187,15 @@ bool
RubberBandStretcher::Impl::processChunkForChannel(size_t c, RubberBandStretcher::Impl::processChunkForChannel(size_t c,
size_t phaseIncrement, size_t phaseIncrement,
size_t shiftIncrement, size_t shiftIncrement,
bool lock) bool phaseReset)
{ {
// Process a single chunk on a single channel. This assumes // Process a single chunk on a single channel. This assumes
// enough input data is available; caller must have tested this // enough input data is available; caller must have tested this
// using e.g. testInbufReadSpace first. Return true if this is // using e.g. testInbufReadSpace first. Return true if this is
// the last chunk on the channel. // the last chunk on the channel.
if (lock && (m_debugLevel > 1)) { if (phaseReset && (m_debugLevel > 1)) {
cerr << "processChunkForChannel: lock found, incrs " cerr << "processChunkForChannel: phase reset found, incrs "
<< phaseIncrement << ":" << shiftIncrement << endl; << phaseIncrement << ":" << shiftIncrement << endl;
} }
@@ -216,11 +216,11 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
// We need to peek m_windowSize samples for processing, and // We need to peek m_windowSize samples for processing, and
// then skip m_increment to advance the read pointer. // then skip m_increment to advance the read pointer.
modifyChunk(c, phaseIncrement, lock); modifyChunk(c, phaseIncrement, phaseReset);
synthesiseChunk(c); // reads from cd.mag, cd.phase synthesiseChunk(c); // reads from cd.mag, cd.phase
if (m_debugLevel > 2) { if (m_debugLevel > 2) {
if (lock) { if (phaseReset) {
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
cd.accumulator[i] = ((drand48() * 2 - 1.0) > 0 ? 1 : -1); cd.accumulator[i] = ((drand48() * 2 - 1.0) > 0 ? 1 : -1);
} }
@@ -277,7 +277,7 @@ RubberBandStretcher::Impl::processChunkForChannel(size_t c,
void void
RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn, RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
size_t &shiftIncrementRtn, size_t &shiftIncrementRtn,
bool &lock) bool &phaseReset)
{ {
// cerr << "calculateIncrements" << endl; // cerr << "calculateIncrements" << endl;
@@ -294,7 +294,7 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
phaseIncrementRtn = m_increment; phaseIncrementRtn = m_increment;
shiftIncrementRtn = m_increment; shiftIncrementRtn = m_increment;
lock = false; phaseReset = false;
if (m_channels == 0) return; if (m_channels == 0) return;
@@ -328,18 +328,18 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
} }
} }
float df = m_lockAudioCurve->process(cd.fltbuf, m_increment); float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment);
int incr = m_stretchCalculator->calculateSingle int incr = m_stretchCalculator->calculateSingle
(getEffectiveRatio(), (getEffectiveRatio(),
m_inputDuration, //!!! no, totally wrong... fortunately it doesn't matter atm m_inputDuration, //!!! no, totally wrong... fortunately it doesn't matter atm
df); df);
m_lastProcessLockDf.write(&df, 1); m_lastProcessPhaseResetDf.write(&df, 1);
m_lastProcessOutputIncrements.write(&incr, 1); m_lastProcessOutputIncrements.write(&incr, 1);
if (incr < 0) { if (incr < 0) {
lock = true; phaseReset = true;
incr = -incr; incr = -incr;
} }
@@ -352,9 +352,9 @@ RubberBandStretcher::Impl::calculateIncrements(size_t &phaseIncrementRtn,
// This implies we should use this increment for the shift // This implies we should use this increment for the shift
// increment, and make the following phase increment the same as // increment, and make the following phase increment the same as
// it. This means in RT mode we'll be one chunk later with our // it. This means in RT mode we'll be one chunk later with our
// phase lock than we would be in non-RT mode. The sensitivity of // phase reset than we would be in non-RT mode. The sensitivity
// the broadband onset detector may mean that this isn't a problem // of the broadband onset detector may mean that this isn't a
// -- test it and see. // problem -- test it and see.
shiftIncrementRtn = incr; shiftIncrementRtn = incr;
@@ -371,12 +371,12 @@ bool
RubberBandStretcher::Impl::getIncrements(size_t channel, RubberBandStretcher::Impl::getIncrements(size_t channel,
size_t &phaseIncrementRtn, size_t &phaseIncrementRtn,
size_t &shiftIncrementRtn, size_t &shiftIncrementRtn,
bool &lock) bool &phaseReset)
{ {
if (channel >= m_channels) { if (channel >= m_channels) {
phaseIncrementRtn = m_increment; phaseIncrementRtn = m_increment;
shiftIncrementRtn = m_increment; shiftIncrementRtn = m_increment;
lock = false; phaseReset = false;
return false; return false;
} }
@@ -387,10 +387,10 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
// writing the chunk. The shift increment for one chunk is the // writing the chunk. The shift increment for one chunk is the
// same as the phase increment for the following chunk. // same as the phase increment for the following chunk.
// When an onset occurs for which we need to lock phases, the // When an onset occurs for which we need to reset phases, the
// increment given will be negative. // increment given will be negative.
// When we lock phases, the previous shift increment (and so // When we reset phases, the previous shift increment (and so
// current phase increments) must have been m_increment to ensure // current phase increments) must have been m_increment to ensure
// consistency. // consistency.
@@ -406,7 +406,7 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
if (m_outputIncrements.size() == 0) { if (m_outputIncrements.size() == 0) {
phaseIncrementRtn = m_increment; phaseIncrementRtn = m_increment;
shiftIncrementRtn = m_increment; shiftIncrementRtn = m_increment;
lock = false; phaseReset = false;
return false; return false;
} else { } else {
cd.chunkCount = m_outputIncrements.size()-1; cd.chunkCount = m_outputIncrements.size()-1;
@@ -423,7 +423,7 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
if (phaseIncrement < 0) { if (phaseIncrement < 0) {
phaseIncrement = -phaseIncrement; phaseIncrement = -phaseIncrement;
lock = true; phaseReset = true;
} }
if (shiftIncrement < 0) { if (shiftIncrement < 0) {
@@ -437,7 +437,7 @@ RubberBandStretcher::Impl::getIncrements(size_t channel,
phaseIncrementRtn = phaseIncrement; phaseIncrementRtn = phaseIncrement;
shiftIncrementRtn = shiftIncrement; shiftIncrementRtn = shiftIncrement;
if (cd.chunkCount == 0) lock = true; // don't mess with the first chunk if (cd.chunkCount == 0) phaseReset = true; // don't mess with the first chunk
return gotData; return gotData;
} }
@@ -465,12 +465,12 @@ double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; }
void void
RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement, RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
bool lock) bool phaseReset)
{ {
ChannelData &cd = *m_channelData[channel]; ChannelData &cd = *m_channelData[channel];
if (lock && m_debugLevel > 1) { if (phaseReset && m_debugLevel > 1) {
cerr << "lock: leaving phases unmodified" << endl; cerr << "phase reset: leaving phases unmodified" << endl;
} }
size_t count = m_windowSize/2; size_t count = m_windowSize/2;
@@ -585,19 +585,19 @@ RubberBandStretcher::Impl::modifyChunk(size_t channel, size_t outputIncrement,
pp = cd.freqPeak[i-1]; pp = cd.freqPeak[i-1];
} }
bool lockThis = lock; bool resetThis = phaseReset;
if (!(m_options & OptionTransientsSmooth) && if (!(m_options & OptionTransientsSmooth) &&
!(m_options & OptionTransientsCrisp)) { !(m_options & OptionTransientsCrisp)) {
// must be OptionTransientsMixed // must be OptionTransientsMixed
size_t low = lrint((150 * m_windowSize) / rate); size_t low = lrint((150 * m_windowSize) / rate);
size_t high = lrint((1000 * m_windowSize) / rate); size_t high = lrint((1000 * m_windowSize) / rate);
if (lockThis) { if (resetThis) {
if (i > low && i < high) lockThis = false; if (i > low && i < high) resetThis = false;
} }
} }
if (!lockThis) { if (!resetThis) {
if (i == 0 || p != pp) { if (i == 0 || p != pp) {

View File

@@ -35,17 +35,20 @@ public:
bool m_realtime; bool m_realtime;
bool m_elasticTiming; bool m_elasticTiming;
bool m_crispTransients; int m_transientMode;
bool m_phaseIndependent;
bool m_threadingAllowed; bool m_threadingAllowed;
int m_windowLength;
RubberBand::RubberBandStretcher *m_stretcher; RubberBand::RubberBandStretcher *m_stretcher;
int m_incrementsOutput; int m_incrementsOutput;
int m_aggregateIncrementsOutput; int m_aggregateIncrementsOutput;
int m_divergenceOutput; int m_divergenceOutput;
int m_lockDfOutput; int m_phaseResetDfOutput;
int m_smoothedLockDfOutput; int m_smoothedPhaseResetDfOutput;
int m_lockPointsOutput; int m_phaseResetPointsOutput;
int m_timeSyncPointsOutput;
size_t m_counter; size_t m_counter;
size_t m_accumulatedIncrement; size_t m_accumulatedIncrement;
@@ -62,9 +65,9 @@ public:
FeatureSet createFeatures(size_t inputIncrement, FeatureSet createFeatures(size_t inputIncrement,
std::vector<int> &outputIncrements, std::vector<int> &outputIncrements,
std::vector<float> &lockDf, std::vector<float> &phaseResetDf,
std::vector<int> &exactPoints, std::vector<int> &exactPoints,
std::vector<float> &smoothedDF, std::vector<float> &smoothedDf,
size_t baseCount, size_t baseCount,
bool includeFinal); bool includeFinal);
}; };
@@ -75,12 +78,14 @@ RubberBandVampPlugin::RubberBandVampPlugin(float inputSampleRate) :
{ {
m_d = new Impl(); m_d = new Impl();
m_d->m_stepSize = 0; m_d->m_stepSize = 0;
m_d->m_timeRatio = 1.0; m_d->m_timeRatio = 1.f;
m_d->m_pitchRatio = 1.0; m_d->m_pitchRatio = 1.f;
m_d->m_realtime = false; m_d->m_realtime = false;
m_d->m_elasticTiming = true; m_d->m_elasticTiming = true;
m_d->m_crispTransients = true; m_d->m_transientMode = 0;
m_d->m_phaseIndependent = false;
m_d->m_threadingAllowed = true; m_d->m_threadingAllowed = true;
m_d->m_windowLength = 0;
m_d->m_stretcher = 0; m_d->m_stretcher = 0;
m_d->m_sampleRate = lrintf(m_inputSampleRate); m_d->m_sampleRate = lrintf(m_inputSampleRate);
} }
@@ -140,11 +145,11 @@ RubberBandVampPlugin::getOutputDescriptors() const
OutputDescriptor d; OutputDescriptor d;
d.identifier = "increments"; d.identifier = "increments";
d.name = "Output Increments"; d.name = "Output Increments";
d.description = ""; //!!! d.description = "Output time increment for each input step";
d.unit = "samples"; d.unit = "samples";
d.hasFixedBinCount = true; d.hasFixedBinCount = true;
d.binCount = 1; d.binCount = 1;
d.hasKnownExtents = false; //!!! d.hasKnownExtents = false;
d.isQuantized = true; d.isQuantized = true;
d.quantizeStep = 1.0; d.quantizeStep = 1.0;
d.sampleType = OutputDescriptor::VariableSampleRate; d.sampleType = OutputDescriptor::VariableSampleRate;
@@ -154,44 +159,56 @@ RubberBandVampPlugin::getOutputDescriptors() const
d.identifier = "aggregate_increments"; d.identifier = "aggregate_increments";
d.name = "Accumulated Output Increments"; d.name = "Accumulated Output Increments";
d.description = ""; //!!! d.description = "Accumulated output time increments";
d.sampleRate = 0; d.sampleRate = 0;
m_d->m_aggregateIncrementsOutput = list.size(); m_d->m_aggregateIncrementsOutput = list.size();
list.push_back(d); list.push_back(d);
d.identifier = "divergence"; d.identifier = "divergence";
d.name = "Divergence from Linear"; d.name = "Divergence from Linear";
d.description = ""; //!!! d.description = "Difference between actual output time and the output time for a theoretical linear stretch";
d.isQuantized = false; d.isQuantized = false;
d.sampleRate = 0; d.sampleRate = 0;
m_d->m_divergenceOutput = list.size(); m_d->m_divergenceOutput = list.size();
list.push_back(d); list.push_back(d);
d.identifier = "lockdf"; d.identifier = "phaseresetdf";
d.name = "Lock Point Detection Function"; d.name = "Phase Reset Detection Function";
d.description = ""; //!!! d.description = "Curve whose peaks are used to identify transients for phase reset points";
d.unit = ""; d.unit = "";
d.sampleRate = rate; d.sampleRate = rate;
m_d->m_lockDfOutput = list.size(); m_d->m_phaseResetDfOutput = list.size();
list.push_back(d); list.push_back(d);
d.identifier = "smoothedlockdf"; d.identifier = "smoothedphaseresetdf";
d.name = "Smoothed Lock Point Detection Function"; d.name = "Smoothed Phase Reset Detection Function";
d.description = ""; //!!! d.description = "Phase reset curve smoothed for peak picking";
d.unit = ""; d.unit = "";
m_d->m_smoothedLockDfOutput = list.size(); m_d->m_smoothedPhaseResetDfOutput = list.size();
list.push_back(d); list.push_back(d);
d.identifier = "lockpoints"; d.identifier = "phaseresetpoints";
d.name = "Phase Lock Points"; d.name = "Phase Reset Points";
d.description = ""; //!!! d.description = "Points estimated as transients at which phase reset occurs";
d.unit = ""; d.unit = "";
d.hasFixedBinCount = true; d.hasFixedBinCount = true;
d.binCount = 0; d.binCount = 0;
d.hasKnownExtents = false; d.hasKnownExtents = false;
d.isQuantized = false; d.isQuantized = false;
d.sampleRate = 0; d.sampleRate = 0;
m_d->m_lockPointsOutput = list.size(); m_d->m_phaseResetPointsOutput = list.size();
list.push_back(d);
d.identifier = "timesyncpoints";
d.name = "Time Sync Points";
d.description = "Salient points which stretcher aims to place with strictly correct timing";
d.unit = "";
d.hasFixedBinCount = true;
d.binCount = 0;
d.hasKnownExtents = false;
d.isQuantized = false;
d.sampleRate = 0;
m_d->m_timeSyncPointsOutput = list.size();
list.push_back(d); list.push_back(d);
return list; return list;
@@ -204,22 +221,22 @@ RubberBandVampPlugin::getParameterDescriptors() const
ParameterDescriptor d; ParameterDescriptor d;
d.identifier = "timeratio"; d.identifier = "timeratio";
d.name = "Timestretch Ratio"; d.name = "Time Ratio";
d.description = ""; //!!! d.description = "Ratio to modify overall duration by";
d.unit = ""; d.unit = "%";
d.minValue = 0.0000001; d.minValue = 1;
d.maxValue = 1000; d.maxValue = 500;
d.defaultValue = 1.0; d.defaultValue = 100;
d.isQuantized = false; d.isQuantized = false;
list.push_back(d); list.push_back(d);
d.identifier = "pitchratio"; d.identifier = "pitchratio";
d.name = "Pitch Scaling Ratio"; d.name = "Pitch Scale Ratio";
d.description = ""; //!!! d.description = "Frequency ratio to modify pitch by";
d.unit = ""; d.unit = "%";
d.minValue = 0.0000001; d.minValue = 1;
d.maxValue = 1000; d.maxValue = 500;
d.defaultValue = 1.0; d.defaultValue = 100;
d.isQuantized = false; d.isQuantized = false;
list.push_back(d); list.push_back(d);
@@ -256,13 +273,43 @@ RubberBandVampPlugin::getParameterDescriptors() const
d.description = ""; //!!! d.description = ""; //!!!
d.unit = ""; d.unit = "";
d.minValue = 0; d.minValue = 0;
d.maxValue = 2;
d.defaultValue = 0;
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Mixed");
d.valueNames.push_back("Smooth");
d.valueNames.push_back("Crisp");
list.push_back(d);
d.identifier = "phasemode";
d.name = "Phase Handling";
d.description = ""; //!!!
d.unit = "";
d.minValue = 0;
d.maxValue = 1; d.maxValue = 1;
d.defaultValue = 0; d.defaultValue = 0;
d.isQuantized = true; d.isQuantized = true;
d.quantizeStep = 1; d.quantizeStep = 1;
d.valueNames.clear(); d.valueNames.clear();
d.valueNames.push_back("Crisp"); d.valueNames.push_back("Peak Locked");
d.valueNames.push_back("Soft"); d.valueNames.push_back("Independent");
list.push_back(d);
d.identifier = "windowmode";
d.name = "Window Length";
d.description = ""; //!!!
d.unit = "";
d.minValue = 0;
d.maxValue = 2;
d.defaultValue = 0;
d.isQuantized = true;
d.quantizeStep = 1;
d.valueNames.clear();
d.valueNames.push_back("Standard");
d.valueNames.push_back("Short");
d.valueNames.push_back("Long");
list.push_back(d); list.push_back(d);
d.identifier = "threadingmode"; d.identifier = "threadingmode";
@@ -275,7 +322,7 @@ RubberBandVampPlugin::getParameterDescriptors() const
d.isQuantized = true; d.isQuantized = true;
d.quantizeStep = 1; d.quantizeStep = 1;
d.valueNames.clear(); d.valueNames.clear();
d.valueNames.push_back("Enabled"); d.valueNames.push_back("Automatic");
d.valueNames.push_back("Disabled"); d.valueNames.push_back("Disabled");
list.push_back(d); list.push_back(d);
@@ -285,12 +332,14 @@ RubberBandVampPlugin::getParameterDescriptors() const
float float
RubberBandVampPlugin::getParameter(std::string id) const RubberBandVampPlugin::getParameter(std::string id) const
{ {
if (id == "timeratio") return m_d->m_timeRatio; if (id == "timeratio") return m_d->m_timeRatio * 100.f;
if (id == "pitchratio") return m_d->m_pitchRatio; if (id == "pitchratio") return m_d->m_pitchRatio * 100.f;
if (id == "mode") return m_d->m_realtime ? 1 : 0; if (id == "mode") return m_d->m_realtime ? 1 : 0;
if (id == "stretchtype") return m_d->m_elasticTiming ? 0 : 1; if (id == "stretchtype") return m_d->m_elasticTiming ? 0 : 1;
if (id == "transientmode") return m_d->m_crispTransients ? 0 : 1; if (id == "transientmode") return m_d->m_transientMode;
if (id == "phasemode") return m_d->m_phaseIndependent ? 1 : 0;
if (id == "threadingmode") return m_d->m_threadingAllowed ? 0 : 1; if (id == "threadingmode") return m_d->m_threadingAllowed ? 0 : 1;
if (id == "windowmode") return m_d->m_windowLength;
return 0.f; return 0.f;
} }
@@ -298,15 +347,17 @@ void
RubberBandVampPlugin::setParameter(std::string id, float value) RubberBandVampPlugin::setParameter(std::string id, float value)
{ {
if (id == "timeratio") { if (id == "timeratio") {
m_d->m_timeRatio = value; m_d->m_timeRatio = value / 100;
} else if (id == "pitchratio") { } else if (id == "pitchratio") {
m_d->m_pitchRatio = value; m_d->m_pitchRatio = value / 100;
} else { } else {
bool set = (value > 0.5); bool set = (value > 0.5);
if (id == "mode") m_d->m_realtime = set; if (id == "mode") m_d->m_realtime = set;
else if (id == "stretchtype") m_d->m_elasticTiming = !set; else if (id == "stretchtype") m_d->m_elasticTiming = !set;
else if (id == "transientmode") m_d->m_crispTransients = !set; else if (id == "transientmode") m_d->m_transientMode = int(value + 0.5);
else if (id == "phasemode") m_d->m_phaseIndependent = set;
else if (id == "threadingmode") m_d->m_threadingAllowed = !set; else if (id == "threadingmode") m_d->m_threadingAllowed = !set;
else if (id == "windowmode") m_d->m_windowLength = int(value + 0.5);
} }
} }
@@ -329,14 +380,26 @@ RubberBandVampPlugin::initialise(size_t channels, size_t stepSize, size_t blockS
options |= RubberBand::RubberBandStretcher::OptionStretchElastic; options |= RubberBand::RubberBandStretcher::OptionStretchElastic;
else options |= RubberBand::RubberBandStretcher::OptionStretchPrecise; else options |= RubberBand::RubberBandStretcher::OptionStretchPrecise;
if (m_d->m_crispTransients) if (m_d->m_transientMode == 0)
options |= RubberBand::RubberBandStretcher::OptionTransientsCrisp; options |= RubberBand::RubberBandStretcher::OptionTransientsMixed;
else options |= RubberBand::RubberBandStretcher::OptionTransientsSmooth; else if (m_d->m_transientMode == 1)
options |= RubberBand::RubberBandStretcher::OptionTransientsSmooth;
else options |= RubberBand::RubberBandStretcher::OptionTransientsCrisp;
if (m_d->m_phaseIndependent)
options |= RubberBand::RubberBandStretcher::OptionPhaseIndependent;
else options |= RubberBand::RubberBandStretcher::OptionPhasePeakLocked;
if (m_d->m_threadingAllowed) if (m_d->m_threadingAllowed)
options |= RubberBand::RubberBandStretcher::OptionThreadingAuto; options |= RubberBand::RubberBandStretcher::OptionThreadingAuto;
else options |= RubberBand::RubberBandStretcher::OptionThreadingNone; else options |= RubberBand::RubberBandStretcher::OptionThreadingNone;
if (m_d->m_windowLength == 0)
options |= RubberBand::RubberBandStretcher::OptionWindowStandard;
else if (m_d->m_windowLength == 1)
options |= RubberBand::RubberBandStretcher::OptionWindowShort;
else options |= RubberBand::RubberBandStretcher::OptionWindowLong;
delete m_d->m_stretcher; delete m_d->m_stretcher;
m_d->m_stretcher = new RubberBand::RubberBandStretcher m_d->m_stretcher = new RubberBand::RubberBandStretcher
(m_d->m_sampleRate, channels, options); (m_d->m_sampleRate, channels, options);
@@ -409,12 +472,12 @@ RubberBandVampPlugin::Impl::getRemainingFeaturesOffline()
size_t inputIncrement = m_stretcher->getInputIncrement(); size_t inputIncrement = m_stretcher->getInputIncrement();
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements(); std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();
std::vector<float> lockDf = m_stretcher->getLockCurve(); std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve();
std::vector<int> peaks = m_stretcher->getExactTimePoints(); std::vector<int> peaks = m_stretcher->getExactTimePoints();
std::vector<float> smoothedDf = sc.smoothDF(lockDf); std::vector<float> smoothedDf = sc.smoothDF(phaseResetDf);
FeatureSet features = createFeatures FeatureSet features = createFeatures
(inputIncrement, outputIncrements, lockDf, peaks, smoothedDf, (inputIncrement, outputIncrements, phaseResetDf, peaks, smoothedDf,
0, true); 0, true);
return features; return features;
@@ -439,11 +502,11 @@ RubberBandVampPlugin::Impl::processRealTime(const float *const *inputBuffers,
size_t inputIncrement = m_stretcher->getInputIncrement(); size_t inputIncrement = m_stretcher->getInputIncrement();
std::vector<int> outputIncrements = m_stretcher->getOutputIncrements(); std::vector<int> outputIncrements = m_stretcher->getOutputIncrements();
std::vector<float> lockDf = m_stretcher->getLockCurve(); std::vector<float> phaseResetDf = m_stretcher->getPhaseResetCurve();
std::vector<float> smoothedDf; // not meaningful in RT mode std::vector<float> smoothedDf; // not meaningful in RT mode
std::vector<int> dummyPoints; std::vector<int> dummyPoints;
FeatureSet features = createFeatures FeatureSet features = createFeatures
(inputIncrement, outputIncrements, lockDf, dummyPoints, smoothedDf, (inputIncrement, outputIncrements, phaseResetDf, dummyPoints, smoothedDf,
m_counter, false); m_counter, false);
m_counter += outputIncrements.size(); m_counter += outputIncrements.size();
@@ -459,7 +522,7 @@ RubberBandVampPlugin::Impl::getRemainingFeaturesRealTime()
RubberBandVampPlugin::FeatureSet RubberBandVampPlugin::FeatureSet
RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement, RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement,
std::vector<int> &outputIncrements, std::vector<int> &outputIncrements,
std::vector<float> &lockDf, std::vector<float> &phaseResetDf,
std::vector<int> &exactPoints, std::vector<int> &exactPoints,
std::vector<float> &smoothedDf, std::vector<float> &smoothedDf,
size_t baseCount, size_t baseCount,
@@ -482,16 +545,16 @@ RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement,
size_t frame = (baseCount + i) * inputIncrement; size_t frame = (baseCount + i) * inputIncrement;
int oi = outputIncrements[i]; int oi = outputIncrements[i];
bool hardLock = false; bool hard = false;
bool softLock = false; bool soft = false;
if (oi < 0) { if (oi < 0) {
oi = -oi; oi = -oi;
hardLock = true; hard = true;
} }
if (epi < exactPoints.size() && int(i) == exactPoints[epi]) { if (epi < exactPoints.size() && int(i) == exactPoints[epi]) {
softLock = true; soft = true;
++epi; ++epi;
} }
@@ -528,28 +591,30 @@ RubberBandVampPlugin::Impl::createFeatures(size_t inputIncrement,
char buf[30]; char buf[30];
if (i < lockDf.size()) { if (i < phaseResetDf.size()) {
feature.values.clear(); feature.values.clear();
feature.values.push_back(lockDf[i]); feature.values.push_back(phaseResetDf[i]);
sprintf(buf, "%d", baseCount + i); sprintf(buf, "%d", baseCount + i);
feature.label = buf; feature.label = buf;
features[m_lockDfOutput].push_back(feature); features[m_phaseResetDfOutput].push_back(feature);
} }
if (i < smoothedDf.size()) { if (i < smoothedDf.size()) {
feature.values.clear(); feature.values.clear();
feature.values.push_back(smoothedDf[i]); feature.values.push_back(smoothedDf[i]);
features[m_smoothedLockDfOutput].push_back(feature); features[m_smoothedPhaseResetDfOutput].push_back(feature);
} }
if (hardLock) { if (hard) {
feature.values.clear(); feature.values.clear();
feature.label = "Phase Reset"; feature.label = "Phase Reset";
features[m_lockPointsOutput].push_back(feature); features[m_phaseResetPointsOutput].push_back(feature);
} else if (softLock) { }
if (hard || soft) {
feature.values.clear(); feature.values.clear();
feature.label = "Time Sync"; feature.label = "Time Sync";
features[m_lockPointsOutput].push_back(feature); features[m_timeSyncPointsOutput].push_back(feature);
} }
} }