1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 /*
19     This file is derived from
20 
21     Sonic Visualiser
22     An audio file viewer and annotation editor.
23     Centre for Digital Music, Queen Mary, University of London.
24     This file copyright 2006 Chris Cannam and QMUL.
25 
26     This program is free software; you can redistribute it and/or
27     modify it under the terms of the GNU General Public License as
28     published by the Free Software Foundation; either version 2 of the
29     License, or (at your option) any later version.  See the file
30     COPYING included with this distribution for more information.
31 */
32 
33 #ifndef RG_AUDIO_TIME_STRETCHER_H
34 #define RG_AUDIO_TIME_STRETCHER_H
35 
36 #include "SampleWindow.h"
37 #include "RingBuffer.h"
38 
39 #include <fftw3.h>
40 #include <pthread.h>
41 #include <list>
42 
43 namespace Rosegarden
44 {
45 
46 /**
47  * A time stretcher that alters the performance speed of audio,
48  * preserving pitch.
49  *
50  * This is based on the straightforward phase vocoder with phase
51  * unwrapping (as in e.g. the DAFX book pp275-), with optional
52  * percussive transient detection to avoid smearing percussive notes
53  * and resynchronise phases, and adding a stream API for real-time
54  * use.  Principles and methods from Chris Duxbury, AES 2002 and 2004
55  * thesis; Emmanuel Ravelli, DAFX 2005; Dan Barry, ISSC 2005 on
56  * percussion detection; code by Chris Cannam.
57  */
58 
59 class AudioTimeStretcher
60 {
61 public:
62     AudioTimeStretcher(size_t sampleRate,
63                        size_t channels,
64                        float ratio,
65                        bool sharpen,
66                        size_t maxOutputBlockSize);
67     virtual ~AudioTimeStretcher();
68 
69     /**
70      * Return the number of samples that would need to be added via
71      * putInput in order to provoke the time stretcher into doing some
72      * time stretching and making more output samples available.
73      * This will be an estimate, if transient sharpening is on; the
74      * caller may need to do the put/get/test cycle more than once.
75      */
76     size_t getRequiredInputSamples() const;
77 
78     /**
79      * Put (and possibly process) a given number of input samples.
80      * Number should usually equal the value returned from
81      * getRequiredInputSamples().
82      */
83     void putInput(float **input, size_t samples);
84 
85     /**
86      * Get the number of processed samples ready for reading.
87      */
88     size_t getAvailableOutputSamples() const;
89 
90     /**
91      * Get some processed samples.
92      */
93     void getOutput(float **output, size_t samples);
94 
95     //!!! and reset?
96 
97     /**
98      * Change the time stretch ratio.
99      */
100     void setRatio(float ratio);
101 
102     /**
103      * Get the hop size for input.
104      */
getInputIncrement()105     size_t getInputIncrement() const { return m_n1; }
106 
107     /**
108      * Get the hop size for output.
109      */
getOutputIncrement()110     size_t getOutputIncrement() const { return m_n2; }
111 
112     /**
113      * Get the window size for FFT processing.
114      */
getWindowSize()115     size_t getWindowSize() const { return m_wlen; }
116 
117     /**
118      * Get the stretch ratio.
119      */
getRatio()120     float getRatio() const { return float(m_n2) / float(m_n1); }
121 
122     /**
123      * Return whether this time stretcher will attempt to sharpen transients.
124      */
getSharpening()125     bool getSharpening() const { return m_sharpen; }
126 
127     /**
128      * Return the number of channels for this time stretcher.
129      */
getChannelCount()130     size_t getChannelCount() const { return m_channels; }
131 
132     /**
133      * Get the latency added by the time stretcher, in sample frames.
134      * This will be exact if transient sharpening is off, or approximate
135      * if it is on.
136      */
137     size_t getProcessingLatency() const;
138 
139 protected:
140     /**
141      * Process a single phase vocoder frame from "in" into
142      * m_freq[channel].
143      */
144     void analyseBlock(size_t channel, float *in); // into m_freq[channel]
145 
146     /**
147      * Examine m_freq[0..m_channels-1] and return whether a percussive
148      * transient is found.
149      */
150     bool isTransient();
151 
152     /**
153      * Resynthesise from m_freq[channel] adding in to "out",
154      * adjusting phases on the basis of a prior step size of lastStep.
155      * Also add the window shape in to the modulation array (if
156      * present) -- for use in ensuring the output has the correct
157      * magnitude afterwards.
158      */
159     void synthesiseBlock(size_t channel, float *out, float *modulation,
160                          size_t lastStep);
161 
162     void initialise();
163     void calculateParameters();
164     void cleanup();
165 
shouldSharpen()166     bool shouldSharpen() {
167         return m_sharpen && (m_ratio > 0.25);
168     }
169 
170     size_t m_sampleRate;
171     size_t m_channels;
172     size_t m_maxOutputBlockSize;
173     float m_ratio;
174     bool m_sharpen;
175     size_t m_n1;
176     size_t m_n2;
177     size_t m_wlen;
178     SampleWindow<float> *m_analysisWindow;
179     SampleWindow<float> *m_synthesisWindow;
180 
181     int m_totalCount;
182     int m_transientCount;
183 
184     int m_n2sum;
185     int m_n2total;
186     std::list<int> m_n2list;
187     int m_adjustCount;
188 
189     float **m_prevPhase;
190     float **m_prevAdjustedPhase;
191 
192     float *m_prevTransientMag;
193     int  m_prevTransientScore;
194     int  m_transientThreshold;
195     bool m_prevTransient;
196 
197     float *m_tempbuf;
198     float **m_time;
199     fftwf_complex **m_freq;
200     fftwf_plan *m_plan;
201     fftwf_plan *m_iplan;
202 
203     RingBuffer<float> **m_inbuf;
204     RingBuffer<float> **m_outbuf;
205     float **m_mashbuf;
206     float *m_modulationbuf;
207 
208     mutable pthread_mutex_t m_mutex;
209 };
210 
211 }
212 
213 
214 #endif
215