diff --git a/ladspa/RubberBandPitchShifter.cpp b/ladspa/RubberBandPitchShifter.cpp index 868d59f..3ca1245 100644 --- a/ladspa/RubberBandPitchShifter.cpp +++ b/ladspa/RubberBandPitchShifter.cpp @@ -44,7 +44,7 @@ RubberBandPitchShifter::portNamesMono[PortCountMono] = "Octaves", "Crispness", "Formant Preserving", - "Faster", + "Wet-Dry Mix", "Input", "Output" }; @@ -58,7 +58,7 @@ RubberBandPitchShifter::portNamesStereo[PortCountStereo] = "Octaves", "Crispness", "Formant Preserving", - "Faster", + "Wet-Dry Mix", "Input L", "Output L", "Input R", @@ -123,10 +123,9 @@ RubberBandPitchShifter::hintsMono[PortCountMono] = LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_TOGGLED, 0.0, 1.0 }, - { LADSPA_HINT_DEFAULT_0 | // fast + { LADSPA_HINT_DEFAULT_0 | // wet-dry mix LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_BOUNDED_ABOVE | - LADSPA_HINT_TOGGLED, + LADSPA_HINT_BOUNDED_ABOVE, 0.0, 1.0 }, { 0, 0, 0 }, { 0, 0, 0 } @@ -160,10 +159,9 @@ RubberBandPitchShifter::hintsStereo[PortCountStereo] = LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_TOGGLED, 0.0, 1.0 }, - { LADSPA_HINT_DEFAULT_0 | // fast + { LADSPA_HINT_DEFAULT_0 | // wet-dry mix LADSPA_HINT_BOUNDED_BELOW | - LADSPA_HINT_BOUNDED_ABOVE | - LADSPA_HINT_TOGGLED, + LADSPA_HINT_BOUNDED_ABOVE, 0.0, 1.0 }, { 0, 0, 0 }, { 0, 0, 0 }, @@ -237,12 +235,11 @@ RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) m_octaves(0), m_crispness(0), m_formant(0), - m_fast(0), + m_wetDry(0), m_ratio(1.0), m_prevRatio(1.0), m_currentCrispness(-1), m_currentFormant(false), - m_currentFast(false), m_blockSize(1024), m_reserve(1024), m_minfill(0), @@ -257,6 +254,7 @@ RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) m_output = new float *[m_channels]; m_outputBuffer = new RingBuffer *[m_channels]; + m_delayMixBuffer = new RingBuffer *[m_channels]; m_scratch = new float *[m_channels]; for (size_t c = 0; c < m_channels; ++c) { @@ -267,6 +265,7 @@ RubberBandPitchShifter::RubberBandPitchShifter(int sampleRate, size_t channels) int bufsize = m_blockSize + m_reserve + 8192; m_outputBuffer[c] = new RingBuffer(bufsize); + m_delayMixBuffer[c] = new RingBuffer(bufsize); m_scratch[c] = new float[bufsize]; for (int i = 0; i < bufsize; ++i) m_scratch[c][i] = 0.f; @@ -280,9 +279,11 @@ RubberBandPitchShifter::~RubberBandPitchShifter() delete m_stretcher; for (size_t c = 0; c < m_channels; ++c) { delete m_outputBuffer[c]; + delete m_delayMixBuffer[c]; delete[] m_scratch[c]; } delete[] m_outputBuffer; + delete[] m_delayMixBuffer; delete[] m_scratch; delete[] m_output; delete[] m_input; @@ -312,7 +313,7 @@ RubberBandPitchShifter::connectPort(LADSPA_Handle handle, &shifter->m_octaves, &shifter->m_crispness, &shifter->m_formant, - &shifter->m_fast, + &shifter->m_wetDry, &shifter->m_input[0], &shifter->m_output[0], &shifter->m_input[1], @@ -328,8 +329,17 @@ RubberBandPitchShifter::connectPort(LADSPA_Handle handle, *ports[port] = (float *)location; if (shifter->m_latency) { - *(shifter->m_latency) = - float(shifter->m_stretcher->getLatency() + shifter->m_reserve); + *(shifter->m_latency) = shifter->getLatency(); + } +} + +int +RubberBandPitchShifter::getLatency() const +{ + if (m_stretcher) { + return m_stretcher->getLatency() + m_reserve; + } else { + return 0; } } @@ -353,6 +363,11 @@ RubberBandPitchShifter::activateImpl() m_outputBuffer[c]->zero(m_reserve); } + for (size_t c = 0; c < m_channels; ++c) { + m_delayMixBuffer[c]->reset(); + m_delayMixBuffer[c]->zero(getLatency()); + } + m_minfill = 0; // prime stretcher @@ -431,23 +446,6 @@ RubberBandPitchShifter::updateFormant() m_currentFormant = f; } -void -RubberBandPitchShifter::updateFast() -{ - if (!m_fast) return; - - bool f = (*m_fast > 0.5f); - if (f == m_currentFast) return; - - RubberBandStretcher *s = m_stretcher; - - s->setPitchOption(f ? - RubberBandStretcher::OptionPitchHighSpeed : - RubberBandStretcher::OptionPitchHighConsistency); - - m_currentFast = f; -} - void RubberBandPitchShifter::runImpl(unsigned long insamples) { @@ -466,6 +464,24 @@ RubberBandPitchShifter::runImpl(unsigned long insamples) offset += block; } + + if (m_wetDry) { + for (size_t c = 0; c < m_channels; ++c) { + m_delayMixBuffer[c]->write(m_input[c], insamples); + } + float mix = *m_wetDry; + for (size_t c = 0; c < m_channels; ++c) { + if (mix > 0.0) { + for (unsigned long i = 0; i < insamples; ++i) { + float dry = m_delayMixBuffer[c]->readOne(); + m_output[c][i] *= (1.0 - mix); + m_output[c][i] += dry * mix; + } + } else { + m_delayMixBuffer[c]->skip(insamples); + } + } + } } void @@ -480,15 +496,19 @@ RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset) m_stretcher->setPitchScale(m_ratio); m_prevRatio = m_ratio; } - +/* if (m_latency) { - *m_latency = float(m_stretcher->getLatency() + m_reserve); -// cerr << "latency = " << *m_latency << endl; + float latencyWas = *m_latency; + *m_latency = getLatency(); + cerr << "latency = " << *m_latency << endl; + if (*m_latency != latencyWas) { + cerr << "NOTE: latency changed from " << latencyWas + << " to " << *m_latency << endl; + } } - +*/ updateCrispness(); updateFormant(); - updateFast(); const int samples = insamples; int processed = 0; @@ -496,17 +516,6 @@ RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset) float *ptrs[2]; - int rs = m_outputBuffer[0]->getReadSpace(); - if (rs < int(m_minfill)) { -// cerr << "temporary expansion (have " << rs << ", want " << m_reserve << ")" << endl; - m_stretcher->setTimeRatio(1.1); // fill up temporarily - } else if (rs > 8192) { -// cerr << "temporary reduction (have " << rs << ", want " << m_reserve << ")" << endl; - m_stretcher->setTimeRatio(0.9); // reduce temporarily - } else { - m_stretcher->setTimeRatio(1.0); - } - while (processed < samples) { // never feed more than the minimum necessary number of @@ -523,24 +532,18 @@ RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset) int avail = m_stretcher->available(); int writable = m_outputBuffer[0]->getWriteSpace(); - int outchunk = min(avail, writable); + + int outchunk = avail; + if (outchunk > writable) { + cerr << "RubberBandPitchShifter::runImpl: buffer is not large enough: chunk = " << outchunk << ", space = " << writable << endl; + outchunk = writable; + } + size_t actual = m_stretcher->retrieve(m_scratch, outchunk); outTotal += actual; -// incount += inchunk; -// outcount += actual; - -// cout << "avail: " << avail << ", outchunk = " << outchunk; -// if (actual != outchunk) cout << " (" << actual << ")"; -// cout << endl; - - outchunk = actual; - for (size_t c = 0; c < m_channels; ++c) { - if (int(m_outputBuffer[c]->getWriteSpace()) < outchunk) { - cerr << "RubberBandPitchShifter::runImpl: buffer overrun: chunk = " << outchunk << ", space = " << m_outputBuffer[c]->getWriteSpace() << endl; - } - m_outputBuffer[c]->write(m_scratch[c], outchunk); + m_outputBuffer[c]->write(m_scratch[c], actual); } } @@ -555,7 +558,7 @@ RubberBandPitchShifter::runImpl(unsigned long insamples, unsigned long offset) if (m_minfill == 0) { m_minfill = m_outputBuffer[0]->getReadSpace(); -// cerr << "minfill = " << m_minfill << endl; + cerr << "minfill = " << m_minfill << endl; } } diff --git a/ladspa/RubberBandPitchShifter.h b/ladspa/RubberBandPitchShifter.h index 7f56e11..4214fff 100644 --- a/ladspa/RubberBandPitchShifter.h +++ b/ladspa/RubberBandPitchShifter.h @@ -48,7 +48,7 @@ protected: CentsPort = 3, CrispnessPort = 4, FormantPort = 5, - FastPort = 6, + WetDryPort = 6, InputPort1 = 7, OutputPort1 = 8, PortCountMono = OutputPort1 + 1, @@ -83,7 +83,8 @@ protected: void updateRatio(); void updateCrispness(); void updateFormant(); - void updateFast(); + + int getLatency() const; float **m_input; float **m_output; @@ -93,12 +94,11 @@ protected: float *m_octaves; float *m_crispness; float *m_formant; - float *m_fast; + float *m_wetDry; double m_ratio; double m_prevRatio; int m_currentCrispness; bool m_currentFormant; - bool m_currentFast; size_t m_blockSize; size_t m_reserve; @@ -106,6 +106,7 @@ protected: RubberBand::RubberBandStretcher *m_stretcher; RubberBand::RingBuffer **m_outputBuffer; + RubberBand::RingBuffer **m_delayMixBuffer; float **m_scratch; int m_sampleRate; diff --git a/src/StretchCalculator.cpp b/src/StretchCalculator.cpp index 230cbd8..6359e4e 100644 --- a/src/StretchCalculator.cpp +++ b/src/StretchCalculator.cpp @@ -469,7 +469,7 @@ StretchCalculator::calculateSingle(double timeRatio, if (divergence > 1000 || divergence < -1000) { recovery = divergence / ((m_sampleRate / 10.0) / increment); } else if (divergence > 100 || divergence < -100) { - recovery = divergence / ((m_sampleRate / 25.0) / increment); + recovery = divergence / ((m_sampleRate / 20.0) / increment); } else { recovery = divergence / 4.0; } diff --git a/src/StretcherImpl.cpp b/src/StretcherImpl.cpp index d545c8c..f35e48f 100644 --- a/src/StretcherImpl.cpp +++ b/src/StretcherImpl.cpp @@ -868,7 +868,8 @@ size_t RubberBandStretcher::Impl::getLatency() const { if (!m_realtime) return 0; - return int((m_aWindowSize/2) / m_pitchScale + 1); + return lrint((m_aWindowSize/2) / m_pitchScale); +// return int(m_aWindowSize/2); } void diff --git a/src/StretcherProcess.cpp b/src/StretcherProcess.cpp index 5bdf80c..0d7d162 100644 --- a/src/StretcherProcess.cpp +++ b/src/StretcherProcess.cpp @@ -1154,11 +1154,11 @@ RubberBandStretcher::Impl::writeOutput(RingBuffer &to, float *from, size_ // configure(), so we don't want to remove any here. //!!! size_t startSkip = 0; -// if (!m_realtime) { + if (!m_realtime) { //!!! lock down the latency to this initial value in RT mode startSkip = lrintf((m_sWindowSize/2) / m_pitchScale); // startSkip = m_sWindowSize/2; -// } + } if (outCount > startSkip) {