| Chris@738 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@738 | 2 | 
| Chris@738 | 3 /* | 
| Chris@738 | 4     Sonic Visualiser | 
| Chris@738 | 5     An audio file viewer and annotation editor. | 
| Chris@738 | 6     Centre for Digital Music, Queen Mary, University of London. | 
| Chris@738 | 7 | 
| Chris@738 | 8     This program is free software; you can redistribute it and/or | 
| Chris@738 | 9     modify it under the terms of the GNU General Public License as | 
| Chris@738 | 10     published by the Free Software Foundation; either version 2 of the | 
| Chris@738 | 11     License, or (at your option) any later version.  See the file | 
| Chris@738 | 12     COPYING included with this distribution for more information. | 
| Chris@738 | 13 */ | 
| Chris@738 | 14 | 
| Chris@738 | 15 #ifndef SV_TIME_STRETCH_WRAPPER_H | 
| Chris@738 | 16 #define SV_TIME_STRETCH_WRAPPER_H | 
| Chris@738 | 17 | 
| Chris@738 | 18 #include "bqaudioio/ApplicationPlaybackSource.h" | 
| Chris@738 | 19 | 
| Chris@738 | 20 #include "base/BaseTypes.h" | 
| Chris@738 | 21 | 
| Chris@738 | 22 #include <vector> | 
| Chris@738 | 23 #include <mutex> | 
| Chris@738 | 24 | 
| Chris@738 | 25 namespace RubberBand { | 
| Chris@738 | 26     class RubberBandStretcher; | 
| Chris@738 | 27 } | 
| Chris@738 | 28 | 
| Chris@738 | 29 /** | 
| Chris@738 | 30  * A breakfastquay::ApplicationPlaybackSource wrapper that implements | 
| Chris@738 | 31  * time-stretching using Rubber Band. Note that the stretcher is | 
| Chris@738 | 32  * bypassed entirely when a ratio of 1.0 is set; this means it's | 
| Chris@738 | 33  * (almost) free to use one of these wrappers normally, but it also | 
| Chris@738 | 34  * means you can't switch from 1.0 to another ratio (or back again) | 
| Chris@738 | 35  * without some audible artifacts. | 
| Chris@738 | 36  * | 
| Chris@738 | 37  * This is real-time safe while the ratio is fixed, and may perform | 
| Chris@738 | 38  * reallocations when the ratio changes. | 
| Chris@738 | 39  */ | 
| Chris@738 | 40 class TimeStretchWrapper : public breakfastquay::ApplicationPlaybackSource | 
| Chris@738 | 41 { | 
| Chris@738 | 42 public: | 
| Chris@738 | 43     /** | 
| Chris@738 | 44      * Create a wrapper around the given ApplicationPlaybackSource, | 
| Chris@738 | 45      * implementing another ApplicationPlaybackSource interface that | 
| Chris@738 | 46      * draws from the same source data but with a time-stretcher | 
| Chris@738 | 47      * optionally applied. | 
| Chris@738 | 48      * | 
| Chris@738 | 49      * The wrapper does not take ownership of the wrapped | 
| Chris@738 | 50      * ApplicationPlaybackSource, whose lifespan must exceed that of | 
| Chris@738 | 51      * this object. | 
| Chris@738 | 52      */ | 
| Chris@738 | 53     TimeStretchWrapper(ApplicationPlaybackSource *source); | 
| Chris@738 | 54     ~TimeStretchWrapper(); | 
| Chris@738 | 55 | 
| Chris@738 | 56     /** | 
| Chris@738 | 57      * Set a time stretch factor, i.e. playback speed, where 1.0 is | 
| Chris@738 | 58      * normal speed | 
| Chris@738 | 59      */ | 
| Chris@738 | 60     void setTimeStretchRatio(double ratio); | 
| Chris@738 | 61 | 
| Chris@738 | 62     /** | 
| Chris@738 | 63      * Clear stretcher buffers. | 
| Chris@738 | 64      */ | 
| Chris@738 | 65     void reset(); | 
| Chris@738 | 66 | 
| Chris@738 | 67     // These functions are passed through to the wrapped | 
| Chris@738 | 68     // ApplicationPlaybackSource | 
| Chris@738 | 69 | 
| Chris@738 | 70     std::string getClientName() const override; | 
| Chris@738 | 71     int getApplicationSampleRate() const override; | 
| Chris@738 | 72     int getApplicationChannelCount() const override; | 
| Chris@738 | 73 | 
| Chris@738 | 74     void setSystemPlaybackBlockSize(int) override; | 
| Chris@738 | 75     void setSystemPlaybackSampleRate(int) override; | 
| Chris@738 | 76     void setSystemPlaybackChannelCount(int) override; | 
| Chris@738 | 77     void setSystemPlaybackLatency(int) override; | 
| Chris@738 | 78 | 
| Chris@738 | 79     void setOutputLevels(float peakLeft, float peakRight) override; | 
| Chris@738 | 80     void audioProcessingOverload() override; | 
| Chris@738 | 81 | 
| Chris@738 | 82     /** | 
| Chris@738 | 83      * Request some samples from the wrapped | 
| Chris@738 | 84      * ApplicationPlaybackSource, time-stretch if appropriate, and | 
| Chris@738 | 85      * return them to the target | 
| Chris@738 | 86      */ | 
| Chris@738 | 87     int getSourceSamples(float *const *samples, int nchannels, int nframes) | 
| Chris@738 | 88         override; | 
| Chris@738 | 89 | 
| Chris@738 | 90 private: | 
| Chris@738 | 91     ApplicationPlaybackSource *m_source; | 
| Chris@738 | 92     RubberBand::RubberBandStretcher *m_stretcher; | 
| Chris@738 | 93     double m_timeRatio; | 
| Chris@738 | 94     std::vector<std::vector<float>> m_inputs; | 
| Chris@738 | 95     std::mutex m_mutex; | 
| Chris@738 | 96     sv_frame_t m_stretcherInputSize; | 
| Chris@738 | 97     int m_channelCount; | 
| Chris@738 | 98     sv_samplerate_t m_sampleRate; | 
| Chris@738 | 99 | 
| Chris@738 | 100     void checkStretcher(); // call without m_mutex held | 
| Chris@738 | 101 | 
| Chris@738 | 102     TimeStretchWrapper(const TimeStretchWrapper &)=delete; | 
| Chris@738 | 103     TimeStretchWrapper &operator=(const TimeStretchWrapper &)=delete; | 
| Chris@738 | 104 }; | 
| Chris@738 | 105 | 
| Chris@738 | 106 #endif | 
| Chris@738 | 107 | 
| Chris@738 | 108 |