File: StretcherImpl.h

package info (click to toggle)
rubberband 1.8.1-7
  • links: PTS, VCS
  • area: main
  • in suites: buster, stretch
  • size: 1,376 kB
  • ctags: 1,909
  • sloc: cpp: 13,156; ansic: 2,777; makefile: 244; java: 77
file content (269 lines) | stat: -rw-r--r-- 7,968 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Rubber Band Library
    An audio time-stretching and pitch-shifting library.
    Copyright 2007-2012 Particular Programs Ltd.

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.  See the file
    COPYING included with this distribution for more information.

    Alternatively, if you have a valid commercial licence for the
    Rubber Band Library obtained by agreement with the copyright
    holders, you may redistribute and/or modify it under the terms
    described in that licence.

    If you wish to distribute code using the Rubber Band Library
    under terms other than those of the GNU General Public License,
    you must obtain a valid commercial licence before doing so.
*/

#ifndef _RUBBERBAND_STRETCHERIMPL_H_
#define _RUBBERBAND_STRETCHERIMPL_H_

#include "rubberband/RubberBandStretcher.h"

#include "dsp/Window.h"
#include "dsp/SincWindow.h"
#include "dsp/FFT.h"

#include "audiocurves/CompoundAudioCurve.h"

#include "base/RingBuffer.h"
#include "base/Scavenger.h"
#include "system/Thread.h"
#include "system/sysutils.h"

#include <set>

using namespace RubberBand;

namespace RubberBand
{

#ifdef PROCESS_SAMPLE_TYPE
typedef PROCESS_SAMPLE_TYPE process_t;
#else
typedef double process_t;
#endif

class AudioCurveCalculator;
class StretchCalculator;

class RubberBandStretcher::Impl
{
public:
    Impl(size_t sampleRate, size_t channels, Options options,
         double initialTimeRatio, double initialPitchScale);
    ~Impl();
    
    void reset();
    void setTimeRatio(double ratio);
    void setPitchScale(double scale);

    double getTimeRatio() const;
    double getPitchScale() const;

    size_t getLatency() const;

    void setTransientsOption(Options);
    void setDetectorOption(Options);
    void setPhaseOption(Options);
    void setFormantOption(Options);
    void setPitchOption(Options);

    void setExpectedInputDuration(size_t samples);
    void setMaxProcessSize(size_t samples);
    void setKeyFrameMap(const std::map<size_t, size_t> &);

    size_t getSamplesRequired() const;

    void study(const float *const *input, size_t samples, bool final);
    void process(const float *const *input, size_t samples, bool final);

    int available() const;
    size_t retrieve(float *const *output, size_t samples) const;

    float getFrequencyCutoff(int n) const;
    void setFrequencyCutoff(int n, float f);

    size_t getInputIncrement() const {
        return m_increment;
    }

    std::vector<int> getOutputIncrements() const;
    std::vector<float> getPhaseResetCurve() const;
    std::vector<int> getExactTimePoints() const;

    size_t getChannelCount() const {
        return m_channels;
    }
    
    void calculateStretch();

    void setDebugLevel(int level);
    static void setDefaultDebugLevel(int level) { m_defaultDebugLevel = level; }

protected:
    size_t m_sampleRate;
    size_t m_channels;

    void prepareChannelMS(size_t channel, const float *const *inputs,
                          size_t offset, size_t samples, float *prepared);
    size_t consumeChannel(size_t channel, const float *const *inputs,
                          size_t offset, size_t samples, bool final);
    void processChunks(size_t channel, bool &any, bool &last);
    bool processOneChunk(); // across all channels, for real time use
    bool processChunkForChannel(size_t channel, size_t phaseIncrement,
                                size_t shiftIncrement, bool phaseReset);
    bool testInbufReadSpace(size_t channel);
    void calculateIncrements(size_t &phaseIncrement,
                             size_t &shiftIncrement, bool &phaseReset);
    bool getIncrements(size_t channel, size_t &phaseIncrement,
                       size_t &shiftIncrement, bool &phaseReset);
    void analyseChunk(size_t channel);
    void modifyChunk(size_t channel, size_t outputIncrement, bool phaseReset);
    void formantShiftChunk(size_t channel);
    void synthesiseChunk(size_t channel, size_t shiftIncrement);
    void writeChunk(size_t channel, size_t shiftIncrement, bool last);

