diff --git a/src/finer/R3StretcherImpl.cpp b/src/finer/R3StretcherImpl.cpp index bae8894..5394dd8 100644 --- a/src/finer/R3StretcherImpl.cpp +++ b/src/finer/R3StretcherImpl.cpp @@ -29,6 +29,69 @@ namespace RubberBand { +R3StretcherImpl::R3StretcherImpl(Parameters parameters, + double initialTimeRatio, + double initialPitchScale) : + m_parameters(parameters), + m_timeRatio(initialTimeRatio), + m_pitchScale(initialPitchScale), + m_guide(Guide::Parameters(m_parameters.sampleRate, parameters.logger)), + m_guideConfiguration(m_guide.getConfiguration()), + m_channelAssembly(m_parameters.channels), + m_troughPicker(m_guideConfiguration.classificationFftSize / 2 + 1), + m_inhop(1), + m_prevOuthop(1), + m_draining(false) +{ + BinSegmenter::Parameters segmenterParameters + (m_guideConfiguration.classificationFftSize, + m_parameters.sampleRate); + BinClassifier::Parameters classifierParameters + (m_guideConfiguration.classificationFftSize / 2 + 1, + 9, 1, 10, 2.0, 2.0, 1.0e-7); + + int inRingBufferSize = m_guideConfiguration.longestFftSize * 2; + int outRingBufferSize = m_guideConfiguration.longestFftSize * 16; + + for (int c = 0; c < m_parameters.channels; ++c) { + m_channelData.push_back(std::make_shared + (segmenterParameters, + classifierParameters, + m_guideConfiguration.longestFftSize, + inRingBufferSize, + outRingBufferSize)); + for (auto band: m_guideConfiguration.fftBandLimits) { + int fftSize = band.fftSize; + m_channelData[c]->scales[fftSize] = + std::make_shared + (fftSize, m_guideConfiguration.longestFftSize); + } + } + + for (auto band: m_guideConfiguration.fftBandLimits) { + int fftSize = band.fftSize; + GuidedPhaseAdvance::Parameters guidedParameters + (fftSize, m_parameters.sampleRate, m_parameters.channels, + m_parameters.logger); + m_scaleData[fftSize] = std::make_shared(guidedParameters); + } + + m_calculator = std::unique_ptr + (new StretchCalculator(int(round(m_parameters.sampleRate)), //!!! which is a double... + 1, false)); // no fixed inputIncrement + + Resampler::Parameters resamplerParameters; + resamplerParameters.quality = Resampler::FastestTolerable; + resamplerParameters.dynamism = Resampler::RatioOftenChanging; + resamplerParameters.ratioChange = Resampler::SmoothRatioChange; + resamplerParameters.initialSampleRate = m_parameters.sampleRate; + resamplerParameters.maxBufferSize = m_guideConfiguration.longestFftSize; //!!!??? + m_resampler = std::unique_ptr + (new Resampler(resamplerParameters, m_parameters.channels)); + + calculateHop(); +} + void R3StretcherImpl::setTimeRatio(double ratio) { @@ -180,6 +243,7 @@ R3StretcherImpl::consume() { double ratio = getEffectiveRatio(); int longest = m_guideConfiguration.longestFftSize; + int channels = m_parameters.channels; m_calculator->setDebugLevel(3); @@ -213,7 +277,7 @@ R3StretcherImpl::consume() // Analysis - for (int c = 0; c < m_parameters.channels; ++c) { + for (int c = 0; c < channels; ++c) { analyseChannel(c, m_prevOuthop); } @@ -221,7 +285,7 @@ R3StretcherImpl::consume() for (auto &it : m_channelData[0]->scales) { int fftSize = it.first; - for (int c = 0; c < m_parameters.channels; ++c) { + for (int c = 0; c < channels; ++c) { auto &cd = m_channelData.at(c); auto &scale = cd->scales.at(fftSize); m_channelAssembly.mag[c] = scale->mag.data(); @@ -241,9 +305,46 @@ R3StretcherImpl::consume() // Resynthesis - for (int c = 0; c < m_parameters.channels; ++c) { + for (int c = 0; c < channels; ++c) { synthesiseChannel(c, outhop); } + + // Resample + + int resampledCount = 0; + if (m_resampler) { + for (int c = 0; c < channels; ++c) { + auto &cd = m_channelData.at(c); + m_channelAssembly.mixdown[c] = cd->mixdown.data(); + m_channelAssembly.resampled[c] = cd->resampled.data(); + } + resampledCount = m_resampler->resample + (m_channelAssembly.resampled.data(), + m_channelData[0]->resampled.size(), + m_channelAssembly.mixdown.data(), + outhop, + 1.0 / m_pitchScale, + m_draining && readSpace < longest); + } + + // Emit + + for (int c = 0; c < channels; ++c) { + auto &cd = m_channelData.at(c); + if (m_resampler) { + cd->outbuf->write(cd->resampled.data(), resampledCount); + } else { + cd->outbuf->write(cd->mixdown.data(), outhop); + } + + int readSpace = cd->inbuf->getReadSpace(); + if (readSpace < m_inhop) { + // This should happen only when draining + cd->inbuf->skip(readSpace); + } else { + cd->inbuf->skip(m_inhop); + } + } } m_prevOuthop = outhop; @@ -496,35 +597,23 @@ R3StretcherImpl::synthesiseChannel(int c, int outhop) scale->accumulator.data() + toOffset); } - // Mix and emit this channel + // Mix this channel and move the accumulator along - double *mixptr = cd->mixdown.data(); + float *mixptr = cd->mixdown.data(); v_zero(mixptr, outhop); for (auto &it : cd->scales) { auto &scale = it.second; - v_add(mixptr, scale->accumulator.data(), outhop); - } - cd->outbuf->write(mixptr, outhop); - - for (auto &it : cd->scales) { - int fftSize = it.first; - auto &scale = it.second; double *accptr = scale->accumulator.data(); + for (int i = 0; i < outhop; ++i) { + mixptr[i] += float(accptr[i]); + } int n = scale->accumulator.size() - outhop; v_move(accptr, accptr + outhop, n); v_zero(accptr + n, outhop); } - - int readSpace = cd->inbuf->getReadSpace(); - if (readSpace < m_inhop) { - // This should happen only when draining - cd->inbuf->skip(readSpace); - } else { - cd->inbuf->skip(m_inhop); - } } } diff --git a/src/finer/R3StretcherImpl.h b/src/finer/R3StretcherImpl.h index 9cd349e..e8bea99 100644 --- a/src/finer/R3StretcherImpl.h +++ b/src/finer/R3StretcherImpl.h @@ -57,64 +57,7 @@ public: R3StretcherImpl(Parameters parameters, double initialTimeRatio, - double initialPitchScale) : - m_parameters(parameters), - m_timeRatio(initialTimeRatio), - m_pitchScale(initialPitchScale), - m_guide(Guide::Parameters(m_parameters.sampleRate, parameters.logger)), - m_guideConfiguration(m_guide.getConfiguration()), - m_channelAssembly(m_parameters.channels), - m_troughPicker(m_guideConfiguration.classificationFftSize / 2 + 1), - m_inhop(1), - m_prevOuthop(1), - m_draining(false) - { - BinSegmenter::Parameters segmenterParameters - (m_guideConfiguration.classificationFftSize, - m_parameters.sampleRate); - BinClassifier::Parameters classifierParameters - (m_guideConfiguration.classificationFftSize / 2 + 1, - 9, 1, 10, 2.0, 2.0, 1.0e-7); - - int ringBufferSize = m_guideConfiguration.longestFftSize * 2; - - for (int c = 0; c < m_parameters.channels; ++c) { - m_channelData.push_back(std::make_shared - (segmenterParameters, - classifierParameters, - ringBufferSize)); - for (auto band: m_guideConfiguration.fftBandLimits) { - int fftSize = band.fftSize; - m_channelData[c]->scales[fftSize] = - std::make_shared - (fftSize, m_guideConfiguration.longestFftSize); - } - } - - for (auto band: m_guideConfiguration.fftBandLimits) { - int fftSize = band.fftSize; - GuidedPhaseAdvance::Parameters guidedParameters - (fftSize, m_parameters.sampleRate, m_parameters.channels, - m_parameters.logger); - m_scaleData[fftSize] = std::make_shared(guidedParameters); - } - - m_calculator = std::unique_ptr - (new StretchCalculator(int(round(m_parameters.sampleRate)), //!!! which is a double... - 1, false)); // no fixed inputIncrement - - Resampler::Parameters resamplerParameters; - resamplerParameters.quality = Resampler::FastestTolerable; - resamplerParameters.dynamism = Resampler::RatioOftenChanging; - resamplerParameters.ratioChange = Resampler::SmoothRatioChange; - resamplerParameters.initialSampleRate = m_parameters.sampleRate; - resamplerParameters.maxBufferSize = m_guideConfiguration.longestFftSize; //!!!??? - m_resampler = std::unique_ptr - (new Resampler(resamplerParameters, m_parameters.channels)); - - calculateHop(); - } - + double initialPitchScale); ~R3StretcherImpl() { } void reset(); @@ -189,20 +132,24 @@ protected: BinSegmenter::Segmentation prevSegmentation; BinSegmenter::Segmentation nextSegmentation; Guide::Guidance guidance; - FixedVector mixdown; + FixedVector mixdown; + FixedVector resampled; std::unique_ptr> inbuf; std::unique_ptr> outbuf; ChannelData(BinSegmenter::Parameters segmenterParameters, BinClassifier::Parameters classifierParameters, - int ringBufferSize) : + int longestFftSize, + int inRingBufferSize, + int outRingBufferSize) : scales(), readahead(segmenterParameters.fftSize), segmenter(new BinSegmenter(segmenterParameters, classifierParameters)), segmentation(), prevSegmentation(), nextSegmentation(), - mixdown(ringBufferSize, 0.f), //!!! could be shorter (bound is the max fft size I think) - inbuf(new RingBuffer(ringBufferSize)), - outbuf(new RingBuffer(ringBufferSize)) { } + mixdown(longestFftSize, 0.f), // though it could be shorter + resampled(outRingBufferSize, 0.f), + inbuf(new RingBuffer(inRingBufferSize)), + outbuf(new RingBuffer(outRingBufferSize)) { } }; struct ChannelAssembly { @@ -212,9 +159,12 @@ protected: FixedVector phase; FixedVector guidance; FixedVector outPhase; + FixedVector mixdown; + FixedVector resampled; ChannelAssembly(int channels) : mag(channels, nullptr), phase(channels, nullptr), - guidance(channels, nullptr), outPhase(channels, nullptr) { } + guidance(channels, nullptr), outPhase(channels, nullptr), + mixdown(channels, nullptr), resampled(channels, nullptr) { } }; struct ScaleData {