File: TimeStretchWrapper.h

package info (click to toggle)
sonic-visualiser 5.2.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,744 kB
  • sloc: cpp: 158,888; ansic: 11,920; sh: 1,785; makefile: 517; xml: 64; perl: 31
file content (136 lines) | stat: -rw-r--r-- 3,963 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
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Sonic Visualiser
    An audio file viewer and annotation editor.
    Centre for Digital Music, Queen Mary, University of London.
    
    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 SV_TIME_STRETCH_WRAPPER_H
#define SV_TIME_STRETCH_WRAPPER_H

#include "bqaudioio/ApplicationPlaybackSource.h"

#include "base/BaseTypes.h"

#include <vector>
#include <mutex>

namespace RubberBand {
    class RubberBandStretcher;
}

namespace sv {

/**
 * A breakfastquay::ApplicationPlaybackSource wrapper that implements
 * time-stretching using Rubber Band. Note that the stretcher is
 * bypassed entirely when a ratio of 1.0 is set; this means it's
 * (almost) free to use one of these wrappers normally, but it also
 * means you can't switch from 1.0 to another ratio (or back again)
 * without some audible artifacts.
 *
 * This is real-time safe while the ratio is fixed, and may perform
 * reallocations when the ratio changes.
 */
class TimeStretchWrapper : public breakfastquay::ApplicationPlaybackSource
{
public:
    /**
     * Create a wrapper around the given ApplicationPlaybackSource,
     * implementing another ApplicationPlaybackSource interface that
     * draws from the same source data but with a time-stretcher
     * optionally applied.
     *
     * The wrapper does not take ownership of the wrapped
     * ApplicationPlaybackSource, whose lifespan must exceed that of
     * this object.    
     */
    TimeStretchWrapper(ApplicationPlaybackSource *source);
    ~TimeStretchWrapper();
    
    /**
     * Set a time stretch factor, i.e. playback speed, where 1.0 is
     * normal speed
     */
    void setTimeStretchRatio(double ratio);

    /**
     * Obtain the stretch factor.
     */
    double getTimeStretchRatio() const;

    enum class Quality {
        Faster,
        Finer
    };

    /**
     * Set a quality preference. The default is Finer. Any change will
     * take effect at the next call to reset().
     */
    void setQuality(Quality quality);

    /**
     * Obtain the current quality preference.
     */
    Quality getQuality() const;
    
    /**
     * Clear stretcher buffers.
     */
    void reset();

    // These functions are passed through to the wrapped
    // ApplicationPlaybackSource
    
    std::string getClientName() const override;
    int getApplicationSampleRate() const override;
    int getApplicationChannelCount() const override;

    void setSystemPlaybackBlockSize(int) override;
    void setSystemPlaybackSampleRate(int) override;
    void setSystemPlaybackChannelCount(int) override;
    void setSystemPlaybackLatency(int) override;

    void setOutputLevels(float peakLeft, float peakRight) override;
    void audioProcessingOverload() override;

    /** 
     * Request some samples from the wrapped
     * ApplicationPlaybackSource, time-stretch if appropriate, and
     * return them to the target
     */
    int getSourceSamples(float *const *samples, int nchannels, int nframes)
        override;

private:
    ApplicationPlaybackSource *m_source;
    RubberBand::RubberBandStretcher *m_stretcher;
    double m_timeRatio;
    Quality m_quality;
    bool m_qualityChangePending;
    std::vector<std::vector<float>> m_inputs;
    std::mutex m_mutex;
    int m_stretcherInputSize;
    int m_channelCount;
    int m_lastReportedSystemLatency;
    sv_samplerate_t m_sampleRate;

    void checkStretcher(); // call without m_mutex held
    
    TimeStretchWrapper(const TimeStretchWrapper &)=delete;
    TimeStretchWrapper &operator=(const TimeStretchWrapper &)=delete;
};

} // end namespace sv

#endif