Rename debug -> dump
[ardour.git] / libs / rubberband / src / StretcherImpl.cpp
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2
3 /*
4     Rubber Band
5     An audio time-stretching and pitch-shifting library.
6     Copyright 2007-2008 Chris Cannam.
7     
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.
13 */
14
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"
24 #include "Profiler.h"
25
26 #include <cassert>
27 #include <cmath>
28 #include <set>
29 #include <map>
30
31 using std::cerr;
32 using std::endl;
33 using std::vector;
34 using std::map;
35 using std::set;
36 using std::max;
37 using std::min;
38
39
40 namespace RubberBand {
41
42 const size_t
43 RubberBandStretcher::Impl::m_defaultIncrement = 256;
44
45 const size_t
46 RubberBandStretcher::Impl::m_defaultWindowSize = 2048;
47
48 int
49 RubberBandStretcher::Impl::m_defaultDebugLevel = 0;
50
51
52
53 RubberBandStretcher::Impl::Impl(size_t sampleRate,
54                                 size_t channels,
55                                 Options options,
56                                 double initialTimeRatio,
57                                 double initialPitchScale) :
58     m_sampleRate(sampleRate),
59     m_channels(channels),
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),
67     m_threaded(false),
68     m_realtime(false),
69     m_options(options),
70     m_debugLevel(m_defaultDebugLevel),
71     m_mode(JustCreated),
72     m_window(0),
73     m_studyFFT(0),
74     m_spaceAvailable("space"),
75     m_inputDuration(0),
76     m_silentHistory(0),
77     m_lastProcessOutputIncrements(16),
78     m_lastProcessPhaseResetDf(16),
79     m_phaseResetAudioCurve(0),
80     m_stretchAudioCurve(0),
81     m_silentAudioCurve(0),
82     m_stretchCalculator(0),
83     m_freq0(600),
84     m_freq1(1200),
85     m_freq2(12000),
86     m_baseWindowSize(m_defaultWindowSize)
87 {
88
89     if (m_debugLevel > 0) {
90         cerr << "RubberBandStretcher::Impl::Impl: rate = " << m_sampleRate << ", options = " << options << endl;
91     }
92
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));
98
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;
106             }
107         } else if (options & OptionWindowLong) {
108             m_baseWindowSize = m_baseWindowSize * 2;
109             if (m_debugLevel > 0) {
110                 cerr << "setting baseWindowSize to " << m_baseWindowSize << endl;
111             }
112         }
113         m_windowSize = m_baseWindowSize;
114         m_outbufSize = m_baseWindowSize * 2;
115         m_maxProcessSize = m_baseWindowSize;
116     }
117
118     if (m_options & OptionProcessRealTime) {
119
120         m_realtime = true;
121
122         if (!(m_options & OptionStretchPrecise)) {
123             m_options |= OptionStretchPrecise;
124         }
125     }
126
127     if (m_channels > 1) {
128
129         m_threaded = true;
130
131         if (m_realtime) {
132             m_threaded = false;
133         } else if (m_options & OptionThreadingNever) {
134             m_threaded = false;
135         } else if (!(m_options & OptionThreadingAlways) &&
136                    !system_is_multiprocessor()) {
137             m_threaded = false;
138         }
139
140         if (m_threaded && m_debugLevel > 0) {
141             cerr << "Going multithreaded..." << endl;
142         }
143     }
144
145     configure();
146 }
147
148 RubberBandStretcher::Impl::~Impl()
149 {
150     if (m_threaded) {
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;
156             }
157             (*i)->abandon();
158             (*i)->wait();
159             delete *i;
160         }
161     }
162
163     for (size_t c = 0; c < m_channels; ++c) {
164         delete m_channelData[c];
165     }
166
167     delete m_phaseResetAudioCurve;
168     delete m_stretchAudioCurve;
169     delete m_silentAudioCurve;
170     delete m_stretchCalculator;
171     delete m_studyFFT;
172
173     for (map<size_t, Window<float> *>::iterator i = m_windows.begin();
174          i != m_windows.end(); ++i) {
175         delete i->second;
176     }
177 }
178
179 void
180 RubberBandStretcher::Impl::reset()
181 {
182     if (m_threaded) {
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;
188             }
189             (*i)->abandon();
190             (*i)->wait();
191             delete *i;
192         }
193         m_threadSet.clear();
194     }
195
196     for (size_t c = 0; c < m_channels; ++c) {
197         m_channelData[c]->reset();
198     }
199
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();
204     m_inputDuration = 0;
205     m_silentHistory = 0;
206
207     if (m_threaded) m_threadSetMutex.unlock();
208
209     reconfigure();
210 }
211
212 void
213 RubberBandStretcher::Impl::setTimeRatio(double ratio)
214 {
215     if (!m_realtime) {
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;
218             return;
219         }
220     }
221
222     if (ratio == m_timeRatio) return;
223     m_timeRatio = ratio;
224
225     reconfigure();
226 }
227
228 void
229 RubberBandStretcher::Impl::setPitchScale(double fs)
230 {
231     if (!m_realtime) {
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;
234             return;
235         }
236     }
237
238     if (fs == m_pitchScale) return;
239     
240     bool was1 = (m_pitchScale == 1.f);
241     bool rbs = resampleBeforeStretching();
242
243     m_pitchScale = fs;
244
245     reconfigure();
246
247     if (!(m_options & OptionPitchHighConsistency) &&
248         (was1 || resampleBeforeStretching() != rbs) &&
249         m_pitchScale != 1.f) {
250         
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();
255             }
256         }
257     }
258 }
259
260 double
261 RubberBandStretcher::Impl::getTimeRatio() const
262 {
263     return m_timeRatio;
264 }
265
266 double
267 RubberBandStretcher::Impl::getPitchScale() const
268 {
269     return m_pitchScale;
270 }
271
272 void
273 RubberBandStretcher::Impl::setExpectedInputDuration(size_t samples)
274 {
275     if (samples == m_expectedInputDuration) return;
276     m_expectedInputDuration = samples;
277
278     reconfigure();
279 }
280
281 void
282 RubberBandStretcher::Impl::setMaxProcessSize(size_t samples)
283 {
284     if (samples <= m_maxProcessSize) return;
285     m_maxProcessSize = samples;
286
287     reconfigure();
288 }
289
290 float
291 RubberBandStretcher::Impl::getFrequencyCutoff(int n) const
292 {
293     switch (n) {
294     case 0: return m_freq0;
295     case 1: return m_freq1;
296     case 2: return m_freq2;
297     }
298     return 0.f;
299 }
300
301 void
302 RubberBandStretcher::Impl::setFrequencyCutoff(int n, float f)
303 {
304     switch (n) {
305     case 0: m_freq0 = f; break;
306     case 1: m_freq1 = f; break;
307     case 2: m_freq2 = f; break;
308     }
309 }
310
311 double
312 RubberBandStretcher::Impl::getEffectiveRatio() const
313 {
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).
317
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.
324
325     return m_timeRatio * m_pitchScale;
326 }
327
328 size_t
329 RubberBandStretcher::Impl::roundUp(size_t value)
330 {
331     if (!(value & (value - 1))) return value;
332     int bits = 0;
333     while (value) { ++bits; value >>= 1; }
334     value = 1 << bits;
335     return value;
336 }
337
338 void
339 RubberBandStretcher::Impl::calculateSizes()
340 {
341     size_t inputIncrement = m_defaultIncrement;
342     size_t windowSize = m_baseWindowSize;
343     size_t outputIncrement;
344
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
348         // variable
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;
350         m_pitchScale = 1.0;
351     }
352     if (m_timeRatio <= 0.0) {
353         // Likewise
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;
355         m_timeRatio = 1.0;
356     }
357
358     double r = getEffectiveRatio();
359
360     if (m_realtime) {
361
362         if (r < 1) {
363             
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;
369
370             inputIncrement = int(windowSize / windowIncrRatio);
371             outputIncrement = int(floor(inputIncrement * r));
372
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)));
381                 }
382             }
383
384         } else {
385
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;
391
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);
398             }
399             size_t minwin = roundUp(lrint(outputIncrement * windowIncrRatio));
400             if (windowSize < minwin) windowSize = minwin;
401
402             if (rsb) {
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;
410                     windowSize /= div;
411                 }
412 //                cerr << " to " << windowSize << " (inputIncrement = " << inputIncrement << ", outputIncrement = " << outputIncrement << ")" << endl;
413             }
414         }
415
416     } else {
417
418         if (r < 1) {
419             inputIncrement = windowSize / 4;
420             while (inputIncrement >= 512) inputIncrement /= 2;
421             outputIncrement = int(floor(inputIncrement * r));
422             if (outputIncrement < 1) {
423                 outputIncrement = 1;
424                 inputIncrement = roundUp(lrint(ceil(outputIncrement / r)));
425                 windowSize = inputIncrement * 4;
426             }
427         } else {
428             outputIncrement = windowSize / 6;
429             inputIncrement = int(outputIncrement / r);
430             while (outputIncrement > 1024 && inputIncrement > 1) {
431                 outputIncrement /= 2;
432                 inputIncrement = int(outputIncrement / r);
433             }
434             windowSize = std::max(windowSize, roundUp(outputIncrement * 6));
435             if (r > 5) while (windowSize < 8192) windowSize *= 2;
436         }
437     }
438
439     if (m_expectedInputDuration > 0) {
440         while (inputIncrement * 4 > m_expectedInputDuration &&
441                inputIncrement > 1) {
442             inputIncrement /= 2;
443         }
444     }
445
446     // windowSize can be almost anything, but it can't be greater than
447     // 4 * m_baseWindowSize unless ratio is less than 1/1024.
448
449     m_windowSize = windowSize;
450     m_increment = inputIncrement;
451
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.
458
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;
462     }
463
464     if (m_windowSize > m_maxProcessSize) {
465         m_maxProcessSize = m_windowSize;
466     }
467
468     m_outbufSize =
469         size_t
470         (ceil(max
471               (m_maxProcessSize / m_pitchScale,
472                m_windowSize * 2 * (m_timeRatio > 1.f ? m_timeRatio : 1.f))));
473
474     if (m_realtime) {
475         // This headroom is so as to try to avoid reallocation when
476         // the pitch scale changes
477         m_outbufSize = m_outbufSize * 16;
478     } else {
479         if (m_threaded) {
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
483             // results
484             m_outbufSize = m_outbufSize * 16;
485         }
486     }
487
488     if (m_debugLevel > 0) {
489         cerr << "configure: outbuf size = " << m_outbufSize << endl;
490     }
491 }
492
493 void
494 RubberBandStretcher::Impl::configure()
495 {
496 //    std::cerr << "configure[" << this << "]: realtime = " << m_realtime << ", pitch scale = "
497 //              << m_pitchScale << ", channels = " << m_channels << std::endl;
498
499     size_t prevWindowSize = m_windowSize;
500     size_t prevOutbufSize = m_outbufSize;
501     if (m_windows.empty()) {
502         prevWindowSize = 0;
503         prevOutbufSize = 0;
504     }
505
506     calculateSizes();
507
508     bool windowSizeChanged = (prevWindowSize != m_windowSize);
509     bool outbufSizeChanged = (prevOutbufSize != m_outbufSize);
510
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.
514
515     // This function is only called once (on construction) in RT
516     // mode.  After that reconfigure() does the work in a hopefully
517     // RT-safe way.
518
519     set<size_t> windowSizes;
520     if (m_realtime) {
521         windowSizes.insert(m_baseWindowSize);
522         windowSizes.insert(m_baseWindowSize / 2);
523         windowSizes.insert(m_baseWindowSize * 2);
524 //        windowSizes.insert(m_baseWindowSize * 4);
525     }
526     windowSizes.insert(m_windowSize);
527
528     if (windowSizeChanged) {
529
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);
534             }
535         }
536         m_window = m_windows[m_windowSize];
537
538         if (m_debugLevel > 0) {
539             cerr << "Window area: " << m_window->getArea() << "; synthesis window area: " << m_window->getArea() << endl;
540         }
541     }
542
543     if (windowSizeChanged || outbufSizeChanged) {
544         
545         for (size_t c = 0; c < m_channelData.size(); ++c) {
546             delete m_channelData[c];
547         }
548         m_channelData.clear();
549
550         for (size_t c = 0; c < m_channels; ++c) {
551             m_channelData.push_back
552                 (new ChannelData(windowSizes, 1, m_windowSize, m_outbufSize));
553         }
554     }
555
556     if (!m_realtime && windowSizeChanged) {
557         delete m_studyFFT;
558         m_studyFFT = new FFT(m_windowSize, m_debugLevel);
559         m_studyFFT->initFloat();
560     }
561
562     if (m_pitchScale != 1.0 ||
563         (m_options & OptionPitchHighConsistency) ||
564         m_realtime) {
565
566         for (size_t c = 0; c < m_channels; ++c) {
567
568             if (m_channelData[c]->resampler) continue;
569
570             m_channelData[c]->resampler =
571                 new Resampler(Resampler::FastestTolerable, 1, 4096 * 16,
572                               m_debugLevel);
573
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
577             size_t rbs = 
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);
581         }
582     }
583     
584     // stretchAudioCurve is unused in RT mode; phaseResetAudioCurve,
585     // silentAudioCurve and stretchCalculator however are used in all
586     // modes
587
588     delete m_phaseResetAudioCurve;
589     m_phaseResetAudioCurve = new PercussiveAudioCurve
590         (m_sampleRate, m_windowSize);
591
592     delete m_silentAudioCurve;
593     m_silentAudioCurve = new SilentAudioCurve
594         (m_sampleRate, m_windowSize);
595
596     if (!m_realtime) {
597         delete m_stretchAudioCurve;
598         if (!(m_options & OptionStretchPrecise)) {
599             m_stretchAudioCurve = new SpectralDifferenceAudioCurve
600                 (m_sampleRate, m_windowSize);
601         } else {
602             m_stretchAudioCurve = new ConstantAudioCurve
603                 (m_sampleRate, m_windowSize);
604         }
605     }
606
607     delete m_stretchCalculator;
608     m_stretchCalculator = new StretchCalculator
609         (m_sampleRate, m_increment,
610          !(m_options & OptionTransientsSmooth));
611
612     m_stretchCalculator->setDebugLevel(m_debugLevel);
613     m_inputDuration = 0;
614
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.
621
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.
625
626     if (!m_realtime) {
627         for (size_t c = 0; c < m_channels; ++c) {
628             m_channelData[c]->reset();
629             m_channelData[c]->inbuf->zero(m_windowSize/2);
630         }
631     }
632 }
633
634
635 void
636 RubberBandStretcher::Impl::reconfigure()
637 {
638     if (!m_realtime) {
639         if (m_mode == Studying) {
640             // stop and calculate the stretch curve so far, then reset
641             // the df vectors
642             calculateStretch();
643             m_phaseResetDf.clear();
644             m_stretchDf.clear();
645             m_silence.clear();
646             m_inputDuration = 0;
647         }
648         configure();
649     }
650
651     size_t prevWindowSize = m_windowSize;
652     size_t prevOutbufSize = m_outbufSize;
653
654     calculateSizes();
655
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.
662
663     if (m_windowSize != prevWindowSize) {
664
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);
668         }
669         m_window = m_windows[m_windowSize];
670
671         for (size_t c = 0; c < m_channels; ++c) {
672             m_channelData[c]->setWindowSize(m_windowSize);
673         }
674     }
675
676     if (m_outbufSize != prevOutbufSize) {
677         for (size_t c = 0; c < m_channels; ++c) {
678             m_channelData[c]->setOutbufSize(m_outbufSize);
679         }
680     }
681
682     if (m_pitchScale != 1.0) {
683         for (size_t c = 0; c < m_channels; ++c) {
684
685             if (m_channelData[c]->resampler) continue;
686
687             std::cerr << "WARNING: reconfigure(): resampler construction required in RT mode" << std::endl;
688
689             m_channelData[c]->resampler =
690                 new Resampler(Resampler::FastestTolerable, 1, m_windowSize,
691                               m_debugLevel);
692
693             m_channelData[c]->setResampleBufSize
694                 (lrintf(ceil((m_increment * m_timeRatio * 2) / m_pitchScale)));
695         }
696     }
697
698     if (m_windowSize != prevWindowSize) {
699         m_phaseResetAudioCurve->setWindowSize(m_windowSize);
700     }
701 }
702
703 size_t
704 RubberBandStretcher::Impl::getLatency() const
705 {
706     if (!m_realtime) return 0;
707     return int((m_windowSize/2) / m_pitchScale + 1);
708 }
709
710 void
711 RubberBandStretcher::Impl::setTransientsOption(Options options)
712 {
713     if (!m_realtime) {
714         cerr << "RubberBandStretcher::Impl::setTransientsOption: Not permissible in non-realtime mode" << endl;
715         return;
716     }
717     int mask = (OptionTransientsMixed | OptionTransientsSmooth | OptionTransientsCrisp);
718     m_options &= ~mask;
719     options &= mask;
720     m_options |= options;
721
722     m_stretchCalculator->setUseHardPeaks
723         (!(m_options & OptionTransientsSmooth));
724 }
725
726 void
727 RubberBandStretcher::Impl::setPhaseOption(Options options)
728 {
729     int mask = (OptionPhaseLaminar | OptionPhaseIndependent);
730     m_options &= ~mask;
731     options &= mask;
732     m_options |= options;
733 }
734
735 void
736 RubberBandStretcher::Impl::setFormantOption(Options options)
737 {
738     int mask = (OptionFormantShifted | OptionFormantPreserved);
739     m_options &= ~mask;
740     options &= mask;
741     m_options |= options;
742 }
743
744 void
745 RubberBandStretcher::Impl::setPitchOption(Options options)
746 {
747     if (!m_realtime) {
748         cerr << "RubberBandStretcher::Impl::setPitchOption: Pitch option is not used in non-RT mode" << endl;
749         return;
750     }
751
752     Options prior = m_options;
753
754     int mask = (OptionPitchHighQuality |
755                 OptionPitchHighSpeed |
756                 OptionPitchHighConsistency);
757     m_options &= ~mask;
758     options &= mask;
759     m_options |= options;
760
761     if (prior != m_options) reconfigure();
762 }
763
764 void
765 RubberBandStretcher::Impl::study(const float *const *input, size_t samples, bool final)
766 {
767     Profiler profiler("RubberBandStretcher::Impl::study");
768
769     if (m_realtime) {
770         if (m_debugLevel > 1) {
771             cerr << "RubberBandStretcher::Impl::study: Not meaningful in realtime mode" << endl;
772         }
773         return;
774     }
775
776     if (m_mode == Processing || m_mode == Finished) {
777         cerr << "RubberBandStretcher::Impl::study: Cannot study after processing" << endl;
778         return;
779     }
780     m_mode = Studying;
781     
782     size_t consumed = 0;
783
784     ChannelData &cd = *m_channelData[0];
785     RingBuffer<float> &inbuf = *cd.inbuf;
786
787     const float *mixdown;
788     float *mdalloc = 0;
789
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) {
794             if (i < samples) {
795                 mdalloc[i] = input[0][i];
796             } else {
797                 mdalloc[i] = 0.f;
798             }
799         }
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];
803             }
804         }
805         for (size_t i = 0; i < samples; ++i) {
806             mdalloc[i] /= m_channels;
807         }
808         mixdown = mdalloc;
809     } else {
810         mixdown = input[0];
811     }
812
813     while (consumed < samples) {
814
815         size_t writable = inbuf.getWriteSpace();
816         writable = min(writable, samples - consumed);
817
818         if (writable == 0) {
819             // warn
820             cerr << "WARNING: writable == 0 (consumed = " << consumed << ", samples = " << samples << ")" << endl;
821         } else {
822             inbuf.write(mixdown + consumed, writable);
823             consumed += writable;
824         }
825
826         while ((inbuf.getReadSpace() >= int(m_windowSize)) ||
827                (final && (inbuf.getReadSpace() >= int(m_windowSize/2)))) {
828
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
832             // read pointer.
833
834             // cd.accumulator is not otherwise used during studying,
835             // so we can use it as a temporary buffer here
836
837             size_t got = inbuf.peek(cd.accumulator, m_windowSize);
838             assert(final || got == m_windowSize);
839
840             m_window->cut(cd.accumulator);
841
842             // We don't need the fftshift for studying, as we're only
843             // interested in magnitude
844
845             m_studyFFT->forwardMagnitude(cd.accumulator, cd.fltbuf);
846
847             float df = m_phaseResetAudioCurve->process(cd.fltbuf, m_increment);
848             m_phaseResetDf.push_back(df);
849
850 //            cout << m_phaseResetDf.size() << " [" << final << "] -> " << df << " \t: ";
851
852             df = m_stretchAudioCurve->process(cd.fltbuf, m_increment);
853             m_stretchDf.push_back(df);
854
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;
859             }
860             m_silence.push_back(silent);
861
862 //            cout << df << endl;
863
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.
870
871             m_inputDuration += m_increment;
872 //                cerr << "incr input duration by increment: " << m_increment << " -> " << m_inputDuration << endl;
873             inbuf.skip(m_increment);
874         }
875     }
876
877     if (final) {
878         int rs = inbuf.getReadSpace();
879         m_inputDuration += rs;
880 //        cerr << "incr input duration by read space: " << rs << " -> " << m_inputDuration << endl;
881
882         if (m_inputDuration > m_windowSize/2) { // deducting the extra
883             m_inputDuration -= m_windowSize/2;
884         }
885     }
886
887     if (m_channels > 1) delete[] mdalloc;
888 }
889
890 vector<int>
891 RubberBandStretcher::Impl::getOutputIncrements() const
892 {
893     if (!m_realtime) {
894         return m_outputIncrements;
895     } else {
896         vector<int> increments;
897         while (m_lastProcessOutputIncrements.getReadSpace() > 0) {
898             increments.push_back(m_lastProcessOutputIncrements.readOne());
899         }
900         return increments;
901     }
902 }
903
904 vector<float>
905 RubberBandStretcher::Impl::getPhaseResetCurve() const
906 {
907     if (!m_realtime) {
908         return m_phaseResetDf;
909     } else {
910         vector<float> df;
911         while (m_lastProcessPhaseResetDf.getReadSpace() > 0) {
912             df.push_back(m_lastProcessPhaseResetDf.readOne());
913         }
914         return df;
915     }
916 }
917
918 vector<int>
919 RubberBandStretcher::Impl::getExactTimePoints() const
920 {
921     std::vector<int> points;
922     if (!m_realtime) {
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);
927         }
928     }
929     return points;
930 }
931
932 void
933 RubberBandStretcher::Impl::calculateStretch()
934 {
935     Profiler profiler("RubberBandStretcher::Impl::calculateStretch");
936
937     size_t inputDuration = m_inputDuration;
938
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;
943         }
944     }
945
946     std::vector<int> increments = m_stretchCalculator->calculate
947         (getEffectiveRatio(),
948          inputDuration,
949          m_phaseResetDf,
950          m_stretchDf);
951
952     int history = 0;
953     for (size_t i = 0; i < increments.size(); ++i) {
954         if (i >= m_silence.size()) break;
955         if (m_silence[i]) ++history;
956         else history = 0;
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;
962             }
963         }
964     }
965
966     if (m_outputIncrements.empty()) m_outputIncrements = increments;
967     else {
968         for (size_t i = 0; i < increments.size(); ++i) {
969             m_outputIncrements.push_back(increments[i]);
970         }
971     }
972     
973     return;
974 }
975
976 void
977 RubberBandStretcher::Impl::setDebugLevel(int level)
978 {
979     m_debugLevel = level;
980     if (m_stretchCalculator) m_stretchCalculator->setDebugLevel(level);
981 }       
982
983 size_t
984 RubberBandStretcher::Impl::getSamplesRequired() const
985 {
986     Profiler profiler("RubberBandStretcher::Impl::getSamplesRequired");
987
988     size_t reqd = 0;
989
990     for (size_t c = 0; c < m_channels; ++c) {
991
992         size_t reqdHere = 0;
993
994         ChannelData &cd = *m_channelData[c];
995         RingBuffer<float> &inbuf = *cd.inbuf;
996
997         size_t rs = inbuf.getReadSpace();
998
999         // See notes in testInbufReadSpace 
1000
1001         if (rs < m_windowSize && !cd.draining) {
1002             
1003             if (cd.inputSize == -1) {
1004                 reqdHere = m_windowSize - rs;
1005                 if (reqdHere > reqd) reqd = reqdHere;
1006                 continue;
1007             }
1008         
1009             if (rs == 0) {
1010                 reqdHere = m_windowSize;
1011                 if (reqdHere > reqd) reqd = reqdHere;
1012                 continue;
1013             }
1014         }
1015     }
1016     
1017     return reqd;
1018 }    
1019
1020 void
1021 RubberBandStretcher::Impl::process(const float *const *input, size_t samples, bool final)
1022 {
1023     Profiler profiler("RubberBandStretcher::Impl::process");
1024
1025     if (m_mode == Finished) {
1026         cerr << "RubberBandStretcher::Impl::process: Cannot process again after final chunk" << endl;
1027         return;
1028     }
1029
1030     if (m_mode == JustCreated || m_mode == Studying) {
1031
1032         if (m_mode == Studying) {
1033             calculateStretch();
1034         }
1035
1036         for (size_t c = 0; c < m_channels; ++c) {
1037             m_channelData[c]->reset();
1038             m_channelData[c]->inbuf->zero(m_windowSize/2);
1039         }
1040
1041         if (m_threaded) {
1042             MutexLocker locker(&m_threadSetMutex);
1043
1044             for (size_t c = 0; c < m_channels; ++c) {
1045                 ProcessThread *thread = new ProcessThread(this, c);
1046                 m_threadSet.insert(thread);
1047                 thread->start();
1048             }
1049             
1050             if (m_debugLevel > 0) {
1051                 cerr << m_channels << " threads created" << endl;
1052             }
1053         }
1054         
1055         m_mode = Processing;
1056     }
1057
1058     bool allConsumed = false;
1059
1060     size_t *consumed = (size_t *)alloca(m_channels * sizeof(size_t));
1061     for (size_t c = 0; c < m_channels; ++c) {
1062         consumed[c] = 0;
1063     }
1064
1065     while (!allConsumed) {
1066
1067 //#ifndef NO_THREADING
1068 //        if (m_threaded) {
1069 //            pthread_mutex_lock(&m_inputProcessedMutex);
1070 //        }
1071 //#endif
1072
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.
1078
1079         allConsumed = true;
1080
1081         for (size_t c = 0; c < m_channels; ++c) {
1082             consumed[c] += consumeChannel(c,
1083                                           input[c] + consumed[c],
1084                                           samples - consumed[c],
1085                                           final);
1086             if (consumed[c] < samples) {
1087                 allConsumed = false;
1088 //                cerr << "process: waiting on input consumption for channel " << c << endl;
1089             } else {
1090                 if (final) {
1091                     m_channelData[c]->inputSize = m_channelData[c]->inCount;
1092                 }
1093 //                cerr << "process: happy with channel " << c << endl;
1094             }
1095             if (!m_threaded && !m_realtime) {
1096                 bool any = false, last = false;
1097                 processChunks(c, any, last);
1098             }
1099         }
1100
1101         if (m_realtime) {
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
1106             processOneChunk();
1107         }
1108
1109         if (m_threaded) {
1110             for (ThreadSet::iterator i = m_threadSet.begin();
1111                  i != m_threadSet.end(); ++i) {
1112                 (*i)->signalDataAvailable();
1113             }
1114             if (!allConsumed) {
1115                 m_spaceAvailable.wait(500);
1116             }
1117 /*
1118         } else {
1119             if (!allConsumed) {
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;
1123                 }
1124 //                break;
1125             }
1126 */
1127         }
1128
1129 //        if (!allConsumed) cerr << "process looping" << endl;
1130
1131     }
1132     
1133 //    cerr << "process returning" << endl;
1134
1135     if (final) m_mode = Finished;
1136 }
1137
1138
1139 }
1140