From d3830870c03aa8340c337d2e0f208d174105184c Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Wed, 15 Mar 2023 18:01:21 +0000 Subject: [PATCH 1/2] Experiments with mid-side in R3 - in this code always used when channels=2 --- src/finer/R3Stretcher.cpp | 47 +++++++++++++++++++++++++++++++++++++-- src/finer/R3Stretcher.h | 5 ++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index 6cb6ae9..a4e0945 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -752,11 +752,13 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final) int maxResampleInput = int(floor(maxResampleOutput * m_pitchScale)); int resampleInput = std::min(remaining, maxResampleInput); if (resampleInput == 0) resampleInput = 1; + + prepareInput(input, inputIx, resampleInput); int resampleOutput = m_resampler->resample (m_channelAssembly.resampled.data(), maxResampleOutput, - input, + m_channelAssembly.input.data(), resampleInput, 1.0 / m_pitchScale, final); @@ -776,8 +778,11 @@ R3Stretcher::process(const float *const *input, size_t samples, bool final) m_log.log(2, "process: resamplingBefore is false, writing to inbuf from supplied data, former read space and samples being added", m_channelData[0]->inbuf->getReadSpace(), toWrite); + prepareInput(input, inputIx, toWrite); + for (int c = 0; c < m_parameters.channels; ++c) { - m_channelData[c]->inbuf->write(input[c] + inputIx, toWrite); + m_channelData[c]->inbuf->write + (m_channelAssembly.input[c], toWrite); } inputIx += toWrite; } @@ -814,9 +819,47 @@ R3Stretcher::retrieve(float *const *output, size_t samples) const } } + bool useMidSide = (m_parameters.channels == 2); //!!! + + if (useMidSide) { + for (int i = 0; i < got; ++i) { + float m = output[0][i]; + float s = output[1][i]; + float l = m + s; + float r = m - s; + output[0][i] = l; + output[1][i] = r; + } + } + return got; } +void +R3Stretcher::prepareInput(const float *const *input, int ix, int n) +{ + bool useMidSide = (m_parameters.channels == 2); //!!! + + if (useMidSide) { + auto &c0 = m_channelData.at(0)->mixdown; + auto &c1 = m_channelData.at(1)->mixdown; + for (int i = 0; i < n; ++i) { + float l = input[0][i + ix]; + float r = input[1][i + ix]; + float m = (l + r) / 2.f; + float s = (l - r) / 2.f; + c0[i] = m; + c1[i] = s; + } + m_channelAssembly.input[0] = m_channelData.at(0)->mixdown.data(); + m_channelAssembly.input[1] = m_channelData.at(1)->mixdown.data(); + } else { + for (int c = 0; c < m_parameters.channels; ++c) { + m_channelAssembly.input[c] = input[c] + ix; + } + } +} + void R3Stretcher::consume() { diff --git a/src/finer/R3Stretcher.h b/src/finer/R3Stretcher.h index d1b8308..57a3187 100644 --- a/src/finer/R3Stretcher.h +++ b/src/finer/R3Stretcher.h @@ -241,7 +241,7 @@ protected: BinClassifier::Classification::Residual), segmenter(new BinSegmenter(segmenterParameters)), segmentation(), prevSegmentation(), nextSegmentation(), - mixdown(longestFftSize, 0.f), + mixdown(inRingBufferSize, 0.f), resampled(outRingBufferSize, 0.f), inbuf(new RingBuffer(inRingBufferSize)), outbuf(new RingBuffer(outRingBufferSize)), @@ -263,6 +263,7 @@ protected: struct ChannelAssembly { // Vectors of bare pointers, used to package container data // from different channels into arguments for PhaseAdvance + FixedVector input; FixedVector mag; FixedVector phase; FixedVector prevMag; @@ -271,6 +272,7 @@ protected: FixedVector mixdown; FixedVector resampled; ChannelAssembly(int channels) : + input(channels, nullptr), mag(channels, nullptr), phase(channels, nullptr), prevMag(channels, nullptr), guidance(channels, nullptr), outPhase(channels, nullptr), mixdown(channels, nullptr), @@ -350,6 +352,7 @@ protected: }; ProcessMode m_mode; + void prepareInput(const float *const *input, int ix, int n); void consume(); void createResampler(); void calculateHop(); From e2611485d849e1c905c1e8f23944baddb4325d48 Mon Sep 17 00:00:00 2001 From: Chris Cannam Date: Fri, 17 Mar 2023 13:19:18 +0000 Subject: [PATCH 2/2] Use mid-side processing in channels-together mode in R3; for a more stable stereo image, ensure transient bins are reset in mid whenever they are in side --- src/finer/PhaseAdvance.h | 4 ++++ src/finer/R3Stretcher.cpp | 9 +++------ src/finer/R3Stretcher.h | 6 ++++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/finer/PhaseAdvance.h b/src/finer/PhaseAdvance.h index f5a6496..1c1384f 100644 --- a/src/finer/PhaseAdvance.h +++ b/src/finer/PhaseAdvance.h @@ -94,6 +94,7 @@ public: const process_t *const *prevMag, const Guide::Configuration &configuration, const Guide::Guidance *const *guidance, + bool usingMidSide, int inhop, int outhop) { @@ -197,6 +198,9 @@ public: process_t ph = 0.0; if (inRange(f, g->phaseReset) || inRange(f, g->kick)) { ph = phase[c][i]; + } else if (usingMidSide && channels == 2 && + c == 0 && inRange(f, guidance[1]->phaseReset)) { + ph = phase[c][i]; } else if (inhop == outhop) { ph = m_unlocked[c][i]; } else if (inRange (f, g->highUnlocked)) { diff --git a/src/finer/R3Stretcher.cpp b/src/finer/R3Stretcher.cpp index a4e0945..406133a 100644 --- a/src/finer/R3Stretcher.cpp +++ b/src/finer/R3Stretcher.cpp @@ -819,9 +819,7 @@ R3Stretcher::retrieve(float *const *output, size_t samples) const } } - bool useMidSide = (m_parameters.channels == 2); //!!! - - if (useMidSide) { + if (useMidSide()) { for (int i = 0; i < got; ++i) { float m = output[0][i]; float s = output[1][i]; @@ -838,9 +836,7 @@ R3Stretcher::retrieve(float *const *output, size_t samples) const void R3Stretcher::prepareInput(const float *const *input, int ix, int n) { - bool useMidSide = (m_parameters.channels == 2); //!!! - - if (useMidSide) { + if (useMidSide()) { auto &c0 = m_channelData.at(0)->mixdown; auto &c1 = m_channelData.at(1)->mixdown; for (int i = 0; i < n; ++i) { @@ -971,6 +967,7 @@ R3Stretcher::consume() m_channelAssembly.prevMag.data(), m_guideConfiguration, m_channelAssembly.guidance.data(), + useMidSide(), m_prevInhop, m_prevOuthop); } diff --git a/src/finer/R3Stretcher.h b/src/finer/R3Stretcher.h index 57a3187..88660f1 100644 --- a/src/finer/R3Stretcher.h +++ b/src/finer/R3Stretcher.h @@ -472,6 +472,12 @@ protected: } } + bool useMidSide() const { + return m_parameters.channels == 2 && + (m_parameters.options & + RubberBandStretcher::OptionChannelsTogether); + } + bool isSingleWindowed() const { return m_parameters.options & RubberBandStretcher::OptionWindowShort;