* 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 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 size_t getChannelCount() const;

View File

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

View File

@@ -44,7 +44,7 @@ StretchCalculator::~StretchCalculator()
std::vector<int>
StretchCalculator::calculate(double ratio, size_t inputDuration,
const std::vector<float> &lockDf,
const std::vector<float> &phaseResetDf,
const std::vector<float> &stretchDf)
{
// 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
// 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
// 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
// start with a high sensitivity and reduce it).
// 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
// short time frame (e.g. 30-50ms).
@@ -79,11 +79,11 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
// 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;
size_t totalCount = lockDf.size();
size_t totalCount = phaseResetDf.size();
std::vector<int> increments;
@@ -96,11 +96,11 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
}
//!!! round down?
outputDuration = lrint((lockDf.size() * m_increment) * ratio);
outputDuration = lrint((phaseResetDf.size() * m_increment) * ratio);
if (m_debugLevel > 0) {
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;
@@ -329,10 +329,10 @@ StretchCalculator::findPeaks(const std::vector<float> &rawDf)
}
//!!! 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
//shortly after hard ones, otherwise either locking on them, or at
//least making sure they fall at the correct sample time
//shortly after hard ones, otherwise either resetting on them, or
//at least making sure they fall at the correct sample time
// int mediansize = lrint(ceil(double(m_sampleRate) /
// (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
//peak (the first value after the rise is not necessarily
//the peak itself, but it is probably where we should
//locate the lock). For hard peaks we need to lock in
//time to preserve the shape of the transient (unless some
//option is set to soft mode), for soft peaks we just want
//to avoid poor timing positioning so we build up to the
//lock at the exact peak moment.
//locate the phase reset). For hard peaks we need to
//reset in time to preserve the shape of the transient
//(unless some option is set to soft mode), for soft peaks
//we just want to avoid poor timing positioning so we
//build up to the reset at the exact peak moment.
// size_t peak = i + maxindex - mediansize;
size_t peak = i + maxindex - middle;
@@ -563,7 +563,7 @@ StretchCalculator::smoothDF(const std::vector<float> &df)
std::vector<int>
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<int> increments;
@@ -706,7 +706,7 @@ StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
if (displacement < 0) displacement -= adj;
else displacement += adj;
if (i == 0 && lock) {
if (i == 0 && phaseReset) {
if (df.size() == 1) {
increments.push_back(duration);
totalIncrement += duration;

View File

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

View File

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

View File

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

View File

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

View File

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