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