1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rubber Band Library
5     An audio time-stretching and pitch-shifting library.
6     Copyright 2007-2021 Particular Programs Ltd.
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     Alternatively, if you have a valid commercial licence for the
15     Rubber Band Library obtained by agreement with the copyright
16     holders, you may redistribute and/or modify it under the terms
17     described in that licence.
18 
19     If you wish to distribute code using the Rubber Band Library
20     under terms other than those of the GNU General Public License,
21     you must obtain a valid commercial licence before doing so.
22 */
23 
24 #ifndef RUBBERBAND_STRETCHERIMPL_H
25 #define RUBBERBAND_STRETCHERIMPL_H
26 
27 #include "../rubberband/RubberBandStretcher.h"
28 
29 #include "dsp/Window.h"
30 #include "dsp/SincWindow.h"
31 #include "dsp/FFT.h"
32 
33 #include "audiocurves/CompoundAudioCurve.h"
34 
35 #include "base/RingBuffer.h"
36 #include "base/Scavenger.h"
37 #include "system/Thread.h"
38 #include "system/sysutils.h"
39 
40 #include <set>
41 #include <algorithm>
42 
43 using namespace RubberBand;
44 
45 namespace RubberBand
46 {
47 
48 #ifdef PROCESS_SAMPLE_TYPE
49 typedef PROCESS_SAMPLE_TYPE process_t;
50 #else
51 typedef double process_t;
52 #endif
53 
54 class AudioCurveCalculator;
55 class StretchCalculator;
56 
57 class RubberBandStretcher::Impl
58 {
59 public:
60     Impl(size_t sampleRate, size_t channels, Options options,
61          double initialTimeRatio, double initialPitchScale);
62     ~Impl();
63 
64     void reset();
65     void setTimeRatio(double ratio);
66     void setPitchScale(double scale);
67 
68     double getTimeRatio() const;
69     double getPitchScale() const;
70 
71     size_t getLatency() const;
72 
73     void setTransientsOption(Options);
74     void setDetectorOption(Options);
75     void setPhaseOption(Options);
76     void setFormantOption(Options);
77     void setPitchOption(Options);
78 
79     void setExpectedInputDuration(size_t samples);
80     void setMaxProcessSize(size_t samples);
81     void setKeyFrameMap(const std::map<size_t, size_t> &);
82 
83     size_t getSamplesRequired() const;
84 
85     void study(const float *const *input, size_t samples, bool final);
86     void process(const float *const *input, size_t samples, bool final);
87 
88     int available() const;
89     size_t retrieve(float *const *output, size_t samples) const;
90 
91     float getFrequencyCutoff(int n) const;
92     void setFrequencyCutoff(int n, float f);
93 
getInputIncrement()94     size_t getInputIncrement() const {
95         return m_increment;
96     }
97 
98     std::vector<int> getOutputIncrements() const;
99     std::vector<float> getPhaseResetCurve() const;
100     std::vector<int> getExactTimePoints() const;
101 
getChannelCount()102     size_t getChannelCount() const {
103         return m_channels;
104     }
105 
106     void calculateStretch();
107 
108     void setDebugLevel(int level);
setDefaultDebugLevel(int level)109     static void setDefaultDebugLevel(int level) { m_defaultDebugLevel = level; }
110 
111 protected:
112     size_t m_sampleRate;
113     size_t m_channels;
114 
115     void prepareChannelMS(size_t channel, const float *const *inputs,
116                           size_t offset, size_t samples, float *prepared);
117     size_t consumeChannel(size_t channel, const float *const *inputs,
118                           size_t offset, size_t samples, bool final);
119     void processChunks(size_t channel, bool &any, bool &last);
120     bool processOneChunk(); // across all channels, for real time use
121     bool processChunkForChannel(size_t channel, size_t phaseIncrement,
122                                 size_t shiftIncrement, bool phaseReset);
123     bool testInbufReadSpace(size_t channel);
124     void calculateIncrements(size_t &phaseIncrement,
125                              size_t &shiftIncrement, bool &phaseReset);
126     bool getIncrements(size_t channel, size_t &phaseIncrement,
127                        size_t &shiftIncrement, bool &phaseReset);
128     void analyseChunk(size_t channel);
129     void modifyChunk(size_t channel, size_t outputIncrement, bool phaseReset);
130     void formantShiftChunk(size_t channel);
131     void synthesiseChunk(size_t channel, size_t shiftIncrement);
132     void writeChunk(size_t channel, size_t shiftIncrement, bool last);
133 
134     void calculateSizes();
135     void configure();
136     void reconfigure();
137 
138     double getEffectiveRatio() const;
139 
140     size_t roundUp(size_t value); // to next power of two
141 
142     template <typename T, typename S>
cutShiftAndFold(T * target,int targetSize,S * src,Window<float> * window)143     void cutShiftAndFold(T *target, int targetSize,
144                          S *src, // destructive to src
145                          Window<float> *window) {
146         window->cut(src);
147         const int windowSize = window->getSize();
148         const int hs = targetSize / 2;
149         if (windowSize == targetSize) {
150             v_convert(target, src + hs, hs);
151             v_convert(target + hs, src, hs);
152         } else {
153             v_zero(target, targetSize);
154             int j = targetSize - windowSize/2;
155             while (j < 0) j += targetSize;
156             for (int i = 0; i < windowSize; ++i) {
157                 target[j] += src[i];
158                 if (++j == targetSize) j = 0;
159             }
160         }
161     }
162 
163     bool resampleBeforeStretching() const;
164 
165     double m_timeRatio;
166     double m_pitchScale;
167 
168     // n.b. either m_fftSize is an integer multiple of m_windowSize,
169     // or vice versa
170     size_t m_fftSize;
171     size_t m_aWindowSize; //!!! or use m_awindow->getSize() throughout?
172     size_t m_sWindowSize; //!!! or use m_swindow->getSize() throughout?
173     size_t m_increment;
174     size_t m_outbufSize;
175 
176     size_t m_maxProcessSize;
177     size_t m_expectedInputDuration;
178 
179 #ifndef NO_THREADING
180     bool m_threaded;
181 #endif
182 
183     bool m_realtime;
184     Options m_options;
185     int m_debugLevel;
186 
187     enum ProcessMode {
188         JustCreated,
189         Studying,
190         Processing,
191         Finished
192     };
193 
194     ProcessMode m_mode;
195 
196     std::map<size_t, Window<float> *> m_windows;
197     std::map<size_t, SincWindow<float> *> m_sincs;
198     Window<float> *m_awindow;
199     SincWindow<float> *m_afilter;
200     Window<float> *m_swindow;
201     FFT *m_studyFFT;
202 
203 #ifndef NO_THREADING
204     Condition m_spaceAvailable;
205 
206     class ProcessThread : public Thread
207     {
208     public:
209         ProcessThread(Impl *s, size_t c);
210         void run();
211         void signalDataAvailable();
212         void abandon();
213     private:
214         Impl *m_s;
215         size_t m_channel;
216         Condition m_dataAvailable;
217         bool m_abandoning;
218     };
219 
220     mutable Mutex m_threadSetMutex;
221     typedef std::set<ProcessThread *> ThreadSet;
222     ThreadSet m_threadSet;
223 
224 #if defined HAVE_IPP && !defined USE_SPEEX
225     // Exasperatingly, the IPP polyphase resampler does not appear to
226     // be thread-safe as advertised -- a good reason to prefer the
227     // Speex alternative
228     Mutex m_resamplerMutex;
229 #endif
230 #endif
231 
232     size_t m_inputDuration;
233     CompoundAudioCurve::Type m_detectorType;
234     std::vector<float> m_phaseResetDf;
235     std::vector<float> m_stretchDf;
236     std::vector<bool> m_silence;
237     int m_silentHistory;
238 
239     class ChannelData;
240     std::vector<ChannelData *> m_channelData;
241 
242     std::vector<int> m_outputIncrements;
243 
244     mutable RingBuffer<int> m_lastProcessOutputIncrements;
245     mutable RingBuffer<float> m_lastProcessPhaseResetDf;
246     Scavenger<RingBuffer<float> > m_emergencyScavenger;
247 
248     CompoundAudioCurve *m_phaseResetAudioCurve;
249     AudioCurveCalculator *m_stretchAudioCurve;
250     AudioCurveCalculator *m_silentAudioCurve;
251     StretchCalculator *m_stretchCalculator;
252 
253     float m_freq0;
254     float m_freq1;
255     float m_freq2;
256 
257     size_t m_baseFftSize;
258     float m_rateMultiple;
259 
260     void writeOutput(RingBuffer<float> &to, float *from,
261                      size_t qty, size_t &outCount, size_t theoreticalOut);
262 
263     static int m_defaultDebugLevel;
264     static const size_t m_defaultIncrement;
265     static const size_t m_defaultFftSize;
266 };
267 
268 }
269 
270 #endif
271