Remove elastic/loose processing support
This commit is contained in:
@@ -90,7 +90,7 @@ int main(int argc, char **argv)
|
||||
double frequencyshift = 1.0;
|
||||
int debug = 0;
|
||||
bool realtime = false;
|
||||
bool precise = true;
|
||||
bool precisiongiven = false;
|
||||
int threading = 0;
|
||||
bool lamination = true;
|
||||
bool longwin = false;
|
||||
@@ -179,8 +179,8 @@ int main(int argc, char **argv)
|
||||
case 'f': frequencyshift = atof(optarg); haveRatio = true; break;
|
||||
case 'd': debug = atoi(optarg); break;
|
||||
case 'R': realtime = true; break;
|
||||
case 'L': precise = false; break;
|
||||
case 'P': precise = true; break;
|
||||
case 'L': precisiongiven = true; break;
|
||||
case 'P': precisiongiven = true; break;
|
||||
case 'F': formant = true; break;
|
||||
case '0': threading = 1; break;
|
||||
case '@': threading = 2; break;
|
||||
@@ -276,9 +276,10 @@ int main(int argc, char **argv)
|
||||
cerr << "crispness parameter are intended to provide the best sounding set of options" << endl;
|
||||
cerr << "for most situations. The default is to use none of these options." << endl;
|
||||
cerr << endl;
|
||||
cerr << " -L, --loose Relax timing in hope of better transient preservation" << endl;
|
||||
cerr << " -P, --precise Ignored: The opposite of -L, this is default from 1.6" << endl;
|
||||
cerr << " -R, --realtime Select realtime mode (implies --no-threads)" << endl;
|
||||
cerr << " -R, --realtime Select realtime mode (implies --no-threads)." << endl;
|
||||
cerr << " This utility does not do realtime stream processing;" << endl;
|
||||
cerr << " the option merely selects realtime mode for the" << endl;
|
||||
cerr << " stretcher it uses" << endl;
|
||||
cerr << " --no-threads No extra threads regardless of CPU and channel count" << endl;
|
||||
cerr << " --threads Assume multi-CPU even if only one CPU is identified" << endl;
|
||||
cerr << " --no-transients Disable phase resynchronisation at transients" << endl;
|
||||
@@ -294,6 +295,8 @@ int main(int argc, char **argv)
|
||||
cerr << " (at a cost in width and individual channel quality)" << endl;
|
||||
cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl;
|
||||
cerr << " with reduced gain if clipping occurs" << endl;
|
||||
cerr << " -L, --loose [Accepted for compatibility but ignored; always off]" << endl;
|
||||
cerr << " -P, --precise [Accepted for compatibility but ignored; always on]" << endl;
|
||||
cerr << endl;
|
||||
cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << endl;
|
||||
cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl;
|
||||
@@ -330,6 +333,11 @@ int main(int argc, char **argv)
|
||||
hqpitch = false;
|
||||
}
|
||||
|
||||
if (precisiongiven) {
|
||||
cerr << "NOTE: The -L/--loose and -P/--precise options are both ignored -- precise" << endl;
|
||||
cerr << " became the default in v1.6 and loose was removed in v3.0" << endl;
|
||||
}
|
||||
|
||||
switch (crispness) {
|
||||
case -1: crispness = 5; break;
|
||||
case 0: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = true; shortwin = false; break;
|
||||
@@ -493,7 +501,6 @@ int main(int argc, char **argv)
|
||||
|
||||
RubberBandStretcher::Options options = 0;
|
||||
if (realtime) options |= RubberBandStretcher::OptionProcessRealTime;
|
||||
if (precise) options |= RubberBandStretcher::OptionStretchPrecise;
|
||||
if (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent;
|
||||
if (longwin) options |= RubberBandStretcher::OptionWindowLong;
|
||||
if (shortwin) options |= RubberBandStretcher::OptionWindowShort;
|
||||
|
||||
@@ -38,10 +38,8 @@ library_sources = [
|
||||
'src/base/Profiler.cpp',
|
||||
'src/dsp/AudioCurveCalculator.cpp',
|
||||
'src/audiocurves/CompoundAudioCurve.cpp',
|
||||
'src/audiocurves/SpectralDifferenceAudioCurve.cpp',
|
||||
'src/audiocurves/HighFrequencyAudioCurve.cpp',
|
||||
'src/audiocurves/SilentAudioCurve.cpp',
|
||||
'src/audiocurves/ConstantAudioCurve.cpp',
|
||||
'src/audiocurves/PercussiveAudioCurve.cpp',
|
||||
'src/dsp/Resampler.cpp',
|
||||
'src/dsp/FFT.cpp',
|
||||
|
||||
@@ -109,27 +109,6 @@ public:
|
||||
* non-real-time operation on seekable files: Offline; real-time
|
||||
* or streaming operation: RealTime.
|
||||
*
|
||||
* 2. Flags prefixed \c OptionStretch control the profile used for
|
||||
* variable timestretching. Rubber Band always adjusts the
|
||||
* stretch profile to minimise stretching of busy broadband
|
||||
* transient sounds, but the degree to which it does so is
|
||||
* adjustable. These options may not be changed after
|
||||
* construction.
|
||||
*
|
||||
* \li \c OptionStretchElastic - Only meaningful in offline
|
||||
* mode, and the default in that mode. The audio will be
|
||||
* stretched at a variable rate, aimed at preserving the quality
|
||||
* of transient sounds as much as possible. The timings of low
|
||||
* activity regions between transients may be less exact than
|
||||
* when the precise flag is set.
|
||||
*
|
||||
* \li \c OptionStretchPrecise - Although still using a variable
|
||||
* stretch rate, the audio will be stretched so as to maintain
|
||||
* as close as possible to a linear stretch ratio throughout.
|
||||
* Timing may be better than when using \c OptionStretchElastic, at
|
||||
* slight cost to the sound quality of transients. This setting
|
||||
* is always used when running in real-time mode.
|
||||
*
|
||||
* 3. Flags prefixed \c OptionTransients control the component
|
||||
* frequency phase-reset mechanism that may be used at transient
|
||||
* points to provide clarity and realism to percussion and other
|
||||
@@ -293,6 +272,10 @@ public:
|
||||
* setting). This usually leads to better focus in the centre
|
||||
* but a loss of stereo space and width. Any channels beyond
|
||||
* the first two are processed individually.
|
||||
*
|
||||
* Finally, flags prefixed \c OptionStretch are obsolete flags
|
||||
* provided for backward compatibility only. They are ignored by
|
||||
* the stretcher.
|
||||
*/
|
||||
|
||||
enum Option {
|
||||
@@ -300,8 +283,8 @@ public:
|
||||
OptionProcessOffline = 0x00000000,
|
||||
OptionProcessRealTime = 0x00000001,
|
||||
|
||||
OptionStretchElastic = 0x00000000,
|
||||
OptionStretchPrecise = 0x00000010,
|
||||
OptionStretchElastic = 0x00000000, // obsolete
|
||||
OptionStretchPrecise = 0x00000010, // obsolete
|
||||
|
||||
OptionTransientsCrisp = 0x00000000,
|
||||
OptionTransientsMixed = 0x00000100,
|
||||
|
||||
@@ -57,8 +57,8 @@ enum RubberBandOption {
|
||||
RubberBandOptionProcessOffline = 0x00000000,
|
||||
RubberBandOptionProcessRealTime = 0x00000001,
|
||||
|
||||
RubberBandOptionStretchElastic = 0x00000000,
|
||||
RubberBandOptionStretchPrecise = 0x00000010,
|
||||
RubberBandOptionStretchElastic = 0x00000000, // obsolete
|
||||
RubberBandOptionStretchPrecise = 0x00000010, // obsolete
|
||||
|
||||
RubberBandOptionTransientsCrisp = 0x00000000,
|
||||
RubberBandOptionTransientsMixed = 0x00000100,
|
||||
|
||||
@@ -74,11 +74,8 @@ StretchCalculator::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
|
||||
|
||||
std::vector<int>
|
||||
StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
const std::vector<float> &phaseResetDf,
|
||||
const std::vector<float> &stretchDf)
|
||||
const std::vector<float> &phaseResetDf)
|
||||
{
|
||||
assert(phaseResetDf.size() == stretchDf.size());
|
||||
|
||||
m_peaks = findPeaks(phaseResetDf);
|
||||
|
||||
size_t totalCount = phaseResetDf.size();
|
||||
@@ -107,16 +104,6 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
|
||||
size_t totalInput = 0, totalOutput = 0;
|
||||
|
||||
// For each region between two consecutive time sync points, we
|
||||
// want to take the number of output chunks to be allocated and
|
||||
// the detection function values within the range, and produce a
|
||||
// series of increments that sum to the number of output chunks,
|
||||
// such that each increment is displaced from the input increment
|
||||
// by an amount inversely proportional to the magnitude of the
|
||||
// stretch detection function at that input step.
|
||||
|
||||
size_t regionTotalChunks = 0;
|
||||
|
||||
std::vector<int> increments;
|
||||
|
||||
for (size_t i = 0; i <= peaks.size(); ++i) {
|
||||
@@ -147,41 +134,55 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
if (regionEndChunk > totalCount) regionEndChunk = totalCount;
|
||||
if (regionEnd > outputDuration) regionEnd = outputDuration;
|
||||
|
||||
if (regionEndChunk < regionStartChunk) regionEndChunk = regionStartChunk;
|
||||
if (regionEnd < regionStart) regionEnd = regionStart;
|
||||
|
||||
size_t regionDuration = regionEnd - regionStart;
|
||||
regionTotalChunks += regionDuration;
|
||||
|
||||
std::vector<float> dfRegion;
|
||||
size_t nchunks = regionEndChunk - regionStartChunk;
|
||||
|
||||
for (size_t j = regionStartChunk; j != regionEndChunk; ++j) {
|
||||
dfRegion.push_back(stretchDf[j]);
|
||||
if (nchunks == 0) {
|
||||
//!!!
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
std::cerr << "distributeRegion from " << regionStartChunk << " to " << regionEndChunk << " (samples " << regionStart << " to " << regionEnd << ")" << std::endl;
|
||||
}
|
||||
|
||||
dfRegion = smoothDF(dfRegion);
|
||||
|
||||
std::vector<int> regionIncrements = distributeRegion
|
||||
(dfRegion, regionDuration, ratio, phaseReset);
|
||||
|
||||
double per = double(regionDuration) / double(nchunks);
|
||||
double acc = 0.0;
|
||||
size_t nremaining = nchunks;
|
||||
size_t totalForRegion = 0;
|
||||
|
||||
for (size_t j = 0; j < regionIncrements.size(); ++j) {
|
||||
|
||||
int incr = regionIncrements[j];
|
||||
|
||||
if (j == 0 && phaseReset) increments.push_back(-incr);
|
||||
else increments.push_back(incr);
|
||||
|
||||
if (incr > 0) totalForRegion += incr;
|
||||
else totalForRegion += -incr;
|
||||
|
||||
if (phaseReset) {
|
||||
size_t incr;
|
||||
if (nchunks > 1) {
|
||||
incr = m_increment;
|
||||
if (incr > regionDuration) {
|
||||
incr = regionDuration;
|
||||
}
|
||||
} else {
|
||||
incr = regionDuration;
|
||||
}
|
||||
increments.push_back(- int64_t(incr));
|
||||
per = double(regionDuration - incr) / double(nchunks - 1);
|
||||
acc += incr;
|
||||
totalForRegion += incr;
|
||||
totalInput += m_increment;
|
||||
nremaining = nremaining - 1;
|
||||
}
|
||||
|
||||
if (totalForRegion != regionDuration) {
|
||||
std::cerr << "*** ERROR: distributeRegion returned wrong duration " << totalForRegion << ", expected " << regionDuration << std::endl;
|
||||
if (nremaining > 0) {
|
||||
for (size_t j = 0; j+1 < nremaining; ++j) {
|
||||
acc += per;
|
||||
size_t incr = size_t(round(acc - totalForRegion));
|
||||
increments.push_back(incr);
|
||||
totalForRegion += incr;
|
||||
totalInput += m_increment;
|
||||
}
|
||||
if (regionDuration > totalForRegion) {
|
||||
size_t final = regionDuration - totalForRegion;
|
||||
increments.push_back(final);
|
||||
totalForRegion += final;
|
||||
totalInput += m_increment;
|
||||
}
|
||||
}
|
||||
|
||||
totalOutput += totalForRegion;
|
||||
@@ -189,7 +190,6 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
|
||||
|
||||
if (m_debugLevel > 0) {
|
||||
std::cerr << "total input increment = " << totalInput << " (= " << totalInput / m_increment << " chunks), output = " << totalOutput << ", ratio = " << double(totalOutput)/double(totalInput) << ", ideal output " << size_t(ceil(totalInput * ratio)) << std::endl;
|
||||
std::cerr << "(region total = " << regionTotalChunks << ")" << std::endl;
|
||||
}
|
||||
|
||||
return increments;
|
||||
@@ -861,285 +861,5 @@ StretchCalculator::smoothDF(const std::vector<float> &df)
|
||||
return smoothedDF;
|
||||
}
|
||||
|
||||
std::vector<int>
|
||||
StretchCalculator::distributeRegion(const std::vector<float> &dfIn,
|
||||
size_t duration, float ratio, bool phaseReset)
|
||||
{
|
||||
std::vector<float> df(dfIn);
|
||||
std::vector<int> increments;
|
||||
|
||||
// The peak for the stretch detection function may appear after
|
||||
// the peak that we're using to calculate the start of the region.
|
||||
// We don't want that. If we find a peak in the first half of
|
||||
// the region, we should set all the values up to that point to
|
||||
// the same value as the peak.
|
||||
|
||||
// (This might not be subtle enough, especially if the region is
|
||||
// long -- we want a bound that corresponds to acoustic perception
|
||||
// of the audible bounce.)
|
||||
|
||||
for (size_t i = 1; i < df.size()/2; ++i) {
|
||||
if (df[i] < df[i-1]) {
|
||||
if (m_debugLevel > 1) {
|
||||
std::cerr << "stretch peak offset: " << i-1 << " (peak " << df[i-1] << ")" << std::endl;
|
||||
}
|
||||
for (size_t j = 0; j < i-1; ++j) {
|
||||
df[j] = df[i-1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float maxDf = 0;
|
||||
|
||||
for (size_t i = 0; i < df.size(); ++i) {
|
||||
if (i == 0 || df[i] > maxDf) maxDf = df[i];
|
||||
}
|
||||
|
||||
// We want to try to ensure the last 100ms or so (if possible) are
|
||||
// tending back towards the maximum df, so that the stretchiness
|
||||
// reduces at the end of the stretched region.
|
||||
|
||||
int reducedRegion = lrint((0.1 * m_sampleRate) / m_increment);
|
||||
if (reducedRegion > int(df.size()/5)) reducedRegion = df.size()/5;
|
||||
|
||||
for (int i = 0; i < reducedRegion; ++i) {
|
||||
size_t index = df.size() - reducedRegion + i;
|
||||
df[index] = df[index] + ((maxDf - df[index]) * i) / reducedRegion;
|
||||
}
|
||||
|
||||
long toAllot = long(duration) - long(m_increment * df.size());
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
std::cerr << "region of " << df.size() << " chunks, output duration " << duration << ", increment " << m_increment << ", toAllot " << toAllot << std::endl;
|
||||
}
|
||||
|
||||
size_t totalIncrement = 0;
|
||||
|
||||
// We place limits on the amount of displacement per chunk. if
|
||||
// ratio < 0, no increment should be larger than increment*ratio
|
||||
// or smaller than increment*ratio/2; if ratio > 0, none should be
|
||||
// smaller than increment*ratio or larger than increment*ratio*2.
|
||||
// We need to enforce this in the assignment of displacements to
|
||||
// allotments, not by trying to respond if something turns out
|
||||
// wrong.
|
||||
|
||||
// Note that the ratio is only provided to this function for the
|
||||
// purposes of establishing this bound to the displacement.
|
||||
|
||||
// so if
|
||||
// maxDisplacement / totalDisplacement > increment * ratio*2 - increment
|
||||
// (for ratio > 1)
|
||||
// or
|
||||
// maxDisplacement / totalDisplacement < increment * ratio/2
|
||||
// (for ratio < 1)
|
||||
|
||||
// then we need to adjust and accommodate
|
||||
|
||||
double totalDisplacement = 0;
|
||||
double maxDisplacement = 0; // min displacement will be 0 by definition
|
||||
|
||||
maxDf = 0;
|
||||
float adj = 0;
|
||||
|
||||
bool tooShort = true, tooLong = true;
|
||||
const int acceptableIterations = 10;
|
||||
int iteration = 0;
|
||||
int prevExtreme = 0;
|
||||
bool better = false;
|
||||
|
||||
while ((tooLong || tooShort) && iteration < acceptableIterations) {
|
||||
|
||||
++iteration;
|
||||
|
||||
tooLong = false;
|
||||
tooShort = false;
|
||||
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
|
||||
adj);
|
||||
|
||||
if (m_debugLevel > 1) {
|
||||
std::cerr << "totalDisplacement " << totalDisplacement << ", max " << maxDisplacement << " (maxDf " << maxDf << ", df count " << df.size() << ")" << std::endl;
|
||||
}
|
||||
|
||||
if (totalDisplacement == 0) {
|
||||
// Not usually a problem, in fact
|
||||
// std::cerr << "WARNING: totalDisplacement == 0 (duration " << duration << ", " << df.size() << " values in df)" << std::endl;
|
||||
if (!df.empty() && adj == 0) {
|
||||
tooLong = true; tooShort = true;
|
||||
adj = 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
int extremeIncrement = m_increment +
|
||||
lrint((toAllot * maxDisplacement) / totalDisplacement);
|
||||
|
||||
if (extremeIncrement < 0) {
|
||||
if (m_debugLevel > 0) {
|
||||
std::cerr << "NOTE: extreme increment " << extremeIncrement << " < 0, adjusting" << std::endl;
|
||||
}
|
||||
tooShort = true;
|
||||
} else {
|
||||
if (ratio < 1.0) {
|
||||
if (extremeIncrement > lrint(ceil(m_increment * ratio))) {
|
||||
std::cerr << "WARNING: extreme increment "
|
||||
<< extremeIncrement << " > "
|
||||
<< m_increment * ratio << std::endl;
|
||||
} else if (extremeIncrement < (m_increment * ratio) / 2) {
|
||||
if (m_debugLevel > 0) {
|
||||
std::cerr << "NOTE: extreme increment "
|
||||
<< extremeIncrement << " < "
|
||||
<< (m_increment * ratio) / 2
|
||||
<< ", adjusting" << std::endl;
|
||||
}
|
||||
tooShort = true;
|
||||
if (iteration > 0) {
|
||||
better = (extremeIncrement > prevExtreme);
|
||||
}
|
||||
prevExtreme = extremeIncrement;
|
||||
}
|
||||
} else {
|
||||
if (extremeIncrement > m_increment * ratio * 2) {
|
||||
if (m_debugLevel > 0) {
|
||||
std::cerr << "NOTE: extreme increment "
|
||||
<< extremeIncrement << " > "
|
||||
<< m_increment * ratio * 2
|
||||
<< ", adjusting" << std::endl;
|
||||
}
|
||||
tooLong = true;
|
||||
if (iteration > 0) {
|
||||
better = (extremeIncrement < prevExtreme);
|
||||
}
|
||||
prevExtreme = extremeIncrement;
|
||||
} else if (extremeIncrement < lrint(floor(m_increment * ratio))) {
|
||||
std::cerr << "WARNING: extreme increment "
|
||||
<< extremeIncrement << " < "
|
||||
<< m_increment * ratio << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tooLong || tooShort) {
|
||||
// Need to make maxDisplacement smaller as a proportion of
|
||||
// the total displacement, yet ensure that the
|
||||
// displacements still sum to the total.
|
||||
adj += maxDf/10;
|
||||
}
|
||||
}
|
||||
|
||||
if (tooLong) {
|
||||
if (better) {
|
||||
// we were iterating in the right direction, so
|
||||
// leave things as they are (and undo that last tweak)
|
||||
std::cerr << "WARNING: No acceptable displacement adjustment found, using latest values:\nthis region could sound bad" << std::endl;
|
||||
adj -= maxDf/10;
|
||||
} else {
|
||||
std::cerr << "WARNING: No acceptable displacement adjustment found, using defaults:\nthis region could sound bad" << std::endl;
|
||||
adj = 1;
|
||||
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
|
||||
adj);
|
||||
}
|
||||
} else if (tooShort) {
|
||||
std::cerr << "WARNING: No acceptable displacement adjustment found, using flat distribution:\nthis region could sound bad" << std::endl;
|
||||
adj = 1;
|
||||
for (size_t i = 0; i < df.size(); ++i) {
|
||||
df[i] = 1.f;
|
||||
}
|
||||
calculateDisplacements(df, maxDf, totalDisplacement, maxDisplacement,
|
||||
adj);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < df.size(); ++i) {
|
||||
|
||||
double displacement = maxDf - df[i];
|
||||
if (displacement < 0) displacement -= adj;
|
||||
else displacement += adj;
|
||||
|
||||
if (i == 0 && phaseReset) {
|
||||
if (m_debugLevel > 2) {
|
||||
std::cerr << "Phase reset at first chunk" << std::endl;
|
||||
}
|
||||
if (df.size() == 1) {
|
||||
increments.push_back(duration);
|
||||
totalIncrement += duration;
|
||||
} else {
|
||||
increments.push_back(m_increment);
|
||||
totalIncrement += m_increment;
|
||||
}
|
||||
totalDisplacement -= displacement;
|
||||
continue;
|
||||
}
|
||||
|
||||
double theoreticalAllotment = 0;
|
||||
|
||||
if (totalDisplacement != 0) {
|
||||
theoreticalAllotment = (toAllot * displacement) / totalDisplacement;
|
||||
}
|
||||
int allotment = lrint(theoreticalAllotment);
|
||||
if (i + 1 == df.size()) allotment = toAllot;
|
||||
|
||||
int increment = m_increment + allotment;
|
||||
|
||||
if (increment < 0) {
|
||||
// this is a serious problem, the allocation is quite
|
||||
// wrong if it allows increment to diverge so far from the
|
||||
// input increment (though it can happen legitimately if
|
||||
// asked to squash very violently)
|
||||
std::cerr << "*** WARNING: increment " << increment << " <= 0, rounding to zero" << std::endl;
|
||||
|
||||
toAllot += m_increment;
|
||||
increment = 0;
|
||||
|
||||
} else {
|
||||
toAllot -= allotment;
|
||||
}
|
||||
|
||||
increments.push_back(increment);
|
||||
totalIncrement += increment;
|
||||
|
||||
totalDisplacement -= displacement;
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
std::cerr << "df " << df[i] << ", smoothed " << df[i] << ", disp " << displacement << ", allot " << theoreticalAllotment << ", incr " << increment << ", remain " << toAllot << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_debugLevel > 2) {
|
||||
std::cerr << "total increment: " << totalIncrement << ", left over: " << toAllot << " to allot, displacement " << totalDisplacement << std::endl;
|
||||
}
|
||||
|
||||
if (totalIncrement != duration) {
|
||||
std::cerr << "*** WARNING: calculated output duration " << totalIncrement << " != expected " << duration << std::endl;
|
||||
}
|
||||
|
||||
return increments;
|
||||
}
|
||||
|
||||
void
|
||||
StretchCalculator::calculateDisplacements(const std::vector<float> &df,
|
||||
float &maxDf,
|
||||
double &totalDisplacement,
|
||||
double &maxDisplacement,
|
||||
float adj) const
|
||||
{
|
||||
totalDisplacement = maxDisplacement = 0;
|
||||
|
||||
maxDf = 0;
|
||||
|
||||
for (size_t i = 0; i < df.size(); ++i) {
|
||||
if (i == 0 || df[i] > maxDf) maxDf = df[i];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < df.size(); ++i) {
|
||||
double displacement = maxDf - df[i];
|
||||
if (displacement < 0) displacement -= adj;
|
||||
else displacement += adj;
|
||||
totalDisplacement += displacement;
|
||||
if (i == 0 || displacement > maxDisplacement) {
|
||||
maxDisplacement = displacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,10 @@ public:
|
||||
/**
|
||||
* Calculate phase increments for a region of audio, given the
|
||||
* overall target stretch ratio, input duration in audio samples,
|
||||
* and the audio curves to use for identifying phase lock points
|
||||
* (lockAudioCurve) and for allocating stretches to relatively
|
||||
* less prominent points (stretchAudioCurve).
|
||||
* and the audio curves to use for identifying phase lock points.
|
||||
*/
|
||||
std::vector<int> calculate(double ratio, size_t inputDuration,
|
||||
const std::vector<float> &lockAudioCurve,
|
||||
const std::vector<float> &stretchAudioCurve);
|
||||
const std::vector<float> &lockAudioCurve);
|
||||
|
||||
/**
|
||||
* Calculate the phase increment for a single audio block, given
|
||||
@@ -96,16 +93,6 @@ protected:
|
||||
void mapPeaks(std::vector<Peak> &peaks, std::vector<size_t> &targets,
|
||||
size_t outputDuration, size_t totalCount);
|
||||
|
||||
std::vector<int> distributeRegion(const std::vector<float> ®ionCurve,
|
||||
size_t outputDuration, float ratio,
|
||||
bool phaseReset);
|
||||
|
||||
void calculateDisplacements(const std::vector<float> &df,
|
||||
float &maxDf,
|
||||
double &totalDisplacement,
|
||||
double &maxDisplacement,
|
||||
float adj) const;
|
||||
|
||||
size_t m_sampleRate;
|
||||
size_t m_increment;
|
||||
float m_prevDf;
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
|
||||
#include "audiocurves/PercussiveAudioCurve.h"
|
||||
#include "audiocurves/HighFrequencyAudioCurve.h"
|
||||
#include "audiocurves/SpectralDifferenceAudioCurve.h"
|
||||
#include "audiocurves/SilentAudioCurve.h"
|
||||
#include "audiocurves/ConstantAudioCurve.h"
|
||||
#include "audiocurves/CompoundAudioCurve.h"
|
||||
|
||||
#include "dsp/Resampler.h"
|
||||
@@ -105,7 +103,6 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
|
||||
m_lastProcessPhaseResetDf(16),
|
||||
m_emergencyScavenger(10, 4),
|
||||
m_phaseResetAudioCurve(0),
|
||||
m_stretchAudioCurve(0),
|
||||
m_silentAudioCurve(0),
|
||||
m_stretchCalculator(0),
|
||||
m_freq0(600),
|
||||
@@ -150,12 +147,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
|
||||
}
|
||||
|
||||
if (m_options & OptionProcessRealTime) {
|
||||
|
||||
m_realtime = true;
|
||||
|
||||
if (!(m_options & OptionStretchPrecise)) {
|
||||
m_options |= OptionStretchPrecise;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NO_THREADING
|
||||
@@ -203,7 +195,6 @@ RubberBandStretcher::Impl::~Impl()
|
||||
}
|
||||
|
||||
delete m_phaseResetAudioCurve;
|
||||
delete m_stretchAudioCurve;
|
||||
delete m_silentAudioCurve;
|
||||
delete m_stretchCalculator;
|
||||
delete m_studyFFT;
|
||||
@@ -249,7 +240,6 @@ RubberBandStretcher::Impl::reset()
|
||||
|
||||
m_mode = JustCreated;
|
||||
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
|
||||
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
|
||||
if (m_silentAudioCurve) m_silentAudioCurve->reset();
|
||||
m_inputDuration = 0;
|
||||
m_silentHistory = 0;
|
||||
@@ -701,10 +691,6 @@ RubberBandStretcher::Impl::configure()
|
||||
}
|
||||
}
|
||||
|
||||
// stretchAudioCurve is unused in RT mode; phaseResetAudioCurve,
|
||||
// silentAudioCurve and stretchCalculator however are used in all
|
||||
// modes
|
||||
|
||||
delete m_phaseResetAudioCurve;
|
||||
m_phaseResetAudioCurve = new CompoundAudioCurve
|
||||
(CompoundAudioCurve::Parameters(m_sampleRate, m_fftSize));
|
||||
@@ -714,17 +700,6 @@ RubberBandStretcher::Impl::configure()
|
||||
m_silentAudioCurve = new SilentAudioCurve
|
||||
(SilentAudioCurve::Parameters(m_sampleRate, m_fftSize));
|
||||
|
||||
if (!m_realtime) {
|
||||
delete m_stretchAudioCurve;
|
||||
if (!(m_options & OptionStretchPrecise)) {
|
||||
m_stretchAudioCurve = new SpectralDifferenceAudioCurve
|
||||
(SpectralDifferenceAudioCurve::Parameters(m_sampleRate, m_fftSize));
|
||||
} else {
|
||||
m_stretchAudioCurve = new ConstantAudioCurve
|
||||
(ConstantAudioCurve::Parameters(m_sampleRate, m_fftSize));
|
||||
}
|
||||
}
|
||||
|
||||
delete m_stretchCalculator;
|
||||
m_stretchCalculator = new StretchCalculator
|
||||
(m_sampleRate, m_increment,
|
||||
@@ -765,7 +740,6 @@ RubberBandStretcher::Impl::reconfigure()
|
||||
// the df vectors
|
||||
calculateStretch();
|
||||
m_phaseResetDf.clear();
|
||||
m_stretchDf.clear();
|
||||
m_silence.clear();
|
||||
m_inputDuration = 0;
|
||||
}
|
||||
@@ -854,9 +828,6 @@ RubberBandStretcher::Impl::reconfigure()
|
||||
if (m_fftSize != prevFftSize) {
|
||||
m_phaseResetAudioCurve->setFftSize(m_fftSize);
|
||||
m_silentAudioCurve->setFftSize(m_fftSize);
|
||||
if (m_stretchAudioCurve) {
|
||||
m_stretchAudioCurve->setFftSize(m_fftSize);
|
||||
}
|
||||
somethingChanged = true;
|
||||
}
|
||||
|
||||
@@ -1069,9 +1040,6 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
|
||||
|
||||
// cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: ";
|
||||
|
||||
df = m_stretchAudioCurve->processFloat(cd.fltbuf, m_increment);
|
||||
m_stretchDf.push_back(df);
|
||||
|
||||
df = m_silentAudioCurve->processFloat(cd.fltbuf, m_increment);
|
||||
bool silent = (df > 0.f);
|
||||
if (silent && m_debugLevel > 1) {
|
||||
@@ -1163,28 +1131,10 @@ RubberBandStretcher::Impl::calculateStretch()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
double prdm = 0, sdm = 0;
|
||||
if (!m_phaseResetDf.empty()) {
|
||||
for (int i = 0; i < (int)m_phaseResetDf.size(); ++i) {
|
||||
prdm += m_phaseResetDf[i];
|
||||
}
|
||||
prdm /= m_phaseResetDf.size();
|
||||
}
|
||||
if (!m_stretchDf.empty()) {
|
||||
for (int i = 0; i < (int)m_stretchDf.size(); ++i) {
|
||||
sdm += m_stretchDf[i];
|
||||
}
|
||||
sdm /= m_stretchDf.size();
|
||||
}
|
||||
std::cerr << "phase reset df mean = " << prdm << ", stretch df mean = " << sdm << std::endl;
|
||||
*/
|
||||
|
||||
std::vector<int> increments = m_stretchCalculator->calculate
|
||||
(getEffectiveRatio(),
|
||||
inputDuration,
|
||||
m_phaseResetDf,
|
||||
m_stretchDf);
|
||||
m_phaseResetDf);
|
||||
|
||||
int history = 0;
|
||||
for (size_t i = 0; i < increments.size(); ++i) {
|
||||
|
||||
@@ -221,18 +221,18 @@ protected:
|
||||
typedef std::set<ProcessThread *> ThreadSet;
|
||||
ThreadSet m_threadSet;
|
||||
|
||||
#if defined HAVE_IPP && !defined USE_SPEEX
|
||||
#if defined(HAVE_IPP) && !defined(NO_THREADING) && !defined(USE_BQRESAMPLER) && !defined(USE_SPEEX) && !defined(HAVE_LIBSAMPLERATE)
|
||||
// Exasperatingly, the IPP polyphase resampler does not appear to
|
||||
// be thread-safe as advertised -- a good reason to prefer the
|
||||
// Speex alternative
|
||||
// be thread-safe as advertised -- a good reason to prefer any of
|
||||
// the alternatives
|
||||
#define STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED 1
|
||||
Mutex m_resamplerMutex;
|
||||
#endif
|
||||
#endif
|
||||
#endif // ! NO_THREADING
|
||||
|
||||
size_t m_inputDuration;
|
||||
CompoundAudioCurve::Type m_detectorType;
|
||||
std::vector<float> m_phaseResetDf;
|
||||
std::vector<float> m_stretchDf;
|
||||
std::vector<bool> m_silence;
|
||||
int m_silentHistory;
|
||||
|
||||
@@ -246,7 +246,6 @@ protected:
|
||||
Scavenger<RingBuffer<float> > m_emergencyScavenger;
|
||||
|
||||
CompoundAudioCurve *m_phaseResetAudioCurve;
|
||||
AudioCurveCalculator *m_stretchAudioCurve;
|
||||
AudioCurveCalculator *m_silentAudioCurve;
|
||||
StretchCalculator *m_stretchCalculator;
|
||||
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
*/
|
||||
|
||||
#include "StretcherImpl.h"
|
||||
|
||||
#include "audiocurves/PercussiveAudioCurve.h"
|
||||
#include "audiocurves/HighFrequencyAudioCurve.h"
|
||||
#include "audiocurves/ConstantAudioCurve.h"
|
||||
|
||||
#include "StretchCalculator.h"
|
||||
#include "StretcherChannelData.h"
|
||||
|
||||
@@ -213,12 +208,10 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
|
||||
cd.setResampleBufSize(reqSize);
|
||||
}
|
||||
|
||||
#ifndef NO_THREADING
|
||||
#if defined HAVE_IPP && !defined USE_SPEEX
|
||||
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
|
||||
if (m_threaded) {
|
||||
m_resamplerMutex.lock();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (useMidSide) {
|
||||
@@ -235,12 +228,10 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
|
||||
1.0 / m_pitchScale,
|
||||
final);
|
||||
|
||||
#ifndef NO_THREADING
|
||||
#if defined HAVE_IPP && !defined USE_SPEEX
|
||||
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
|
||||
if (m_threaded) {
|
||||
m_resamplerMutex.unlock();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1102,12 +1093,11 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
|
||||
cd.setResampleBufSize(reqSize);
|
||||
}
|
||||
|
||||
#ifndef NO_THREADING
|
||||
#if defined HAVE_IPP && !defined USE_SPEEX
|
||||
|
||||
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
|
||||
if (m_threaded) {
|
||||
m_resamplerMutex.lock();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
size_t outframes = cd.resampler->resample(&cd.resamplebuf,
|
||||
@@ -1117,12 +1107,10 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
|
||||
1.0 / m_pitchScale,
|
||||
last);
|
||||
|
||||
#ifndef NO_THREADING
|
||||
#if defined HAVE_IPP && !defined USE_SPEEX
|
||||
#if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
|
||||
if (m_threaded) {
|
||||
m_resamplerMutex.unlock();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
writeOutput(*cd.outbuf, cd.resamplebuf,
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2022 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Library obtained by agreement with the copyright
|
||||
holders, you may redistribute and/or modify it under the terms
|
||||
described in that licence.
|
||||
|
||||
If you wish to distribute code using the Rubber Band Library
|
||||
under terms other than those of the GNU General Public License,
|
||||
you must obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#include "ConstantAudioCurve.h"
|
||||
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
|
||||
ConstantAudioCurve::ConstantAudioCurve(Parameters parameters) :
|
||||
AudioCurveCalculator(parameters)
|
||||
{
|
||||
}
|
||||
|
||||
ConstantAudioCurve::~ConstantAudioCurve()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ConstantAudioCurve::reset()
|
||||
{
|
||||
}
|
||||
|
||||
float
|
||||
ConstantAudioCurve::processFloat(const float *R__, int)
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
double
|
||||
ConstantAudioCurve::processDouble(const double *R__, int)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2022 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Library obtained by agreement with the copyright
|
||||
holders, you may redistribute and/or modify it under the terms
|
||||
described in that licence.
|
||||
|
||||
If you wish to distribute code using the Rubber Band Library
|
||||
under terms other than those of the GNU General Public License,
|
||||
you must obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#ifndef RUBBERBAND_CONSTANT_AUDIO_CURVE_H
|
||||
#define RUBBERBAND_CONSTANT_AUDIO_CURVE_H
|
||||
|
||||
#include "../dsp/AudioCurveCalculator.h"
|
||||
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
class ConstantAudioCurve : public AudioCurveCalculator
|
||||
{
|
||||
public:
|
||||
ConstantAudioCurve(Parameters parameters);
|
||||
virtual ~ConstantAudioCurve();
|
||||
|
||||
virtual float processFloat(const float *R__ mag, int increment);
|
||||
virtual double processDouble(const double *R__ mag, int increment);
|
||||
virtual void reset();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,107 +0,0 @@
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2022 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Library obtained by agreement with the copyright
|
||||
holders, you may redistribute and/or modify it under the terms
|
||||
described in that licence.
|
||||
|
||||
If you wish to distribute code using the Rubber Band Library
|
||||
under terms other than those of the GNU General Public License,
|
||||
you must obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#include "SpectralDifferenceAudioCurve.h"
|
||||
|
||||
#include "../system/Allocators.h"
|
||||
#include "../system/VectorOps.h"
|
||||
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
|
||||
SpectralDifferenceAudioCurve::SpectralDifferenceAudioCurve(Parameters parameters) :
|
||||
AudioCurveCalculator(parameters)
|
||||
{
|
||||
m_mag = allocate<double>(m_lastPerceivedBin + 1);
|
||||
m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
|
||||
v_zero(m_mag, m_lastPerceivedBin + 1);
|
||||
}
|
||||
|
||||
SpectralDifferenceAudioCurve::~SpectralDifferenceAudioCurve()
|
||||
{
|
||||
deallocate(m_mag);
|
||||
deallocate(m_tmpbuf);
|
||||
}
|
||||
|
||||
void
|
||||
SpectralDifferenceAudioCurve::reset()
|
||||
{
|
||||
v_zero(m_mag, m_lastPerceivedBin + 1);
|
||||
}
|
||||
|
||||
void
|
||||
SpectralDifferenceAudioCurve::setFftSize(int newSize)
|
||||
{
|
||||
deallocate(m_tmpbuf);
|
||||
deallocate(m_mag);
|
||||
AudioCurveCalculator::setFftSize(newSize);
|
||||
m_mag = allocate<double>(m_lastPerceivedBin + 1);
|
||||
m_tmpbuf = allocate<double>(m_lastPerceivedBin + 1);
|
||||
reset();
|
||||
}
|
||||
|
||||
float
|
||||
SpectralDifferenceAudioCurve::processFloat(const float *R__ mag, int)
|
||||
{
|
||||
double result = 0.0;
|
||||
|
||||
const int hs1 = m_lastPerceivedBin + 1;
|
||||
|
||||
v_convert(m_tmpbuf, mag, hs1);
|
||||
v_square(m_tmpbuf, hs1);
|
||||
v_subtract(m_mag, m_tmpbuf, hs1);
|
||||
v_abs(m_mag, hs1);
|
||||
v_sqrt(m_mag, hs1);
|
||||
|
||||
for (int i = 0; i < hs1; ++i) {
|
||||
result += m_mag[i];
|
||||
}
|
||||
|
||||
v_copy(m_mag, m_tmpbuf, hs1);
|
||||
return result;
|
||||
}
|
||||
|
||||
double
|
||||
SpectralDifferenceAudioCurve::processDouble(const double *R__ mag, int)
|
||||
{
|
||||
double result = 0.0;
|
||||
|
||||
const int hs1 = m_lastPerceivedBin + 1;
|
||||
|
||||
v_convert(m_tmpbuf, mag, hs1);
|
||||
v_square(m_tmpbuf, hs1);
|
||||
v_subtract(m_mag, m_tmpbuf, hs1);
|
||||
v_abs(m_mag, hs1);
|
||||
v_sqrt(m_mag, hs1);
|
||||
|
||||
for (int i = 0; i < hs1; ++i) {
|
||||
result += m_mag[i];
|
||||
}
|
||||
|
||||
v_copy(m_mag, m_tmpbuf, hs1);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
||||
|
||||
/*
|
||||
Rubber Band Library
|
||||
An audio time-stretching and pitch-shifting library.
|
||||
Copyright 2007-2022 Particular Programs Ltd.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version. See the file
|
||||
COPYING included with this distribution for more information.
|
||||
|
||||
Alternatively, if you have a valid commercial licence for the
|
||||
Rubber Band Library obtained by agreement with the copyright
|
||||
holders, you may redistribute and/or modify it under the terms
|
||||
described in that licence.
|
||||
|
||||
If you wish to distribute code using the Rubber Band Library
|
||||
under terms other than those of the GNU General Public License,
|
||||
you must obtain a valid commercial licence before doing so.
|
||||
*/
|
||||
|
||||
#ifndef RUBBERBAND_SPECTRALDIFFERENCE_AUDIO_CURVE_H
|
||||
#define RUBBERBAND_SPECTRALDIFFERENCE_AUDIO_CURVE_H
|
||||
|
||||
#include "../dsp/AudioCurveCalculator.h"
|
||||
#include "../dsp/Window.h"
|
||||
|
||||
namespace RubberBand
|
||||
{
|
||||
|
||||
class SpectralDifferenceAudioCurve : public AudioCurveCalculator
|
||||
{
|
||||
public:
|
||||
SpectralDifferenceAudioCurve(Parameters parameters);
|
||||
|
||||
virtual ~SpectralDifferenceAudioCurve();
|
||||
|
||||
virtual void setFftSize(int newSize);
|
||||
|
||||
virtual float processFloat(const float *R__ mag, int increment);
|
||||
virtual double processDouble(const double *R__ mag, int increment);
|
||||
virtual void reset();
|
||||
virtual const char *getUnit() const { return "V"; }
|
||||
|
||||
protected:
|
||||
double *R__ m_mag;
|
||||
double *R__ m_tmpbuf;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user