Mercurial > hg > sonic-visualiser
diff audioio/PhaseVocoderTimeStretcher.h @ 16:3715efc38f95
* substantial enhancements to time stretcher:
-- use putInput/getOutput methods to ensure the audio source always feeds
it enough input, avoiding underruns due to rounding error
-- add a percussion detector and an optional "Sharpen" toggle to the main
window, which invokes a very basic variable speed timestretcher
author | Chris Cannam |
---|---|
date | Wed, 13 Sep 2006 17:17:42 +0000 |
parents | cc566264c935 |
children | 67d54627efd3 |
line wrap: on
line diff
--- a/audioio/PhaseVocoderTimeStretcher.h Wed Sep 13 11:56:44 2006 +0000 +++ b/audioio/PhaseVocoderTimeStretcher.h Wed Sep 13 17:17:42 2006 +0000 @@ -33,14 +33,45 @@ class PhaseVocoderTimeStretcher { public: - PhaseVocoderTimeStretcher(float ratio, size_t maxProcessInputBlockSize); + PhaseVocoderTimeStretcher(size_t channels, + float ratio, + bool sharpen, + size_t maxProcessInputBlockSize); virtual ~PhaseVocoderTimeStretcher(); /** * Process a block. The input array contains the given number of - * samples; the output must have space for lrintf(samples * m_ratio). + * samples (on each channel); the output must have space for + * lrintf(samples * m_ratio). + * + * This should work correctly for some ratios, e.g. small powers + * of two. For other ratios it may drop samples -- use putInput + * in a loop followed by getOutput (when getAvailableOutputSamples + * reports enough) instead. + * + * Do not mix process calls with putInput/getOutput calls. */ - void process(float *input, float *output, size_t samples); + void process(float **input, float **output, size_t samples); + + /** + * Return the number of samples that would need to be added via + * putInput in order to provoke the time stretcher into doing some + * time stretching and making more output samples available. + */ + size_t getRequiredInputSamples() const; + + /** + * Put (and possibly process) a given number of input samples. + * Number must not exceed the maxProcessInputBlockSize passed to + * constructor. + */ + void putInput(float **input, size_t samples); + + size_t getAvailableOutputSamples() const; + + void getOutput(float **output, size_t samples); + + //!!! and reset? /** * Get the hop size for input. @@ -50,7 +81,7 @@ /** * Get the hop size for output. */ - size_t getOutputIncrement() const { return getInputIncrement() * getRatio(); } + size_t getOutputIncrement() const { return m_n2; } /** * Get the window size for FFT processing. @@ -63,9 +94,14 @@ WindowType getWindowType() const { return m_window->getType(); } /** - * Get the stretch ratio set in the constructor. + * Get the stretch ratio. */ - float getRatio() const { return m_ratio; } + float getRatio() const { return float(m_n2) / float(m_n1); } + + /** + * Return whether this time stretcher will attempt to sharpen transients. + */ + bool getSharpening() const { return m_sharpen; } /** * Get the latency added by the time stretcher, in sample frames. @@ -86,26 +122,33 @@ * the window overlap varies or otherwise results in something * other than a flat sum. */ - void processBlock(float *in, float *out, float *modulation); + bool processBlock(size_t channel, + float *in, float *out, + float *modulation, + bool knownPercussive); + size_t m_channels; float m_ratio; + bool m_sharpen; size_t m_n1; size_t m_n2; size_t m_wlen; Window<float> *m_window; + float **m_prevPhase; + float **m_prevAdjustedPhase; + float **m_prevMag; + int *m_prevPercussiveCount; + + float *m_dbuf; fftwf_complex *m_time; fftwf_complex *m_freq; - float *m_dbuf; - float *m_prevPhase; - float *m_prevAdjustedPhase; - fftwf_plan m_plan; fftwf_plan m_iplan; - RingBuffer<float> *m_inbuf; - RingBuffer<float> *m_outbuf; - float *m_mashbuf; + RingBuffer<float> **m_inbuf; + RingBuffer<float> **m_outbuf; + float **m_mashbuf; float *m_modulationbuf; };