Add resample-before mode

This commit is contained in:
Chris Cannam
2022-09-02 14:49:34 +01:00
parent deb84a5f78
commit 021de9d51c
3 changed files with 107 additions and 31 deletions

View File

@@ -1222,9 +1222,9 @@ D_Speex::setRatio(double ratio)
// Speex wants a ratio of two unsigned integers, not a single // Speex wants a ratio of two unsigned integers, not a single
// float. Let's do that. // float. Let's do that.
int max_denom = 96000; int max_denom = 48000;
if (ratio > 1.0) { if (ratio > 1.0) {
max_denom = int(ceil(96000 / ratio)); max_denom = int(ceil(48000 / ratio));
} }
int inum, idenom; int inum, idenom;

View File

@@ -298,6 +298,20 @@ R3Stretcher::createResampler()
m_resampler = std::unique_ptr<Resampler> m_resampler = std::unique_ptr<Resampler>
(new Resampler(resamplerParameters, m_parameters.channels)); (new Resampler(resamplerParameters, m_parameters.channels));
bool before, after;
areWeResampling(&before, &after);
if (before) {
if (after) {
m_log.log(0, "WARNING: createResampler: we think we are resampling both before and after!");
} else {
m_log.log(1, "createResampler: resampling before");
}
} else {
if (after) {
m_log.log(0, "createResampler: resampling after");
}
}
} }
void void
@@ -646,23 +660,68 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
m_mode = ProcessMode::Processing; m_mode = ProcessMode::Processing;
} }
size_t ws = m_channelData[0]->inbuf->getWriteSpace(); int channels = m_parameters.channels;
if (samples > ws) { int toWrite = int(samples);
m_log.log(2, "R3Stretcher::process: insufficient space in input buffer, attempting consume before write");
consume(); bool resamplingBefore = false;
ws = m_channelData[0]->inbuf->getWriteSpace(); areWeResampling(&resamplingBefore, nullptr);
}
if (samples > ws) { if (resamplingBefore) {
m_log.log(0, "R3Stretcher::process: WARNING: Forced to increase input buffer size. Either setMaxProcessSize was not properly called or process is being called repeatedly without retrieve. Write space and samples", ws, samples);
size_t newSize = m_channelData[0]->inbuf->getSize() - ws + samples; for (int c = 0; c < channels; ++c) {
for (int c = 0; c < m_parameters.channels; ++c) { auto &cd = m_channelData.at(c);
auto newBuf = m_channelData[c]->inbuf->resized(newSize); m_channelAssembly.resampled[c] = cd->resampled.data();
m_channelData[c]->inbuf = std::unique_ptr<RingBuffer<float>>(newBuf);
} }
toWrite = m_resampler->resample
(m_channelAssembly.resampled.data(),
m_channelData.at(0)->resampled.size(),
input,
int(samples),
1.0 / m_pitchScale,
final);
} }
for (int c = 0; c < m_parameters.channels; ++c) { int written = 0;
m_channelData[c]->inbuf->write(input[c], samples);
while (written < toWrite) {
int remaining = toWrite - written;
int ws = m_channelData[0]->inbuf->getWriteSpace();
if (ws == 0) {
consume();
ws = m_channelData[0]->inbuf->getWriteSpace();
}
if (ws == 0) {
m_log.log(0, "R3Stretcher::process: WARNING: Forced to increase input buffer size. Either setMaxProcessSize was not properly called, process is being called repeatedly without retrieve, or an internal error has led to an incorrect resampler output calculation. Samples to write", toWrite);
size_t newSize = m_channelData[0]->inbuf->getSize() + toWrite;
for (int c = 0; c < m_parameters.channels; ++c) {
auto newBuf = m_channelData[c]->inbuf->resized(newSize);
m_channelData[c]->inbuf =
std::unique_ptr<RingBuffer<float>>(newBuf);
}
continue;
}
int toWriteHere = remaining;
if (toWriteHere > ws) {
toWriteHere = ws;
}
for (int c = 0; c < m_parameters.channels; ++c) {
if (resamplingBefore) {
m_channelData[c]->inbuf->write
(m_channelData.at(c)->resampled.data() + written,
toWriteHere);
} else {
m_channelData[c]->inbuf->write
(input[c] + written, toWriteHere);
}
}
written += toWriteHere;
} }
consume(); consume();
@@ -708,6 +767,9 @@ R3Stretcher::consume()
int channels = m_parameters.channels; int channels = m_parameters.channels;
int inhop = m_inhop; int inhop = m_inhop;
bool resamplingAfter = false;
areWeResampling(nullptr, &resamplingAfter);
double effectivePitchRatio = 1.0 / m_pitchScale; double effectivePitchRatio = 1.0 / m_pitchScale;
if (m_resampler) { if (m_resampler) {
effectivePitchRatio = effectivePitchRatio =
@@ -818,17 +880,8 @@ R3Stretcher::consume()
// Resample // Resample
bool resampling = false;
if (m_resampler) {
if (m_pitchScale != 1.0 ||
(m_parameters.options &
RubberBandStretcher::OptionPitchHighConsistency)) {
resampling = true;
}
}
int resampledCount = 0; int resampledCount = 0;
if (resampling) { if (resamplingAfter) {
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c); auto &cd = m_channelData.at(c);
m_channelAssembly.mixdown[c] = cd->mixdown.data(); m_channelAssembly.mixdown[c] = cd->mixdown.data();
@@ -846,7 +899,7 @@ R3Stretcher::consume()
// Emit // Emit
int writeCount = outhop; int writeCount = outhop;
if (resampling) { if (resamplingAfter) {
writeCount = resampledCount; writeCount = resampledCount;
} }
if (!isRealTime()) { if (!isRealTime()) {
@@ -871,7 +924,7 @@ R3Stretcher::consume()
for (int c = 0; c < channels; ++c) { for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c); auto &cd = m_channelData.at(c);
if (resampling) { if (resamplingAfter) {
cd->outbuf->write(cd->resampled.data(), writeCount); cd->outbuf->write(cd->resampled.data(), writeCount);
} else { } else {
cd->outbuf->write(cd->mixdown.data(), writeCount); cd->outbuf->write(cd->mixdown.data(), writeCount);

View File

@@ -398,6 +398,29 @@ protected:
RubberBandStretcher::OptionProcessRealTime; RubberBandStretcher::OptionProcessRealTime;
} }
void areWeResampling(bool *before, bool *after) const {
if (before) *before = false;
if (after) *after = false;
if (!m_resampler) return;
if (m_parameters.options &
RubberBandStretcher::OptionPitchHighConsistency) {
if (after) *after = true;
} else if (m_pitchScale != 1.0) {
if (m_pitchScale > 1.0 &&
(m_parameters.options &
RubberBandStretcher::OptionPitchHighQuality)) {
if (after) *after = true;
} else if (m_pitchScale < 1.0) {
if (after) *after = true;
} else {
if (before) *before = true;
}
}
}
bool isSingleWindowed() const { bool isSingleWindowed() const {
return m_parameters.options & return m_parameters.options &
RubberBandStretcher::OptionWindowShort; RubberBandStretcher::OptionWindowShort;