* More rationalisation -- lock becomes phase reset in most cases
* Update Vamp plugin parameters and outputs
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -66,7 +66,7 @@ protected:
|
||||
|
||||
std::vector<int> distributeRegion(const std::vector<float> ®ionCurve,
|
||||
size_t outputDuration, float ratio,
|
||||
bool lock);
|
||||
bool phaseReset);
|
||||
|
||||
void calculateDisplacements(const std::vector<float> &df,
|
||||
float &maxDf,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user