diff --git a/main/main.cpp b/main/main.cpp index ce105c4..0df99b5 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -303,11 +303,23 @@ int main(int argc, char **argv) cerr << " the pitch, retaining the original timbre of vocals and instruments in a" << endl; cerr << " recognisable way." << endl; cerr << endl; + cerr << " --centre-focus Preserve focus of centre material in stereo" << endl; + cerr << endl; + cerr << " This option assumes that any 2-channel audio files are stereo and treats" << endl; + cerr << " them in a way that improves focus of the centre material at a small expense" << endl; + cerr << " in quality of the individual channels. In v3.2+ (and R2) this also" << endl; + cerr << " preserves mono compatibility, which the default options do not always." << endl; + cerr << endl; if (fullHelp || !isR3) { cerr << " -c, --crisp Crispness (N = 0,1,2,3,4,5,6); default 5" << endl; cerr << endl; - cerr << " This option only has an effect when using the R2 (faster) engine. See below" << endl; - cerr << " for details of the different levels." << endl; + cerr << " This option only has an effect when using the R2 (faster) engine. See" << endl; + if (fullHelp) { + cerr << " below "; + } else { + cerr << " the full help "; + } + cerr << "for details of the different levels." << endl; cerr << endl; } if (fullHelp) { @@ -332,8 +344,6 @@ int main(int argc, char **argv) cerr << " --window-short Use shorter processing window (with the R3 engine" << endl; cerr << " this is effectively a quick \"draft mode\")" << endl; cerr << " --pitch-hq In RT mode, use a slower, higher quality pitch shift" << endl; - cerr << " --centre-focus Preserve focus of centre material in stereo" << endl; - cerr << " (at a cost in width and individual channel quality)" << endl; cerr << " --ignore-clipping Ignore clipping at output; the default is to restart" << endl; cerr << " with reduced gain if clipping occurs" << endl; cerr << " -L, --loose [Accepted for compatibility but ignored; always off]" << endl; 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 6cb6ae9..406133a 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,43 @@ R3Stretcher::retrieve(float *const *output, size_t samples) const } } + 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) +{ + 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() { @@ -928,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 d1b8308..88660f1 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(); @@ -469,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;