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