    void calculateSizes();
    void configure();
    void reconfigure();

    double getEffectiveRatio() const;
    
    size_t roundUp(size_t value); // to next power of two

    template <typename T, typename S>
    void cutShiftAndFold(T *target, int targetSize,
                         S *src, // destructive to src
                         Window<float> *window) {
        window->cut(src);
        const int windowSize = window->getSize();
        const int hs = targetSize / 2;
        if (windowSize == targetSize) {
            v_convert(target, src + hs, hs);
            v_convert(target + hs, src, hs);
        } else {
            v_zero(target, targetSize);
            int j = targetSize - windowSize/2;
            while (j < 0) j += targetSize;
            for (int i = 0; i < windowSize; ++i) {
                target[j] += src[i];
                if (++j == targetSize) j = 0;
            }
        }
    }

    bool resampleBeforeStretching() const;
    
    double m_timeRatio;
    double m_pitchScale;

    // n.b. either m_fftSize is an integer multiple of m_windowSize,
    // or vice versa
    size_t m_fftSize;
    size_t m_aWindowSize; //!!! or use m_awindow->getSize() throughout?
    size_t m_sWindowSize; //!!! or use m_swindow->getSize() throughout?
    size_t m_increment;
    size_t m_outbufSize;

    size_t m_maxProcessSize;
    size_t m_expectedInputDuration;

#ifndef NO_THREADING    
    bool m_threaded;
#endif

    bool m_realtime;
    Options m_options;
    int m_debugLevel;

    enum ProcessMode {
        JustCreated,
        Studying,
        Processing,
        Finished
    };

    ProcessMode m_mode;

    std::map<size_t, Window<float> *> m_windows;
    std::map<size_t, SincWindow<float> *> m_sincs;
    Window<float> *m_awindow;
    SincWindow<float> *m_afilter;
    Window<float> *m_swindow;
    FFT *m_studyFFT;

#ifndef NO_THREADING
    Condition m_spaceAvailable;
    
    class ProcessThread : public Thread
    {
    public:
        ProcessThread(Impl *s, size_t c);
        void run();
        void signalDataAvailable();
        void abandon();
    private:
        Impl *m_s;
        size_t m_channel;
        Condition m_dataAvailable;
        bool m_abandoning;
    };

    mutable Mutex m_threadSetMutex;
    typedef std::set<ProcessThread *> ThreadSet;
    ThreadSet m_threadSet;
    
#if defined HAVE_IPP && !defined USE_SPEEX
    // Exasperatingly, the IPP polyphase resampler does not appear to
    // be thread-safe as advertised -- a good reason to prefer the
    // Speex alternative
    Mutex m_resamplerMutex;
#endif
#endif

    size_t m_inputDuration;
    CompoundAudioCurve::Type m_detectorType;
    std::vector<float> m_phaseResetDf;
    std::vector<float> m_stretchDf;
    std::vector<bool> m_silence;
    int m_silentHistory;

    class ChannelData; 
    std::vector<ChannelData *> m_channelData;

    std::vector<int> m_outputIncrements;

    mutable RingBuffer<int> m_lastProcessOutputIncrements;
    mutable RingBuffer<float> m_lastProcessPhaseResetDf;
    Scavenger<RingBuffer<float> > m_emergencyScavenger;

    CompoundAudioCurve *m_phaseResetAudioCurve;
    AudioCurveCalculator *m_stretchAudioCurve;
    AudioCurveCalculator *m_silentAudioCurve;
    StretchCalculator *m_stretchCalculator;

    float m_freq0;
    float m_freq1;
    float m_freq2;

    size_t m_baseFftSize;
    float m_rateMultiple;

    void writeOutput(RingBuffer<float> &to, float *from,
                     size_t qty, size_t &outCount, size_t theoreticalOut);

    static int m_defaultDebugLevel;
    static const size_t m_defaultIncrement;
    static const size_t m_defaultFftSize;
};

}

#endif