summaryrefslogtreecommitdiff
path: root/libs/rubberband/src/StretcherImpl.h
blob: 996c61b7ef5b033126b6a60c7078d0ab37bac477 (plain)
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
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Rubber Band
    An audio time-stretching and pitch-shifting library.
    Copyright 2007-2008 Chris Cannam.
    
    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.
*/

#ifndef _RUBBERBAND_STRETCHERIMPL_H_
#define _RUBBERBAND_STRETCHERIMPL_H_

#include "RubberBandStretcher.h"

#include "Window.h"
#include "Thread.h"
#include "RingBuffer.h"
#include "FFT.h"
#include "sysutils.h"

#include <set>

namespace RubberBand
{

class AudioCurve;
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 setPhaseOption(Options);
    void setFormantOption(Options);
    void setPitchOption(Options);

    void setExpectedInputDuration(size_t samples);
    void setMaxProcessSize(size_t samples);

    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;

    size_t consumeChannel(size_t channel, const float *input,
                          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);
    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

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

    size_t m_windowSize;
    size_t m_increment;
    size_t m_outbufSize;

    size_t m_maxProcessSize;
    size_t m_expectedInputDuration;
    
    bool m_threaded;
    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;
    Window<float> *m_window;
    FFT *m_studyFFT;

    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;
    

    size_t m_inputDuration;
    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;

    AudioCurve *m_phaseResetAudioCurve;
    AudioCurve *m_stretchAudioCurve;
    AudioCurve *m_silentAudioCurve;
    StretchCalculator *m_stretchCalculator;

    float m_freq0;
    float m_freq1;
    float m_freq2;

    size_t m_baseWindowSize;
    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_defaultWindowSize;
};

}

#endif