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
// float. Let's do that.
int max_denom = 96000;
int max_denom = 48000;
if (ratio > 1.0) {
max_denom = int(ceil(96000 / ratio));
max_denom = int(ceil(48000 / ratio));
}
int inum, idenom;

View File

@@ -298,6 +298,20 @@ R3Stretcher::createResampler()
m_resampler = std::unique_ptr<Resampler>
(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
@@ -645,24 +659,69 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final)
} else {
m_mode = ProcessMode::Processing;
}
size_t ws = m_channelData[0]->inbuf->getWriteSpace();
if (samples > ws) {
m_log.log(2, "R3Stretcher::process: insufficient space in input buffer, attempting consume before write");
consume();
ws = m_channelData[0]->inbuf->getWriteSpace();
}
if (samples > ws) {
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 < m_parameters.channels; ++c) {
auto newBuf = m_channelData[c]->inbuf->resized(newSize);
m_channelData[c]->inbuf = std::unique_ptr<RingBuffer<float>>(newBuf);
}
}
for (int c = 0; c < m_parameters.channels; ++c) {
m_channelData[c]->inbuf->write(input[c], samples);
int channels = m_parameters.channels;
int toWrite = int(samples);
bool resamplingBefore = false;
areWeResampling(&resamplingBefore, nullptr);
if (resamplingBefore) {
for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c);
m_channelAssembly.resampled[c] = cd->resampled.data();
}
toWrite = m_resampler->resample
(m_channelAssembly.resampled.data(),
m_channelData.at(0)->resampled.size(),
input,
int(samples),
1.0 / m_pitchScale,
final);
}
int written = 0;
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();
@@ -708,6 +767,9 @@ R3Stretcher::consume()
int channels = m_parameters.channels;
int inhop = m_inhop;
bool resamplingAfter = false;
areWeResampling(nullptr, &resamplingAfter);
double effectivePitchRatio = 1.0 / m_pitchScale;
if (m_resampler) {
effectivePitchRatio =
@@ -818,17 +880,8 @@ R3Stretcher::consume()
// Resample
bool resampling = false;
if (m_resampler) {
if (m_pitchScale != 1.0 ||
(m_parameters.options &
RubberBandStretcher::OptionPitchHighConsistency)) {
resampling = true;
}
}
int resampledCount = 0;
if (resampling) {
if (resamplingAfter) {
for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c);
m_channelAssembly.mixdown[c] = cd->mixdown.data();
@@ -846,7 +899,7 @@ R3Stretcher::consume()
// Emit
int writeCount = outhop;
if (resampling) {
if (resamplingAfter) {
writeCount = resampledCount;
}
if (!isRealTime()) {
@@ -871,7 +924,7 @@ R3Stretcher::consume()
for (int c = 0; c < channels; ++c) {
auto &cd = m_channelData.at(c);
if (resampling) {
if (resamplingAfter) {
cd->outbuf->write(cd->resampled.data(), writeCount);
} else {
cd->outbuf->write(cd->mixdown.data(), writeCount);

View File

@@ -398,6 +398,29 @@ protected:
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 {
return m_parameters.options &
RubberBandStretcher::OptionWindowShort;