diff --git a/src/common/Resampler.cpp b/src/common/Resampler.cpp index d256820..ab2de9c 100644 --- a/src/common/Resampler.cpp +++ b/src/common/Resampler.cpp @@ -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; diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index fd719c1..6ad9074 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -298,6 +298,20 @@ R3Stretcher::createResampler() m_resampler = std::unique_ptr (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>(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>(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); diff --git a/src/finer/R3Stretcher.h b/src/finer/R3Stretcher.h index daf9090..07dde2e 100644 --- a/src/finer/R3Stretcher.h +++ b/src/finer/R3Stretcher.h @@ -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;