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.
16 #include "bsd-3rdparty/float_cast/float_cast.h"
18 #include "StretcherImpl.h"
19 #include "PercussiveAudioCurve.h"
20 #include "HighFrequencyAudioCurve.h"
21 #include "SpectralDifferenceAudioCurve.h"
22 #include "SilentAudioCurve.h"
23 #include "ConstantAudioCurve.h"
24 #include "StretchCalculator.h"
25 #include "StretcherChannelData.h"
26 #include "Resampler.h"
43 namespace RubberBand {
46 RubberBandStretcher::Impl::m_defaultIncrement = 256;
49 RubberBandStretcher::Impl::m_defaultWindowSize = 2048;
52 RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
56 RubberBandStretcher::Impl::Impl(size_t sampleRate,
59 double initialTimeRatio,
60 double initialPitchScale) :
61 m_sampleRate(sampleRate),
63 m_timeRatio(initialTimeRatio),
64 m_pitchScale(initialPitchScale),
65 m_windowSize(m_defaultWindowSize),
66 m_increment(m_defaultIncrement),
67 m_outbufSize(m_defaultWindowSize * 2),
68 m_maxProcessSize(m_defaultWindowSize),
69 m_expectedInputDuration(0),
73 m_debugLevel(m_defaultDebugLevel),
77 m_spaceAvailable("space"),
80 m_lastProcessOutputIncrements(16),
81 m_lastProcessPhaseResetDf(16),
82 m_phaseResetAudioCurve(0),
83 m_stretchAudioCurve(0),
84 m_silentAudioCurve(0),
85 m_stretchCalculator(0),
89 m_baseWindowSize(m_defaultWindowSize)
92 if (m_debugLevel > 0) {
93 cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_sampleRate << ", options = " << options << endl;
96 // Window size will vary according to the audio sample rate, but
97 // we don't let it drop below the 48k default
98 m_rateMultiple = float(m_sampleRate) / 48000.f;
99 if (m_rateMultiple < 1.f) m_rateMultiple = 1.f;
100 m_baseWindowSize = roundUp(int(m_defaultWindowSize * m_rateMultiple));
102 if ((options & OptionWindowShort) || (options & OptionWindowLong)) {
103 if ((options & OptionWindowShort) && (options & OptionWindowLong)) {
104 cerr << "RubberBandStretcher::Impl::Impl: Cannot specify OptionWindowLong and OptionWindowShort together; falling back to OptionWindowStandard" << endl;
105 } else if (options & OptionWindowShort) {
106 m_baseWindowSize = m_baseWindowSize / 2;
107 if (m_debugLevel > 0) {
108 cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
110 } else if (options & OptionWindowLong) {
111 m_baseWindowSize = m_baseWindowSize * 2;
112 if (m_debugLevel > 0) {
113 cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
116 m_windowSize = m_baseWindowSize;
117 m_outbufSize = m_baseWindowSize * 2;
118 m_maxProcessSize = m_baseWindowSize;
121 if (m_options & OptionProcessRealTime) {
125 if (!(m_options & OptionStretchPrecise)) {
126 m_options |= OptionStretchPrecise;
130 if (m_channels > 1) {
136 } else if (m_options & OptionThreadingNever) {
138 } else if (!(m_options & OptionThreadingAlways) &&
139 !system_is_multiprocessor()) {
143 if (m_threaded && m_debugLevel > 0) {
144 cerr << "Going multithreaded..." << endl;
151 RubberBandStretcher::Impl::~Impl()
154 MutexLocker locker(&m_threadSetMutex);
155 for (set<ProcessThread *>::iterator i = m_threadSet.begin();
156 i != m_threadSet.end(); ++i) {
157 if (m_debugLevel > 0) {
158 cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
166 for (size_t c = 0; c < m_channels; ++c) {
167 delete m_channelData[c];
170 delete m_phaseResetAudioCurve;
171 delete m_stretchAudioCurve;
172 delete m_silentAudioCurve;
173 delete m_stretchCalculator;
176 for (map<size_t, Window<float> *>::iterator i = m_windows.begin();
177 i != m_windows.end(); ++i) {
183 RubberBandStretcher::Impl::reset()
186 m_threadSetMutex.lock();
187 for (set<ProcessThread *>::iterator i = m_threadSet.begin();
188 i != m_threadSet.end(); ++i) {
189 if (m_debugLevel > 0) {
190 cerr << "RubberBandStretcher::~RubberBandStretcher: joining (channel " << *i << ")" << endl;
199 for (size_t c = 0; c < m_channels; ++c) {
200 m_channelData[c]->reset();
203 m_mode = JustCreated;
204 if (m_phaseResetAudioCurve) m_phaseResetAudioCurve->reset();
205 if (m_stretchAudioCurve) m_stretchAudioCurve->reset();
206 if (m_silentAudioCurve) m_silentAudioCurve->reset();
210 if (m_threaded) m_threadSetMutex.unlock();
216 RubberBandStretcher::Impl::setTimeRatio(double ratio)
219 if (m_mode == Studying || m_mode == Processing) {
220 cerr << "RubberBandStretcher::Impl::setTimeRatio: Cannot set ratio while studying or processing in non-RT mode" << endl;
225 if (ratio == m_timeRatio) return;
232 RubberBandStretcher::Impl::setPitchScale(double fs)
235 if (m_mode == Studying || m_mode == Processing) {
236 cerr << "RubberBandStretcher::Impl::setPitchScale: Cannot set ratio while studying or processing in non-RT mode" << endl;
241 if (fs == m_pitchScale) return;
243 bool was1 = (m_pitchScale == 1.f);
244 bool rbs = resampleBeforeStretching();
250 if (!(m_options & OptionPitchHighConsistency) &&
251 (was1 || resampleBeforeStretching() != rbs) &&
252 m_pitchScale != 1.f) {
254 // resampling mode has changed
255 for (int c = 0; c < int(m_channels); ++c) {
256 if (m_channelData[c]->resampler) {
257 m_channelData[c]->resampler->reset();
264 RubberBandStretcher::Impl::getTimeRatio() const
270 RubberBandStretcher::Impl::getPitchScale() const
276 RubberBandStretcher::Impl::setExpectedInputDuration(size_t samples)
278 if (samples == m_expectedInputDuration) return;
279 m_expectedInputDuration = samples;
285 RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
287 if (samples <= m_maxProcessSize) return;
288 m_maxProcessSize = samples;
294 RubberBandStretcher::Impl::getFrequencyCutoff(int n) const
297 case 0: return m_freq0;
298 case 1: return m_freq1;
299 case 2: return m_freq2;
305 RubberBandStretcher::Impl::setFrequencyCutoff(int n, float f)
308 case 0: m_freq0 = f; break;
309 case 1: m_freq1 = f; break;
310 case 2: m_freq2 = f; break;
315 RubberBandStretcher::Impl::getEffectiveRatio() const
317 // Returns the ratio that the internal time stretcher needs to
318 // achieve, not the resulting duration ratio of the output (which
319 // is simply m_timeRatio).
321 // A frequency shift is achieved using an additional time shift,
322 // followed by resampling back to the original time shift to
323 // change the pitch. Note that the resulting frequency change is
324 // fixed, as it is effected by the resampler -- in contrast to
325 // time shifting, which is variable aiming to place the majority
326 // of the stretch or squash in low-interest regions of audio.
328 return m_timeRatio * m_pitchScale;
332 RubberBandStretcher::Impl::roundUp(size_t value)
334 if (!(value & (value - 1))) return value;
336 while (value) { ++bits; value >>= 1; }
342 RubberBandStretcher::Impl::calculateSizes()
344 size_t inputIncrement = m_defaultIncrement;
345 size_t windowSize = m_baseWindowSize;
346 size_t outputIncrement;
348 if (m_pitchScale <= 0.0) {
349 // This special case is likelier than one might hope, because
350 // of naive initialisations in programs that set it from a
352 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;
355 if (m_timeRatio <= 0.0) {
357 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;
361 double r = getEffectiveRatio();
367 bool rsb = (m_pitchScale < 1.0 && !resampleBeforeStretching());
368 float windowIncrRatio = 4.5;
369 if (r == 1.0) windowIncrRatio = 4;
370 else if (rsb) windowIncrRatio = 4.5;
371 else windowIncrRatio = 6;
373 inputIncrement = int(windowSize / windowIncrRatio);
374 outputIncrement = int(floor(inputIncrement * r));
376 // Very long stretch or very low pitch shift
377 if (outputIncrement < m_defaultIncrement / 4) {
378 if (outputIncrement < 1) outputIncrement = 1;
379 while (outputIncrement < m_defaultIncrement / 4 &&
380 windowSize < m_baseWindowSize * 4) {
381 outputIncrement *= 2;
382 inputIncrement = lrint(ceil(outputIncrement / r));
383 windowSize = roundUp(lrint(ceil(inputIncrement * windowIncrRatio)));
389 bool rsb = (m_pitchScale > 1.0 && resampleBeforeStretching());
390 float windowIncrRatio = 4.5;
391 if (r == 1.0) windowIncrRatio = 4;
392 else if (rsb) windowIncrRatio = 4.5;
393 else windowIncrRatio = 6;
395 outputIncrement = int(windowSize / windowIncrRatio);
396 inputIncrement = int(outputIncrement / r);
397 while (outputIncrement > 1024 * m_rateMultiple &&
398 inputIncrement > 1) {
399 outputIncrement /= 2;
400 inputIncrement = int(outputIncrement / r);
402 size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio));
403 if (windowSize < minwin) windowSize = minwin;
406 // cerr << "adjusting window size from " << windowSize;
407 size_t newWindowSize = roundUp(lrint(windowSize / m_pitchScale));
408 if (newWindowSize < 512) newWindowSize = 512;
409 size_t div = windowSize / newWindowSize;
410 if (inputIncrement > div && outputIncrement > div) {
411 inputIncrement /= div;
412 outputIncrement /= div;
415 // cerr << " to " << windowSize << " (inputIncrement = " << inputIncrement << ", outputIncrement = " << outputIncrement << ")" << endl;
422 inputIncrement = windowSize / 4;
423 while (inputIncrement >= 512) inputIncrement /= 2;
424 outputIncrement = int(floor(inputIncrement * r));
425 if (outputIncrement < 1) {
427 inputIncrement = roundUp(lrint(ceil(outputIncrement / r)));
428 windowSize = inputIncrement * 4;
431 outputIncrement = windowSize / 6;
432 inputIncrement = int(outputIncrement / r);
433 while (outputIncrement > 1024 && inputIncrement > 1) {
434 outputIncrement /= 2;
435 inputIncrement = int(outputIncrement / r);
437 windowSize = std::max(windowSize, roundUp(outputIncrement * 6));
438 if (r > 5) while (windowSize < 8192) windowSize *= 2;
442 if (m_expectedInputDuration > 0) {
443 while (inputIncrement * 4 > m_expectedInputDuration &&
444 inputIncrement > 1) {
449 // windowSize can be almost anything, but it can't be greater than
450 // 4 * m_baseWindowSize unless ratio is less than 1/1024.
452 m_windowSize = windowSize;
453 m_increment = inputIncrement;
455 // When squashing, the greatest theoretically possible output
456 // increment is the input increment. When stretching adaptively
457 // the sky's the limit in principle, but we expect
458 // StretchCalculator to restrict itself to using no more than
459 // twice the basic output increment (i.e. input increment times
460 // ratio) for any chunk.
462 if (m_debugLevel > 0) {
463 cerr << "configure: effective ratio = " << getEffectiveRatio() << endl;
464 cerr << "configure: window size = " << m_windowSize << ", increment = " << m_increment << " (approx output increment = " << int(lrint(m_increment * getEffectiveRatio())) << ")" << endl;
467 if (m_windowSize > m_maxProcessSize) {
468 m_maxProcessSize = m_windowSize;
474 (m_maxProcessSize / m_pitchScale,
475 m_windowSize * 2 * (m_timeRatio > 1.f ? m_timeRatio : 1.f))));
478 // This headroom is so as to try to avoid reallocation when
479 // the pitch scale changes
480 m_outbufSize = m_outbufSize * 16;
483 // This headroom is to permit the processing threads to
484 // run ahead of the buffer output drainage; the exact
485 // amount of headroom is a question of tuning rather than
487 m_outbufSize = m_outbufSize * 16;
491 if (m_debugLevel > 0) {
492 cerr << "configure: outbuf size = " << m_outbufSize << endl;
497 RubberBandStretcher::Impl::configure()
499 // std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = "
500 // << m_pitchScale << ", channels = " << m_channels << std::endl;
502 size_t prevWindowSize = m_windowSize;
503 size_t prevOutbufSize = m_outbufSize;
504 if (m_windows.empty()) {
511 bool windowSizeChanged = (prevWindowSize != m_windowSize);
512 bool outbufSizeChanged = (prevOutbufSize != m_outbufSize);
514 // This function may be called at any time in non-RT mode, after a
515 // parameter has changed. It shouldn't be legal to call it after
516 // processing has already begun.
518 // This function is only called once (on construction) in RT
519 // mode. After that reconfigure() does the work in a hopefully
522 set<size_t> windowSizes;
524 windowSizes.insert(m_baseWindowSize);
525 windowSizes.insert(m_baseWindowSize / 2);
526 windowSizes.insert(m_baseWindowSize * 2);
527 // windowSizes.insert(m_baseWindowSize * 4);
529 windowSizes.insert(m_windowSize);
531 if (windowSizeChanged) {
533 for (set<size_t>::const_iterator i = windowSizes.begin();
534 i != windowSizes.end(); ++i) {
535 if (m_windows.find(*i) == m_windows.end()) {
536 m_windows[*i] = new Window<float>(HanningWindow, *i);
539 m_window = m_windows[m_windowSize];
541 if (m_debugLevel > 0) {
542 cerr << "Window area: " << m_window->getArea() << "; synthesis window area: " << m_window->getArea() << endl;
546 if (windowSizeChanged || outbufSizeChanged) {
548 for (size_t c = 0; c < m_channelData.size(); ++c) {
549 delete m_channelData[c];
551 m_channelData.clear();
553 for (size_t c = 0; c < m_channels; ++c) {
554 m_channelData.push_back
555 (new ChannelData(windowSizes, 1, m_windowSize, m_outbufSize));
559 if (!m_realtime && windowSizeChanged) {
561 m_studyFFT = new FFT(m_windowSize, m_debugLevel);
562 m_studyFFT->initFloat();
565 if (m_pitchScale != 1.0 ||
566 (m_options & OptionPitchHighConsistency) ||
569 for (size_t c = 0; c < m_channels; ++c) {
571 if (m_channelData[c]->resampler) continue;
573 m_channelData[c]->resampler =
574 new Resampler(Resampler::FastestTolerable, 1, 4096 * 16,
577 // rbs is the amount of buffer space we think we'll need
578 // for resampling; but allocate a sensible amount in case
579 // the pitch scale changes during use
581 lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale));
582 if (rbs < m_increment * 16) rbs = m_increment * 16;
583 m_channelData[c]->setResampleBufSize(rbs);
587 // stretchAudioCurve is unused in RT mode; phaseResetAudioCurve,
588 // silentAudioCurve and stretchCalculator however are used in all
591 delete m_phaseResetAudioCurve;
592 m_phaseResetAudioCurve = new PercussiveAudioCurve
593 (m_sampleRate, m_windowSize);
595 delete m_silentAudioCurve;
596 m_silentAudioCurve = new SilentAudioCurve
597 (m_sampleRate, m_windowSize);
600 delete m_stretchAudioCurve;
601 if (!(m_options & OptionStretchPrecise)) {
602 m_stretchAudioCurve = new SpectralDifferenceAudioCurve
603 (m_sampleRate, m_windowSize);
605 m_stretchAudioCurve = new ConstantAudioCurve
606 (m_sampleRate, m_windowSize);
610 delete m_stretchCalculator;
611 m_stretchCalculator = new StretchCalculator
612 (m_sampleRate, m_increment,
613 !(m_options & OptionTransientsSmooth));
615 m_stretchCalculator->setDebugLevel(m_debugLevel);
618 // Prepare the inbufs with half a chunk of emptiness. The centre
619 // point of the first processing chunk for the onset detector
620 // should be the first sample of the audio, and we continue until
621 // we can no longer centre a chunk within the input audio. The
622 // number of onset detector chunks will be the number of audio
623 // samples input, divided by the input increment, plus one.
625 // In real-time mode, we don't do this prefill -- it's better to
626 // start with a swoosh than introduce more latency, and we don't
627 // want gaps when the ratio changes.
630 for (size_t c = 0; c < m_channels; ++c) {
631 m_channelData[c]->reset();
632 m_channelData[c]->inbuf->zero(m_windowSize/2);
639 RubberBandStretcher::Impl::reconfigure()
642 if (m_mode == Studying) {
643 // stop and calculate the stretch curve so far, then reset
646 m_phaseResetDf.clear();
654 size_t prevWindowSize = m_windowSize;
655 size_t prevOutbufSize = m_outbufSize;
659 // There are various allocations in this function, but they should
660 // never happen in normal use -- they just recover from the case
661 // where not all of the things we need were correctly created when
662 // we first configured (for whatever reason). This is intended to
663 // be "effectively" realtime safe. The same goes for
664 // ChannelData::setOutbufSize and setWindowSize.
666 if (m_windowSize != prevWindowSize) {
668 if (m_windows.find(m_windowSize) == m_windows.end()) {
669 std::cerr << "WARNING: reconfigure(): window allocation (size " << m_windowSize << ") required in RT mode" << std::endl;
670 m_windows[m_windowSize] = new Window<float>(HanningWindow, m_windowSize);
672 m_window = m_windows[m_windowSize];
674 for (size_t c = 0; c < m_channels; ++c) {
675 m_channelData[c]->setWindowSize(m_windowSize);
679 if (m_outbufSize != prevOutbufSize) {
680 for (size_t c = 0; c < m_channels; ++c) {
681 m_channelData[c]->setOutbufSize(m_outbufSize);
685 if (m_pitchScale != 1.0) {
686 for (size_t c = 0; c < m_channels; ++c) {
688 if (m_channelData[c]->resampler) continue;
690 std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
692 m_channelData[c]->resampler =
693 new Resampler(Resampler::FastestTolerable, 1, m_windowSize,
696 m_channelData[c]->setResampleBufSize
697 (lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)));
701 if (m_windowSize != prevWindowSize) {
702 m_phaseResetAudioCurve->setWindowSize(m_windowSize);
707 RubberBandStretcher::Impl::getLatency() const
709 if (!m_realtime) return 0;
710 return int((m_windowSize/2) / m_pitchScale + 1);
714 RubberBandStretcher::Impl::setTransientsOption(Options options)
717 cerr << "RubberBandStretcher::Impl::setTransientsOption: Not permissible in non-realtime mode" << endl;
720 int mask = (OptionTransientsMixed | OptionTransientsSmooth | OptionTransientsCrisp);
723 m_options |= options;
725 m_stretchCalculator->setUseHardPeaks
726 (!(m_options & OptionTransientsSmooth));
730 RubberBandStretcher::Impl::setPhaseOption(Options options)
732 int mask = (OptionPhaseLaminar | OptionPhaseIndependent);
735 m_options |= options;
739 RubberBandStretcher::Impl::setFormantOption(Options options)
741 int mask = (OptionFormantShifted | OptionFormantPreserved);
744 m_options |= options;
748 RubberBandStretcher::Impl::setPitchOption(Options options)
751 cerr << "RubberBandStretcher::Impl::setPitchOption: Pitch option is not used in non-RT mode" << endl;
755 Options prior = m_options;
757 int mask = (OptionPitchHighQuality |
758 OptionPitchHighSpeed |
759 OptionPitchHighConsistency);
762 m_options |= options;
764 if (prior != m_options) reconfigure();
768 RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool final)
770 Profiler profiler("RubberBandStretcher::Impl::study");
773 if (m_debugLevel > 1) {
774 cerr << "RubberBandStretcher::Impl::study: Not meaningful in realtime mode" << endl;
779 if (m_mode == Processing || m_mode == Finished) {
780 cerr << "RubberBandStretcher::Impl::study: Cannot study after processing" << endl;
787 ChannelData &cd = *m_channelData[0];
788 RingBuffer<float> &inbuf = *cd.inbuf;
790 const float *mixdown;
793 if (m_channels > 1 || final) {
794 // mix down into a single channel for analysis
795 mdalloc = new float[samples];
796 for (size_t i = 0; i < samples; ++i) {
798 mdalloc[i] = input[0][i];
803 for (size_t c = 1; c < m_channels; ++c) {
804 for (size_t i = 0; i < samples; ++i) {
805 mdalloc[i] += input[c][i];
808 for (size_t i = 0; i < samples; ++i) {
809 mdalloc[i] /= m_channels;
816 while (consumed < samples) {
818 size_t writable = inbuf.getWriteSpace();
819 writable = min(writable, samples - consumed);
823 cerr << "WARNING: writable == 0 (consumed = " << consumed << ", samples = " << samples << ")" << endl;
825 inbuf.write(mixdown + consumed, writable);
826 consumed += writable;
829 while ((inbuf.getReadSpace() >= int(m_windowSize)) ||
830 (final && (inbuf.getReadSpace() >= int(m_windowSize/2)))) {
832 // We know we have at least m_windowSize samples available
833 // in m_inbuf. We need to peek m_windowSize of them for
834 // processing, and then skip m_increment to advance the
837 // cd.accumulator is not otherwise used during studying,
838 // so we can use it as a temporary buffer here
841 inbuf.peek(cd.accumulator, m_windowSize);
843 size_t got = inbuf.peek(cd.accumulator, m_windowSize);
845 assert(final || got == m_windowSize);
847 m_window->cut(cd.accumulator);
849 // We don't need the fftshift for studying, as we're only
850 // interested in magnitude
852 m_studyFFT->forwardMagnitude(cd.accumulator, cd.fltbuf);
854 float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment);
855 m_phaseResetDf.push_back(df);
857 // cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: ";
859 df = m_stretchAudioCurve->process(cd.fltbuf, m_increment);
860 m_stretchDf.push_back(df);
862 df = m_silentAudioCurve->process(cd.fltbuf, m_increment);
863 bool silent = (df > 0.f);
864 if (silent && m_debugLevel > 1) {
865 cerr << "silence found at " << m_inputDuration << endl;
867 m_silence.push_back(silent);
869 // cout << df << endl;
871 // We have augmented the input by m_windowSize/2 so
872 // that the first chunk is centred on the first audio
873 // sample. We want to ensure that m_inputDuration
874 // contains the exact input duration without including
875 // this extra bit. We just add up all the increments
876 // here, and deduct the extra afterwards.
878 m_inputDuration += m_increment;
879 // cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl;
880 inbuf.skip(m_increment);
885 int rs = inbuf.getReadSpace();
886 m_inputDuration += rs;
887 // cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
889 if (m_inputDuration > m_windowSize/2) { // deducting the extra
890 m_inputDuration -= m_windowSize/2;
894 if (m_channels > 1) delete[] mdalloc;
898 RubberBandStretcher::Impl::getOutputIncrements() const
901 return m_outputIncrements;
903 vector<int> increments;
904 while (m_lastProcessOutputIncrements.getReadSpace() > 0) {
905 increments.push_back(m_lastProcessOutputIncrements.readOne());
912 RubberBandStretcher::Impl::getPhaseResetCurve() const
915 return m_phaseResetDf;
918 while (m_lastProcessPhaseResetDf.getReadSpace() > 0) {
919 df.push_back(m_lastProcessPhaseResetDf.readOne());
926 RubberBandStretcher::Impl::getExactTimePoints() const
928 std::vector<int> points;
930 std::vector<StretchCalculator::Peak> peaks =
931 m_stretchCalculator->getLastCalculatedPeaks();
932 for (size_t i = 0; i < peaks.size(); ++i) {
933 points.push_back(peaks[i].chunk);
940 RubberBandStretcher::Impl::calculateStretch()
942 Profiler profiler("RubberBandStretcher::Impl::calculateStretch");
944 size_t inputDuration = m_inputDuration;
946 if (!m_realtime && m_expectedInputDuration > 0) {
947 if (m_expectedInputDuration != inputDuration) {
948 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;
949 inputDuration = m_expectedInputDuration;
953 std::vector<int> increments = m_stretchCalculator->calculate
954 (getEffectiveRatio(),
960 for (size_t i = 0; i < increments.size(); ++i) {
961 if (i >= m_silence.size()) break;
962 if (m_silence[i]) ++history;
964 if (history >= int(m_windowSize / m_increment) && increments[i] >= 0) {
965 increments[i] = -increments[i];
966 if (m_debugLevel > 1) {
967 std::cerr << "phase reset on silence (silent history == "
968 << history << ")" << std::endl;
973 if (m_outputIncrements.empty()) m_outputIncrements = increments;
975 for (size_t i = 0; i < increments.size(); ++i) {
976 m_outputIncrements.push_back(increments[i]);
984 RubberBandStretcher::Impl::setDebugLevel(int level)
986 m_debugLevel = level;
987 if (m_stretchCalculator) m_stretchCalculator->setDebugLevel(level);
991 RubberBandStretcher::Impl::getSamplesRequired() const
993 Profiler profiler("RubberBandStretcher::Impl::getSamplesRequired");
997 for (size_t c = 0; c < m_channels; ++c) {
1001 ChannelData &cd = *m_channelData[c];
1002 RingBuffer<float> &inbuf = *cd.inbuf;
1004 size_t rs = inbuf.getReadSpace();
1006 // See notes in testInbufReadSpace
1008 if (rs < m_windowSize && !cd.draining) {
1010 if (cd.inputSize == -1) {
1011 reqdHere = m_windowSize - rs;
1012 if (reqdHere > reqd) reqd = reqdHere;
1017 reqdHere = m_windowSize;
1018 if (reqdHere > reqd) reqd = reqdHere;
1028 RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final)
1030 Profiler profiler("RubberBandStretcher::Impl::process");
1032 if (m_mode == Finished) {
1033 cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl;
1037 if (m_mode == JustCreated || m_mode == Studying) {
1039 if (m_mode == Studying) {
1043 for (size_t c = 0; c < m_channels; ++c) {
1044 m_channelData[c]->reset();
1045 m_channelData[c]->inbuf->zero(m_windowSize/2);
1049 MutexLocker locker(&m_threadSetMutex);
1051 for (size_t c = 0; c < m_channels; ++c) {
1052 ProcessThread *thread = new ProcessThread(this, c);
1053 m_threadSet.insert(thread);
1057 if (m_debugLevel > 0) {
1058 cerr << m_channels << " threads created" << endl;
1062 m_mode = Processing;
1065 bool allConsumed = false;
1067 size_t *consumed = (size_t *)alloca(m_channels * sizeof(size_t));
1068 for (size_t c = 0; c < m_channels; ++c) {
1072 while (!allConsumed) {
1074 //#ifndef NO_THREADING
1075 // if (m_threaded) {
1076 // pthread_mutex_lock(&m_inputProcessedMutex);
1080 // In a threaded mode, our "consumed" counters only indicate
1081 // the number of samples that have been taken into the input
1082 // ring buffers waiting to be processed by the process thread.
1083 // In non-threaded mode, "consumed" counts the number that
1084 // have actually been processed.
1088 for (size_t c = 0; c < m_channels; ++c) {
1089 consumed[c] += consumeChannel(c,
1090 input[c] + consumed[c],
1091 samples - consumed[c],
1093 if (consumed[c] < samples) {
1094 allConsumed = false;
1095 // cerr << "process: waiting on input consumption for channel " << c << endl;
1098 m_channelData[c]->inputSize = m_channelData[c]->inCount;
1100 // cerr << "process: happy with channel " << c << endl;
1102 if (!m_threaded && !m_realtime) {
1103 bool any = false, last = false;
1104 processChunks(c, any, last);
1109 // When running in real time, we need to process both
1110 // channels in step because we will need to use the sum of
1111 // their frequency domain representations as the input to
1112 // the realtime onset detector
1117 for (ThreadSet::iterator i = m_threadSet.begin();
1118 i != m_threadSet.end(); ++i) {
1119 (*i)->signalDataAvailable();
1122 m_spaceAvailable.wait(500);
1127 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;
1128 for (size_t c = 0; c < m_channels; ++c) {
1129 cerr << "channel " << c << ": " << samples << " provided, " << consumed[c] << " consumed" << endl;
1136 // if (!allConsumed) cerr << "process looping" << endl;
1140 // cerr << "process returning" << endl;
1142 if (final) m_mode = Finished;