Remove elastic/loose processing support

This commit is contained in:
Chris Cannam
2022-05-18 14:12:57 +01:00
parent 4cff174166
commit 80473f8735
13 changed files with 79 additions and 710 deletions

View File

@@ -90,7 +90,7 @@ int main(int argc, char **argv)
double frequencyshift = 1.0; double frequencyshift = 1.0;
int debug = 0; int debug = 0;
bool realtime = false; bool realtime = false;
bool precise = true; bool precisiongiven = false;
int threading = 0; int threading = 0;
bool lamination = true; bool lamination = true;
bool longwin = false; bool longwin = false;
@@ -179,8 +179,8 @@ int main(int argc, char **argv)
case 'f': frequencyshift = atof(optarg); haveRatio = true; break; case 'f': frequencyshift = atof(optarg); haveRatio = true; break;
case 'd': debug = atoi(optarg); break; case 'd': debug = atoi(optarg); break;
case 'R': realtime = true; break; case 'R': realtime = true; break;
case 'L': precise = false; break; case 'L': precisiongiven = true; break;
case 'P': precise = true; break; case 'P': precisiongiven = true; break;
case 'F': formant = true; break; case 'F': formant = true; break;
case '0': threading = 1; break; case '0': threading = 1; break;
case '@': threading = 2; 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 << "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 << "for most situations. The default is to use none of these options." << endl;
cerr << endl; cerr << endl;
cerr << " -L, --loose Relax timing in hope of better transient preservation" << endl; cerr << " -R, --realtime Select realtime mode (implies --no-threads)." << endl;
cerr << " -P, --precise Ignored: The opposite of -L, this is default from 1.6" << endl; cerr << " This utility does not do realtime stream processing;" << endl;
cerr << " -R, --realtime Select realtime mode (implies --no-threads)" << 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 << " --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 << " --threads Assume multi-CPU even if only one CPU is identified" << endl;
cerr << " --no-transients Disable phase resynchronisation at transients" << 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 << " (at a cost in width and individual channel quality)" << endl;
cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl; cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl;
cerr << " with reduced gain if clipping occurs" << 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 << endl;
cerr << " -d<N>, --debug <N> Select debug level (N = 0,1,2,3); default 0, full 3" << 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; cerr << " (N.B. debug level 3 includes audible ticks in output)" << endl;
@@ -330,6 +333,11 @@ int main(int argc, char **argv)
hqpitch = false; 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) { switch (crispness) {
case -1: crispness = 5; break; case -1: crispness = 5; break;
case 0: detector = CompoundDetector; transients = NoTransients; lamination = false; longwin = true; shortwin = false; 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; RubberBandStretcher::Options options = 0;
if (realtime) options |= RubberBandStretcher::OptionProcessRealTime; if (realtime) options |= RubberBandStretcher::OptionProcessRealTime;
if (precise) options |= RubberBandStretcher::OptionStretchPrecise;
if (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent; if (!lamination) options |= RubberBandStretcher::OptionPhaseIndependent;
if (longwin) options |= RubberBandStretcher::OptionWindowLong; if (longwin) options |= RubberBandStretcher::OptionWindowLong;
if (shortwin) options |= RubberBandStretcher::OptionWindowShort; if (shortwin) options |= RubberBandStretcher::OptionWindowShort;

View File

@@ -38,10 +38,8 @@ library_sources = [
'src/base/Profiler.cpp', 'src/base/Profiler.cpp',
'src/dsp/AudioCurveCalculator.cpp', 'src/dsp/AudioCurveCalculator.cpp',
'src/audiocurves/CompoundAudioCurve.cpp', 'src/audiocurves/CompoundAudioCurve.cpp',
'src/audiocurves/SpectralDifferenceAudioCurve.cpp',
'src/audiocurves/HighFrequencyAudioCurve.cpp', 'src/audiocurves/HighFrequencyAudioCurve.cpp',
'src/audiocurves/SilentAudioCurve.cpp', 'src/audiocurves/SilentAudioCurve.cpp',
'src/audiocurves/ConstantAudioCurve.cpp',
'src/audiocurves/PercussiveAudioCurve.cpp', 'src/audiocurves/PercussiveAudioCurve.cpp',
'src/dsp/Resampler.cpp', 'src/dsp/Resampler.cpp',
'src/dsp/FFT.cpp', 'src/dsp/FFT.cpp',

View File

@@ -109,27 +109,6 @@ public:
* non-real-time operation on seekable files: Offline; real-time * non-real-time operation on seekable files: Offline; real-time
* or streaming operation: RealTime. * 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 * 3. Flags prefixed \c OptionTransients control the component
* frequency phase-reset mechanism that may be used at transient * frequency phase-reset mechanism that may be used at transient
* points to provide clarity and realism to percussion and other * 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 * setting). This usually leads to better focus in the centre
* but a loss of stereo space and width. Any channels beyond * but a loss of stereo space and width. Any channels beyond
* the first two are processed individually. * 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 { enum Option {
@@ -300,8 +283,8 @@ public:
OptionProcessOffline = 0x00000000, OptionProcessOffline = 0x00000000,
OptionProcessRealTime = 0x00000001, OptionProcessRealTime = 0x00000001,
OptionStretchElastic = 0x00000000, OptionStretchElastic = 0x00000000, // obsolete
OptionStretchPrecise = 0x00000010, OptionStretchPrecise = 0x00000010, // obsolete
OptionTransientsCrisp = 0x00000000, OptionTransientsCrisp = 0x00000000,
OptionTransientsMixed = 0x00000100, OptionTransientsMixed = 0x00000100,

View File

@@ -57,8 +57,8 @@ enum RubberBandOption {
RubberBandOptionProcessOffline = 0x00000000, RubberBandOptionProcessOffline = 0x00000000,
RubberBandOptionProcessRealTime = 0x00000001, RubberBandOptionProcessRealTime = 0x00000001,
RubberBandOptionStretchElastic = 0x00000000, RubberBandOptionStretchElastic = 0x00000000, // obsolete
RubberBandOptionStretchPrecise = 0x00000010, RubberBandOptionStretchPrecise = 0x00000010, // obsolete
RubberBandOptionTransientsCrisp = 0x00000000, RubberBandOptionTransientsCrisp = 0x00000000,
RubberBandOptionTransientsMixed = 0x00000100, RubberBandOptionTransientsMixed = 0x00000100,

View File

@@ -74,11 +74,8 @@ StretchCalculator::setKeyFrameMap(const std::map<size_t, size_t> &mapping)
std::vector<int> std::vector<int>
StretchCalculator::calculate(double ratio, size_t inputDuration, StretchCalculator::calculate(double ratio, size_t inputDuration,
const std::vector<float> &phaseResetDf, const std::vector<float> &phaseResetDf)
const std::vector<float> &stretchDf)
{ {
assert(phaseResetDf.size() == stretchDf.size());
m_peaks = findPeaks(phaseResetDf); m_peaks = findPeaks(phaseResetDf);
size_t totalCount = phaseResetDf.size(); size_t totalCount = phaseResetDf.size();
@@ -107,16 +104,6 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
size_t totalInput = 0, totalOutput = 0; 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; std::vector<int> increments;
for (size_t i = 0; i <= peaks.size(); ++i) { 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 (regionEndChunk > totalCount) regionEndChunk = totalCount;
if (regionEnd > outputDuration) regionEnd = outputDuration; if (regionEnd > outputDuration) regionEnd = outputDuration;
if (regionEndChunk < regionStartChunk) regionEndChunk = regionStartChunk;
if (regionEnd < regionStart) regionEnd = regionStart;
size_t regionDuration = 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) { if (nchunks == 0) {
dfRegion.push_back(stretchDf[j]); //!!!
break;
} }
if (m_debugLevel > 1) { double per = double(regionDuration) / double(nchunks);
std::cerr << "distributeRegion from " << regionStartChunk << " to " << regionEndChunk << " (samples " << regionStart << " to " << regionEnd << ")" << std::endl; double acc = 0.0;
} size_t nremaining = nchunks;
dfRegion = smoothDF(dfRegion);
std::vector<int> regionIncrements = distributeRegion
(dfRegion, regionDuration, ratio, phaseReset);
size_t totalForRegion = 0; size_t totalForRegion = 0;
for (size_t j = 0; j < regionIncrements.size(); ++j) { if (phaseReset) {
size_t incr;
int incr = regionIncrements[j]; if (nchunks > 1) {
incr = m_increment;
if (j == 0 && phaseReset) increments.push_back(-incr); if (incr > regionDuration) {
else increments.push_back(incr); incr = regionDuration;
}
if (incr > 0) totalForRegion += incr; } else {
else totalForRegion += -incr; incr = regionDuration;
}
increments.push_back(- int64_t(incr));
per = double(regionDuration - incr) / double(nchunks - 1);
acc += incr;
totalForRegion += incr;
totalInput += m_increment; totalInput += m_increment;
nremaining = nremaining - 1;
} }
if (totalForRegion != regionDuration) { if (nremaining > 0) {
std::cerr << "*** ERROR: distributeRegion returned wrong duration " << totalForRegion << ", expected " << regionDuration << std::endl; 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; totalOutput += totalForRegion;
@@ -189,7 +190,6 @@ StretchCalculator::calculate(double ratio, size_t inputDuration,
if (m_debugLevel > 0) { 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 << "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; return increments;
@@ -861,285 +861,5 @@ StretchCalculator::smoothDF(const std::vector<float> &df)
return smoothedDF; 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;
}
}
}
} }

View File

@@ -51,13 +51,10 @@ public:
/** /**
* Calculate phase increments for a region of audio, given the * Calculate phase increments for a region of audio, given the
* overall target stretch ratio, input duration in audio samples, * overall target stretch ratio, input duration in audio samples,
* and the audio curves to use for identifying phase lock points * and the audio curves to use for identifying phase lock points.
* (lockAudioCurve) and for allocating stretches to relatively
* less prominent points (stretchAudioCurve).
*/ */
std::vector<int> calculate(double ratio, size_t inputDuration, std::vector<int> calculate(double ratio, size_t inputDuration,
const std::vector<float> &lockAudioCurve, const std::vector<float> &lockAudioCurve);
const std::vector<float> &stretchAudioCurve);
/** /**
* Calculate the phase increment for a single audio block, given * 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, void mapPeaks(std::vector<Peak> &peaks, std::vector<size_t> &targets,
size_t outputDuration, size_t totalCount); size_t outputDuration, size_t totalCount);
std::vector<int> distributeRegion(const std::vector<float> &regionCurve,
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_sampleRate;
size_t m_increment; size_t m_increment;
float m_prevDf; float m_prevDf;

View File

@@ -25,9 +25,7 @@
#include "audiocurves/PercussiveAudioCurve.h" #include "audiocurves/PercussiveAudioCurve.h"
#include "audiocurves/HighFrequencyAudioCurve.h" #include "audiocurves/HighFrequencyAudioCurve.h"
#include "audiocurves/SpectralDifferenceAudioCurve.h"
#include "audiocurves/SilentAudioCurve.h" #include "audiocurves/SilentAudioCurve.h"
#include "audiocurves/ConstantAudioCurve.h"
#include "audiocurves/CompoundAudioCurve.h" #include "audiocurves/CompoundAudioCurve.h"
#include "dsp/Resampler.h" #include "dsp/Resampler.h"
@@ -105,7 +103,6 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
m_lastProcessPhaseResetDf(16), m_lastProcessPhaseResetDf(16),
m_emergencyScavenger(10, 4), m_emergencyScavenger(10, 4),
m_phaseResetAudioCurve(0), m_phaseResetAudioCurve(0),
m_stretchAudioCurve(0),
m_silentAudioCurve(0), m_silentAudioCurve(0),
m_stretchCalculator(0), m_stretchCalculator(0),
m_freq0(600), m_freq0(600),
@@ -150,12 +147,7 @@ RubberBandStretcher::Impl::Impl(size_t sampleRate,
} }
if (m_options & OptionProcessRealTime) { if (m_options & OptionProcessRealTime) {
m_realtime = true; m_realtime = true;
if (!(m_options & OptionStretchPrecise)) {
m_options |= OptionStretchPrecise;
}
} }
#ifndef NO_THREADING #ifndef NO_THREADING
@@ -203,7 +195,6 @@ RubberBandStretcher::Impl::~Impl()
} }
delete m_phaseResetAudioCurve; delete m_phaseResetAudioCurve;
delete m_stretchAudioCurve;
delete m_silentAudioCurve; delete m_silentAudioCurve;
delete m_stretchCalculator; delete m_stretchCalculator;
delete m_studyFFT; delete m_studyFFT;
@@ -249,7 +240,6 @@ RubberBandStretcher::Impl::reset()
m_mode = JustCreated; m_mode = JustCreated;
if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset(); if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
if (m_silentAudioCurve) m_silentAudioCurve->reset(); if (m_silentAudioCurve) m_silentAudioCurve->reset();
m_inputDuration = 0; m_inputDuration = 0;
m_silentHistory = 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; delete m_phaseResetAudioCurve;
m_phaseResetAudioCurve = new CompoundAudioCurve m_phaseResetAudioCurve = new CompoundAudioCurve
(CompoundAudioCurve::Parameters(m_sampleRate, m_fftSize)); (CompoundAudioCurve::Parameters(m_sampleRate, m_fftSize));
@@ -714,17 +700,6 @@ RubberBandStretcher::Impl::configure()
m_silentAudioCurve = new SilentAudioCurve m_silentAudioCurve = new SilentAudioCurve
(SilentAudioCurve::Parameters(m_sampleRate, m_fftSize)); (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; delete m_stretchCalculator;
m_stretchCalculator = new StretchCalculator m_stretchCalculator = new StretchCalculator
(m_sampleRate, m_increment, (m_sampleRate, m_increment,
@@ -765,7 +740,6 @@ RubberBandStretcher::Impl::reconfigure()
// the df vectors // the df vectors
calculateStretch(); calculateStretch();
m_phaseResetDf.clear(); m_phaseResetDf.clear();
m_stretchDf.clear();
m_silence.clear(); m_silence.clear();
m_inputDuration = 0; m_inputDuration = 0;
} }
@@ -854,9 +828,6 @@ RubberBandStretcher::Impl::reconfigure()
if (m_fftSize != prevFftSize) { if (m_fftSize != prevFftSize) {
m_phaseResetAudioCurve->setFftSize(m_fftSize); m_phaseResetAudioCurve->setFftSize(m_fftSize);
m_silentAudioCurve->setFftSize(m_fftSize); m_silentAudioCurve->setFftSize(m_fftSize);
if (m_stretchAudioCurve) {
m_stretchAudioCurve->setFftSize(m_fftSize);
}
somethingChanged = true; somethingChanged = true;
} }
@@ -1069,9 +1040,6 @@ RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool
// cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: "; // 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); df = m_silentAudioCurve->processFloat(cd.fltbuf, m_increment);
bool silent = (df > 0.f); bool silent = (df > 0.f);
if (silent && m_debugLevel > 1) { 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 std::vector<int> increments = m_stretchCalculator->calculate
(getEffectiveRatio(), (getEffectiveRatio(),
inputDuration, inputDuration,
m_phaseResetDf, m_phaseResetDf);
m_stretchDf);
int history = 0; int history = 0;
for (size_t i = 0; i < increments.size(); ++i) { for (size_t i = 0; i < increments.size(); ++i) {

View File

@@ -221,18 +221,18 @@ protected:
typedef std::set<ProcessThread *> ThreadSet; typedef std::set<ProcessThread *> ThreadSet;
ThreadSet m_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 // Exasperatingly, the IPP polyphase resampler does not appear to
// be thread-safe as advertised -- a good reason to prefer the // be thread-safe as advertised -- a good reason to prefer any of
// Speex alternative // the alternatives
#define STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED 1
Mutex m_resamplerMutex; Mutex m_resamplerMutex;
#endif #endif
#endif #endif // ! NO_THREADING
size_t m_inputDuration; size_t m_inputDuration;
CompoundAudioCurve::Type m_detectorType; CompoundAudioCurve::Type m_detectorType;
std::vector<float> m_phaseResetDf; std::vector<float> m_phaseResetDf;
std::vector<float> m_stretchDf;
std::vector<bool> m_silence; std::vector<bool> m_silence;
int m_silentHistory; int m_silentHistory;
@@ -246,7 +246,6 @@ protected:
Scavenger<RingBuffer<float> > m_emergencyScavenger; Scavenger<RingBuffer<float> > m_emergencyScavenger;
CompoundAudioCurve *m_phaseResetAudioCurve; CompoundAudioCurve *m_phaseResetAudioCurve;
AudioCurveCalculator *m_stretchAudioCurve;
AudioCurveCalculator *m_silentAudioCurve; AudioCurveCalculator *m_silentAudioCurve;
StretchCalculator *m_stretchCalculator; StretchCalculator *m_stretchCalculator;

View File

@@ -22,11 +22,6 @@
*/ */
#include "StretcherImpl.h" #include "StretcherImpl.h"
#include "audiocurves/PercussiveAudioCurve.h"
#include "audiocurves/HighFrequencyAudioCurve.h"
#include "audiocurves/ConstantAudioCurve.h"
#include "StretchCalculator.h" #include "StretchCalculator.h"
#include "StretcherChannelData.h" #include "StretcherChannelData.h"
@@ -213,12 +208,10 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
cd.setResampleBufSize(reqSize); cd.setResampleBufSize(reqSize);
} }
#ifndef NO_THREADING #if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
#if defined HAVE_IPP && !defined USE_SPEEX
if (m_threaded) { if (m_threaded) {
m_resamplerMutex.lock(); m_resamplerMutex.lock();
} }
#endif
#endif #endif
if (useMidSide) { if (useMidSide) {
@@ -235,12 +228,10 @@ RubberBandStretcher::Impl::consumeChannel(size_t c,
1.0 / m_pitchScale, 1.0 / m_pitchScale,
final); final);
#ifndef NO_THREADING #if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
#if defined HAVE_IPP && !defined USE_SPEEX
if (m_threaded) { if (m_threaded) {
m_resamplerMutex.unlock(); m_resamplerMutex.unlock();
} }
#endif
#endif #endif
} }
@@ -1102,12 +1093,11 @@ RubberBandStretcher::Impl::writeChunk(size_t channel, size_t shiftIncrement, boo
cd.setResampleBufSize(reqSize); cd.setResampleBufSize(reqSize);
} }
#ifndef NO_THREADING
#if defined HAVE_IPP && !defined USE_SPEEX #if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
if (m_threaded) { if (m_threaded) {
m_resamplerMutex.lock(); m_resamplerMutex.lock();
} }
#endif
#endif #endif
size_t outframes = cd.resampler->resample(&cd.resamplebuf, 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, 1.0 / m_pitchScale,
last); last);
#ifndef NO_THREADING #if defined(STRETCHER_IMPL_RESAMPLER_MUTEX_REQUIRED)
#if defined HAVE_IPP && !defined USE_SPEEX
if (m_threaded) { if (m_threaded) {
m_resamplerMutex.unlock(); m_resamplerMutex.unlock();
} }
#endif
#endif #endif
writeOutput(*cd.outbuf, cd.resamplebuf, writeOutput(*cd.outbuf, cd.resamplebuf,

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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