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