1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
5 An audio time-stretching and pitch-shifting library.
6 Copyright 2007-2008 Chris Cannam.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version. See the file
12 COPYING included with this distribution for more information.
15 #include "StretcherImpl.h"
16 #include "PercussiveAudioCurve.h"
17 #include "HighFrequencyAudioCurve.h"
18 #include "SpectralDifferenceAudioCurve.h"
19 #include "SilentAudioCurve.h"
20 #include "ConstantAudioCurve.h"
21 #include "StretchCalculator.h"
22 #include "StretcherChannelData.h"
23 #include "Resampler.h"
40 namespace RubberBand {
43 RubberBandStretcher::Impl::m_defaultIncrement = 256;
46 RubberBandStretcher::Impl::m_defaultWindowSize = 2048;
49 RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
53 RubberBandStretcher::Impl::Impl(size_t sampleRate,
56 double initialTimeRatio,
57 double initialPitchScale) :
58 m_sampleRate(sampleRate),
60 m_timeRatio(initialTimeRatio),
61 m_pitchScale(initialPitchScale),
62 m_windowSize(m_defaultWindowSize),
63 m_increment(m_defaultIncrement),
64 m_outbufSize(m_defaultWindowSize * 2),
65 m_maxProcessSize(m_defaultWindowSize),
66 m_expectedInputDuration(0),
70 m_debugLevel(m_defaultDebugLevel),
74 m_spaceAvailable("space"),
77 m_lastProcessOutputIncrements(16),
78 m_lastProcessPhaseResetDf(16),
79 m_phaseResetAudioCurve(0),
80 m_stretchAudioCurve(0),
81 m_silentAudioCurve(0),
82 m_stretchCalculator(0),
86 m_baseWindowSize(m_defaultWindowSize)
89 if (m_debugLevel > 0) {
90 cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_sampleRate << ", options = " << options << endl;
93 // Window size will vary according to the audio sample rate, but
94 // we don't let it drop below the 48k default
95 m_rateMultiple = float(m_sampleRate) / 48000.f;
96 if (m_rateMultiple < 1.f) m_rateMultiple = 1.f;
97 m_baseWindowSize = roundUp(int(m_defaultWindowSize * m_rateMultiple));
99 if ((options & OptionWindowShort) || (options & OptionWindowLong)) {
100 if ((options & OptionWindowShort) && (options & OptionWindowLong)) {
101 cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl;
102 } else if (options & OptionWindowShort) {
103 m_baseWindowSize = m_baseWindowSize / 2;
104 if (m_debugLevel > 0) {
105 cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
107 } else if (options & OptionWindowLong) {
108 m_baseWindowSize = m_baseWindowSize * 2;
109 if (m_debugLevel > 0) {
110 cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
113 m_windowSize = m_baseWindowSize;
114 m_outbufSize = m_baseWindowSize * 2;
115 m_maxProcessSize = m_baseWindowSize;
118 if (m_options & OptionProcessRealTime) {
122 if (!(m_options & OptionStretchPrecise)) {
123 m_options |= OptionStretchPrecise;
127 if (m_channels > 1) {
133 } else if (m_options & OptionThreadingNever) {
135 } else if (!(m_options & OptionThreadingAlways) &&
136 !system_is_multiprocessor()) {
140 if (m_threaded && m_debugLevel > 0) {
141 cerr << "Going multithreaded..." << endl;
148 RubberBandStretcher::Impl::~Impl()
151 MutexLocker locker(&m_threadSetMutex);
152 for (set<ProcessThread *>::iterator i = m_threadSet.begin();
153 i != m_threadSet.end(); ++i) {
154 if (m_debugLevel > 0) {
155 cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
163 for (size_t c = 0; c < m_channels; ++c) {
164 delete m_channelData[c];
167 delete m_phaseResetAudioCurve;
168 delete m_stretchAudioCurve;
169 delete m_silentAudioCurve;
170 delete m_stretchCalculator;
173 for (map<size_t, Window<float> *>::iterator i = m_windows.begin();
174 i != m_windows.end(); ++i) {
180 RubberBandStretcher::Impl::reset()
183 m_threadSetMutex.lock();
184 for (set<ProcessThread *>::iterator i = m_threadSet.begin();
185 i != m_threadSet.end(); ++i) {
186 if (m_debugLevel > 0) {
187 cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
196 for (size_t c = 0; c < m_channels; ++c) {
197 m_channelData[c]->reset();
200 m_mode = JustCreated;
201 if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
202 if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
203 if (m_silentAudioCurve) m_silentAudioCurve->reset();
207 if (m_threaded) m_threadSetMutex.unlock();
213 RubberBandStretcher::Impl::setTimeRatio(double ratio)
216 if (m_mode == Studying || m_mode == Processing) {
217 cerr << "RubberBandStretcher::Impl::setTimeRatio: Cannot set ratio while studying or processing in non-RT mode" << endl;
222 if (ratio == m_timeRatio) return;
229 RubberBandStretcher::Impl::setPitchScale(double fs)
232 if (m_mode == Studying || m_mode == Processing) {
233 cerr << "RubberBandStretcher::Impl::setPitchScale: Cannot set ratio while studying or processing in non-RT mode" << endl;
238 if (fs == m_pitchScale) return;
240 bool was1 = (m_pitchScale == 1.f);
241 bool rbs = resampleBeforeStretching();
247 if (!(m_options & OptionPitchHighConsistency) &&
248 (was1 || resampleBeforeStretching() != rbs) &&
249 m_pitchScale != 1.f) {
251 // resampling mode has changed
252 for (int c = 0; c < int(m_channels); ++c) {
253 if (m_channelData[c]->resampler) {
254 m_channelData[c]->resampler->reset();
261 RubberBandStretcher::Impl::getTimeRatio() const
267 RubberBandStretcher::Impl::getPitchScale() const
273 RubberBandStretcher::Impl::setExpectedInputDuration(size_t samples)
275 if (samples == m_expectedInputDuration) return;
276 m_expectedInputDuration = samples;
282 RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
284 if (samples <= m_maxProcessSize) return;
285 m_maxProcessSize = samples;
291 RubberBandStretcher::Impl::getFrequencyCutoff(int n) const
294 case 0: return m_freq0;
295 case 1: return m_freq1;
296 case 2: return m_freq2;
302 RubberBandStretcher::Impl::setFrequencyCutoff(int n, float f)
305 case 0: m_freq0 = f; break;
306 case 1: m_freq1 = f; break;
307 case 2: m_freq2 = f; break;
312 RubberBandStretcher::Impl::getEffectiveRatio() const
314 // Returns the ratio that the internal time stretcher needs to
315 // achieve, not the resulting duration ratio of the output (which
316 // is simply m_timeRatio).
318 // A frequency shift is achieved using an additional time shift,
319 // followed by resampling back to the original time shift to
320 // change the pitch. Note that the resulting frequency change is
321 // fixed, as it is effected by the resampler -- in contrast to
322 // time shifting, which is variable aiming to place the majority
323 // of the stretch or squash in low-interest regions of audio.
325 return m_timeRatio * m_pitchScale;
329 RubberBandStretcher::Impl::roundUp(size_t value)
331 if (!(value & (value - 1))) return value;
333 while (value) { ++bits; value >>= 1; }
339 RubberBandStretcher::Impl::calculateSizes()
341 size_t inputIncrement = m_defaultIncrement;
342 size_t windowSize = m_baseWindowSize;
343 size_t outputIncrement;
345 if (m_pitchScale <= 0.0) {
346 // This special case is likelier than one might hope, because
347 // of naive initialisations in programs that set it from a
349 std::cerr << "RubberBandStretcher: WARNING: Pitch scale must be greater than zero!\nResetting it from " << m_pitchScale << " to the default of 1.0: no pitch change will occur" << std::endl;
352 if (m_timeRatio <= 0.0) {
354 std::cerr << "RubberBandStretcher: WARNING: Time ratio must be greater than zero!\nResetting it from " << m_timeRatio << " to the default of 1.0: no time stretch will occur" << std::endl;
358 double r = getEffectiveRatio();
364 bool rsb = (m_pitchScale < 1.0 && !resampleBeforeStretching());
365 float windowIncrRatio = 4.5;
366 if (r == 1.0) windowIncrRatio = 4;
367 else if (rsb) windowIncrRatio = 4.5;
368 else windowIncrRatio = 6;
370 inputIncrement = int(windowSize / windowIncrRatio);
371 outputIncrement = int(floor(inputIncrement * r));
373 // Very long stretch or very low pitch shift
374 if (outputIncrement < m_defaultIncrement / 4) {
375 if (outputIncrement < 1) outputIncrement = 1;
376 while (outputIncrement < m_defaultIncrement / 4 &&
377 windowSize < m_baseWindowSize * 4) {
378 outputIncrement *= 2;
379 inputIncrement = lrint(ceil(outputIncrement / r));
380 windowSize = roundUp(lrint(ceil(inputIncrement * windowIncrRatio)));
386 bool rsb = (m_pitchScale > 1.0 && resampleBeforeStretching());
387 float windowIncrRatio = 4.5;
388 if (r == 1.0) windowIncrRatio = 4;
389 else if (rsb) windowIncrRatio = 4.5;
390 else windowIncrRatio = 6;
392 outputIncrement = int(windowSize / windowIncrRatio);
393 inputIncrement = int(outputIncrement / r);
394 while (outputIncrement > 1024 * m_rateMultiple &&
395 inputIncrement > 1) {
396 outputIncrement /= 2;
397 inputIncrement = int(outputIncrement / r);
399 size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio));
400 if (windowSize < minwin) windowSize = minwin;
403 // cerr << "adjusting window size from " << windowSize;
404 size_t newWindowSize = roundUp(lrint(windowSize / m_pitchScale));
405 if (newWindowSize < 512) newWindowSize = 512;
406 size_t div = windowSize / newWindowSize;
407 if (inputIncrement > div && outputIncrement > div) {
408 inputIncrement /= div;
409 outputIncrement /= div;
412 // cerr << " to " << windowSize << " (inputIncrement = " << inputIncrement << ", outputIncrement = " << outputIncrement << ")" << endl;
419 inputIncrement = windowSize / 4;
420 while (inputIncrement >= 512) inputIncrement /= 2;
421 outputIncrement = int(floor(inputIncrement * r));
422 if (outputIncrement < 1) {
424 inputIncrement = roundUp(lrint(ceil(outputIncrement / r)));
425 windowSize = inputIncrement * 4;
428 outputIncrement = windowSize / 6;
429 inputIncrement = int(outputIncrement / r);
430 while (outputIncrement > 1024 && inputIncrement > 1) {
431 outputIncrement /= 2;
432 inputIncrement = int(outputIncrement / r);
434 windowSize = std::max(windowSize, roundUp(outputIncrement * 6));
435 if (r > 5) while (windowSize < 8192) windowSize *= 2;
439 if (m_expectedInputDuration > 0) {
440 while (inputIncrement * 4 > m_expectedInputDuration &&
441 inputIncrement > 1) {
446 // windowSize can be almost anything, but it can't be greater than
447 // 4 * m_baseWindowSize unless ratio is less than 1/1024.
449 m_windowSize = windowSize;
450 m_increment = inputIncrement;
452 // When squashing, the greatest theoretically possible output
453 // increment is the input increment. When stretching adaptively
454 // the sky's the limit in principle, but we expect
455 // StretchCalculator to restrict itself to using no more than
456 // twice the basic output increment (i.e. input increment times
457 // ratio) for any chunk.
459 if (m_debugLevel > 0) {
460 cerr << "configure: effective ratio = " << getEffectiveRatio() << endl;
461 cerr << "configure: window size = " << m_windowSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl;
464 if (m_windowSize > m_maxProcessSize) {
465 m_maxProcessSize = m_windowSize;
471 (m_maxProcessSize / m_pitchScale,
472 m_windowSize * 2 * (m_timeRatio > 1.f ? m_timeRatio : 1.f))));
475 // This headroom is so as to try to avoid reallocation when
476 // the pitch scale changes
477 m_outbufSize = m_outbufSize * 16;
480 // This headroom is to permit the processing threads to
481 // run ahead of the buffer output drainage; the exact
482 // amount of headroom is a question of tuning rather than
484 m_outbufSize = m_outbufSize * 16;
488 if (m_debugLevel > 0) {
489 cerr << "configure: outbuf size = " << m_outbufSize << endl;
494 RubberBandStretcher::Impl::configure()
496 // std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = "
497 // << m_pitchScale << ", channels = " << m_channels << std::endl;
499 size_t prevWindowSize = m_windowSize;
500 size_t prevOutbufSize = m_outbufSize;
501 if (m_windows.empty()) {
508 bool windowSizeChanged = (prevWindowSize != m_windowSize);
509 bool outbufSizeChanged = (prevOutbufSize != m_outbufSize);
511 // This function may be called at any time in non-RT mode, after a
512 // parameter has changed. It shouldn't be legal to call it after
513 // processing has already begun.
515 // This function is only called once (on construction) in RT
516 // mode. After that reconfigure() does the work in a hopefully
519 set<size_t> windowSizes;
521 windowSizes.insert(m_baseWindowSize);
522 windowSizes.insert(m_baseWindowSize / 2);
523 windowSizes.insert(m_baseWindowSize * 2);
524 // windowSizes.insert(m_baseWindowSize * 4);
526 windowSizes.insert(m_windowSize);
528 if (windowSizeChanged) {
530 for (set<size_t>::const_iterator i = windowSizes.begin();
531 i != windowSizes.end(); ++i) {
532 if (m_windows.find(*i) == m_windows.end()) {
533 m_windows[*i] = new Window<float>(HanningWindow, *i);
536 m_window = m_windows[m_windowSize];
538 if (m_debugLevel > 0) {
539 cerr << "Window area: " << m_window->getArea() << "; synthesis window area: " << m_window->getArea() << endl;
543 if (windowSizeChanged || outbufSizeChanged) {
545 for (size_t c = 0; c < m_channelData.size(); ++c) {
546 delete m_channelData[c];
548 m_channelData.clear();
550 for (size_t c = 0; c < m_channels; ++c) {
551 m_channelData.push_back
552 (new ChannelData(windowSizes, 1, m_windowSize, m_outbufSize));
556 if (!m_realtime && windowSizeChanged) {
558 m_studyFFT = new FFT(m_windowSize, m_debugLevel);
559 m_studyFFT->initFloat();
562 if (m_pitchScale != 1.0 ||
563 (m_options & OptionPitchHighConsistency) ||
566 for (size_t c = 0; c < m_channels; ++c) {
568 if (m_channelData[c]->resampler) continue;
570 m_channelData[c]->resampler =
571 new Resampler(Resampler::FastestTolerable, 1, 4096 * 16,
574 // rbs is the amount of buffer space we think we'll need
575 // for resampling; but allocate a sensible amount in case
576 // the pitch scale changes during use
578 lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale));
579 if (rbs < m_increment * 16) rbs = m_increment * 16;
580 m_channelData[c]->setResampleBufSize(rbs);
584 // stretchAudioCurve is unused in RT mode; phaseResetAudioCurve,
585 // silentAudioCurve and stretchCalculator however are used in all
588 delete m_phaseResetAudioCurve;
589 m_phaseResetAudioCurve = new PercussiveAudioCurve
590 (m_sampleRate, m_windowSize);
592 delete m_silentAudioCurve;
593 m_silentAudioCurve = new SilentAudioCurve
594 (m_sampleRate, m_windowSize);
597 delete m_stretchAudioCurve;
598 if (!(m_options & OptionStretchPrecise)) {
599 m_stretchAudioCurve = new SpectralDifferenceAudioCurve
600 (m_sampleRate, m_windowSize);
602 m_stretchAudioCurve = new ConstantAudioCurve
603 (m_sampleRate, m_windowSize);
607 delete m_stretchCalculator;
608 m_stretchCalculator = new StretchCalculator
609 (m_sampleRate, m_increment,
610 !(m_options & OptionTransientsSmooth));
612 m_stretchCalculator->setDebugLevel(m_debugLevel);
615 // Prepare the inbufs with half a chunk of emptiness. The centre
616 // point of the first processing chunk for the onset detector
617 // should be the first sample of the audio, and we continue until
618 // we can no longer centre a chunk within the input audio. The
619 // number of onset detector chunks will be the number of audio
620 // samples input, divided by the input increment, plus one.
622 // In real-time mode, we don't do this prefill -- it's better to
623 // start with a swoosh than introduce more latency, and we don't
624 // want gaps when the ratio changes.
627 for (size_t c = 0; c < m_channels; ++c) {
628 m_channelData[c]->reset();
629 m_channelData[c]->inbuf->zero(m_windowSize/2);
636 RubberBandStretcher::Impl::reconfigure()
639 if (m_mode == Studying) {
640 // stop and calculate the stretch curve so far, then reset
643 m_phaseResetDf.clear();
651 size_t prevWindowSize = m_windowSize;
652 size_t prevOutbufSize = m_outbufSize;
656 // There are various allocations in this function, but they should
657 // never happen in normal use -- they just recover from the case
658 // where not all of the things we need were correctly created when
659 // we first configured (for whatever reason). This is intended to
660 // be "effectively" realtime safe. The same goes for
661 // ChannelData::setOutbufSize and setWindowSize.
663 if (m_windowSize != prevWindowSize) {
665 if (m_windows.find(m_windowSize) == m_windows.end()) {
666 std::cerr << "WARNING: reconfigure(): window allocation (size " << m_windowSize << ") required in RT mode" << std::endl;
667 m_windows[m_windowSize] = new Window<float>(HanningWindow, m_windowSize);
669 m_window = m_windows[m_windowSize];
671 for (size_t c = 0; c < m_channels; ++c) {
672 m_channelData[c]->setWindowSize(m_windowSize);
676 if (m_outbufSize != prevOutbufSize) {
677 for (size_t c = 0; c < m_channels; ++c) {
678 m_channelData[c]->setOutbufSize(m_outbufSize);
682 if (m_pitchScale != 1.0) {
683 for (size_t c = 0; c < m_channels; ++c) {
685 if (m_channelData[c]->resampler) continue;
687 std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
689 m_channelData[c]->resampler =
690 new Resampler(Resampler::FastestTolerable, 1, m_windowSize,
693 m_channelData[c]->setResampleBufSize
694 (lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)));
698 if (m_windowSize != prevWindowSize) {
699 m_phaseResetAudioCurve->setWindowSize(m_windowSize);
704 RubberBandStretcher::Impl::getLatency() const
706 if (!m_realtime) return 0;
707 return int((m_windowSize/2) / m_pitchScale + 1);
711 RubberBandStretcher::Impl::setTransientsOption(Options options)
714 cerr << "RubberBandStretcher::Impl::setTransientsOption: Not permissible in non-realtime mode" << endl;
717 int mask = (OptionTransientsMixed | OptionTransientsSmooth | OptionTransientsCrisp);
720 m_options |= options;
722 m_stretchCalculator->setUseHardPeaks
723 (!(m_options & OptionTransientsSmooth));
727 RubberBandStretcher::Impl::setPhaseOption(Options options)
729 int mask = (OptionPhaseLaminar | OptionPhaseIndependent);
732 m_options |= options;
736 RubberBandStretcher::Impl::setFormantOption(Options options)
738 int mask = (OptionFormantShifted | OptionFormantPreserved);
741 m_options |= options;
745 RubberBandStretcher::Impl::setPitchOption(Options options)
748 cerr << "RubberBandStretcher::Impl::setPitchOption: Pitch option is not used in non-RT mode" << endl;
752 Options prior = m_options;
754 int mask = (OptionPitchHighQuality |
755 OptionPitchHighSpeed |
756 OptionPitchHighConsistency);
759 m_options |= options;
761 if (prior != m_options) reconfigure();
765 RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool final)
767 Profiler profiler("RubberBandStretcher::Impl::study");
770 if (m_debugLevel > 1) {
771 cerr << "RubberBandStretcher::Impl::study: Not meaningful in realtime mode" << endl;
776 if (m_mode == Processing || m_mode == Finished) {
777 cerr << "RubberBandStretcher::Impl::study: Cannot study after processing" << endl;
784 ChannelData &cd = *m_channelData[0];
785 RingBuffer<float> &inbuf = *cd.inbuf;
787 const float *mixdown;
790 if (m_channels > 1 || final) {
791 // mix down into a single channel for analysis
792 mdalloc = new float[samples];
793 for (size_t i = 0; i < samples; ++i) {
795 mdalloc[i] = input[0][i];
800 for (size_t c = 1; c < m_channels; ++c) {
801 for (size_t i = 0; i < samples; ++i) {
802 mdalloc[i] += input[c][i];
805 for (size_t i = 0; i < samples; ++i) {
806 mdalloc[i] /= m_channels;
813 while (consumed < samples) {
815 size_t writable = inbuf.getWriteSpace();
816 writable = min(writable, samples - consumed);
820 cerr << "WARNING: writable == 0 (consumed = " << consumed << ", samples = " << samples << ")" << endl;
822 inbuf.write(mixdown + consumed, writable);
823 consumed += writable;
826 while ((inbuf.getReadSpace() >= int(m_windowSize)) ||
827 (final && (inbuf.getReadSpace() >= int(m_windowSize/2)))) {
829 // We know we have at least m_windowSize samples available
830 // in m_inbuf. We need to peek m_windowSize of them for
831 // processing, and then skip m_increment to advance the
834 // cd.accumulator is not otherwise used during studying,
835 // so we can use it as a temporary buffer here
837 size_t got = inbuf.peek(cd.accumulator, m_windowSize);
838 assert(final || got == m_windowSize);
840 m_window->cut(cd.accumulator);
842 // We don't need the fftshift for studying, as we're only
843 // interested in magnitude
845 m_studyFFT->forwardMagnitude(cd.accumulator, cd.fltbuf);
847 float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment);
848 m_phaseResetDf.push_back(df);
850 // cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: ";
852 df = m_stretchAudioCurve->process(cd.fltbuf, m_increment);
853 m_stretchDf.push_back(df);
855 df = m_silentAudioCurve->process(cd.fltbuf, m_increment);
856 bool silent = (df > 0.f);
857 if (silent && m_debugLevel > 1) {
858 cerr << "silence found at " << m_inputDuration << endl;
860 m_silence.push_back(silent);
862 // cout << df << endl;
864 // We have augmented the input by m_windowSize/2 so
865 // that the first chunk is centred on the first audio
866 // sample. We want to ensure that m_inputDuration
867 // contains the exact input duration without including
868 // this extra bit. We just add up all the increments
869 // here, and deduct the extra afterwards.
871 m_inputDuration += m_increment;
872 // cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl;
873 inbuf.skip(m_increment);
878 int rs = inbuf.getReadSpace();
879 m_inputDuration += rs;
880 // cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
882 if (m_inputDuration > m_windowSize/2) { // deducting the extra
883 m_inputDuration -= m_windowSize/2;
887 if (m_channels > 1) delete[] mdalloc;
891 RubberBandStretcher::Impl::getOutputIncrements() const
894 return m_outputIncrements;
896 vector<int> increments;
897 while (m_lastProcessOutputIncrements.getReadSpace() > 0) {
898 increments.push_back(m_lastProcessOutputIncrements.readOne());
905 RubberBandStretcher::Impl::getPhaseResetCurve() const
908 return m_phaseResetDf;
911 while (m_lastProcessPhaseResetDf.getReadSpace() > 0) {
912 df.push_back(m_lastProcessPhaseResetDf.readOne());
919 RubberBandStretcher::Impl::getExactTimePoints() const
921 std::vector<int> points;
923 std::vector<StretchCalculator::Peak> peaks =
924 m_stretchCalculator->getLastCalculatedPeaks();
925 for (size_t i = 0; i < peaks.size(); ++i) {
926 points.push_back(peaks[i].chunk);
933 RubberBandStretcher::Impl::calculateStretch()
935 Profiler profiler("RubberBandStretcher::Impl::calculateStretch");
937 size_t inputDuration = m_inputDuration;
939 if (!m_realtime && m_expectedInputDuration > 0) {
940 if (m_expectedInputDuration != inputDuration) {
941 std::cerr << "RubberBandStretcher: WARNING: Actual study() duration differs from duration set by setExpectedInputDuration (" << m_inputDuration << " vs " << m_expectedInputDuration << ", diff = " << (m_expectedInputDuration - m_inputDuration) << "), using the latter for calculation" << std::endl;
942 inputDuration = m_expectedInputDuration;
946 std::vector<int> increments = m_stretchCalculator->calculate
947 (getEffectiveRatio(),
953 for (size_t i = 0; i < increments.size(); ++i) {
954 if (i >= m_silence.size()) break;
955 if (m_silence[i]) ++history;
957 if (history >= int(m_windowSize / m_increment) && increments[i] >= 0) {
958 increments[i] = -increments[i];
959 if (m_debugLevel > 1) {
960 std::cerr << "phase reset on silence (silent history == "
961 << history << ")" << std::endl;
966 if (m_outputIncrements.empty()) m_outputIncrements = increments;
968 for (size_t i = 0; i < increments.size(); ++i) {
969 m_outputIncrements.push_back(increments[i]);
977 RubberBandStretcher::Impl::setDebugLevel(int level)
979 m_debugLevel = level;
980 if (m_stretchCalculator) m_stretchCalculator->setDebugLevel(level);
984 RubberBandStretcher::Impl::getSamplesRequired() const
986 Profiler profiler("RubberBandStretcher::Impl::getSamplesRequired");
990 for (size_t c = 0; c < m_channels; ++c) {
994 ChannelData &cd = *m_channelData[c];
995 RingBuffer<float> &inbuf = *cd.inbuf;
997 size_t rs = inbuf.getReadSpace();
999 // See notes in testInbufReadSpace
1001 if (rs < m_windowSize && !cd.draining) {
1003 if (cd.inputSize == -1) {
1004 reqdHere = m_windowSize - rs;
1005 if (reqdHere > reqd) reqd = reqdHere;
1010 reqdHere = m_windowSize;
1011 if (reqdHere > reqd) reqd = reqdHere;
1021 RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final)
1023 Profiler profiler("RubberBandStretcher::Impl::process");
1025 if (m_mode == Finished) {
1026 cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl;
1030 if (m_mode == JustCreated || m_mode == Studying) {
1032 if (m_mode == Studying) {
1036 for (size_t c = 0; c < m_channels; ++c) {
1037 m_channelData[c]->reset();
1038 m_channelData[c]->inbuf->zero(m_windowSize/2);
1042 MutexLocker locker(&m_threadSetMutex);
1044 for (size_t c = 0; c < m_channels; ++c) {
1045 ProcessThread *thread = new ProcessThread(this, c);
1046 m_threadSet.insert(thread);
1050 if (m_debugLevel > 0) {
1051 cerr << m_channels << " threads created" << endl;
1055 m_mode = Processing;
1058 bool allConsumed = false;
1060 size_t *consumed = (size_t *)alloca(m_channels * sizeof(size_t));
1061 for (size_t c = 0; c < m_channels; ++c) {
1065 while (!allConsumed) {
1067 //#ifndef NO_THREADING
1068 // if (m_threaded) {
1069 // pthread_mutex_lock(&m_inputProcessedMutex);
1073 // In a threaded mode, our "consumed" counters only indicate
1074 // the number of samples that have been taken into the input
1075 // ring buffers waiting to be processed by the process thread.
1076 // In non-threaded mode, "consumed" counts the number that
1077 // have actually been processed.
1081 for (size_t c = 0; c < m_channels; ++c) {
1082 consumed[c] += consumeChannel(c,
1083 input[c] + consumed[c],
1084 samples - consumed[c],
1086 if (consumed[c] < samples) {
1087 allConsumed = false;
1088 // cerr << "process: waiting on input consumption for channel " << c << endl;
1091 m_channelData[c]->inputSize = m_channelData[c]->inCount;
1093 // cerr << "process: happy with channel " << c << endl;
1095 if (!m_threaded && !m_realtime) {
1096 bool any = false, last = false;
1097 processChunks(c, any, last);
1102 // When running in real time, we need to process both
1103 // channels in step because we will need to use the sum of
1104 // their frequency domain representations as the input to
1105 // the realtime onset detector
1110 for (ThreadSet::iterator i = m_threadSet.begin();
1111 i != m_threadSet.end(); ++i) {
1112 (*i)->signalDataAvailable();
1115 m_spaceAvailable.wait(500);
1120 cerr << "RubberBandStretcher::Impl::process: ERROR: Too much data provided to process() call -- either call setMaxProcessSize() beforehand, or provide only getSamplesRequired() frames at a time" << endl;
1121 for (size_t c = 0; c < m_channels; ++c) {
1122 cerr << "channel " << c << ": " << samples << " provided, " << consumed[c] << " consumed" << endl;
1129 // if (!allConsumed) cerr << "process looping" << endl;
1133 // cerr << "process returning" << endl;
1135 if (final) m_mode = Finished;