annotate audioio/PhaseVocoderTimeStretcher.h @ 26:d88d117e0c34

* Add mono timestretch toggle button; some more work on getting blocksize etc parameters through to plugins
author Chris Cannam
date Mon, 18 Sep 2006 16:43:17 +0000
parents e74f508db18c
children 37af203dbd15
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Sonic Visualiser
Chris@0 5 An audio file viewer and annotation editor.
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@0 7 This file copyright 2006 Chris Cannam.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@14 16 #ifndef _PHASE_VOCODER_TIME_STRETCHER_H_
Chris@14 17 #define _PHASE_VOCODER_TIME_STRETCHER_H_
Chris@0 18
Chris@0 19 #include "base/Window.h"
Chris@0 20 #include "base/RingBuffer.h"
Chris@0 21
Chris@0 22 #include <fftw3.h>
Chris@0 23
Chris@25 24 #include <QMutex>
Chris@25 25
Chris@0 26 /**
Chris@14 27 * A time stretcher that alters the performance speed of audio,
Chris@22 28 * preserving pitch.
Chris@0 29 *
Chris@22 30 * This is based on the straightforward phase vocoder with phase
Chris@22 31 * unwrapping (as in e.g. the DAFX book pp275-), with optional
Chris@22 32 * percussive transient detection to avoid smearing percussive notes
Chris@22 33 * and resynchronise phases, and adding a stream API for real-time
Chris@22 34 * use. Principles and methods from Chris Duxbury, AES 2002 and 2004
Chris@22 35 * thesis; Emmanuel Ravelli, DAFX 2005; Dan Barry, ISSC 2005 on
Chris@22 36 * percussion detection; code by Chris Cannam.
Chris@0 37 */
Chris@0 38
Chris@14 39 class PhaseVocoderTimeStretcher
Chris@0 40 {
Chris@0 41 public:
Chris@22 42 PhaseVocoderTimeStretcher(size_t sampleRate,
Chris@22 43 size_t channels,
Chris@16 44 float ratio,
Chris@16 45 bool sharpen,
Chris@16 46 size_t maxProcessInputBlockSize);
Chris@14 47 virtual ~PhaseVocoderTimeStretcher();
Chris@0 48
Chris@12 49 /**
Chris@12 50 * Process a block. The input array contains the given number of
Chris@16 51 * samples (on each channel); the output must have space for
Chris@16 52 * lrintf(samples * m_ratio).
Chris@16 53 *
Chris@23 54 * This function isn't really recommended, and I may yet remove it.
Chris@23 55 * It should work correctly for some ratios, e.g. small powers of
Chris@23 56 * two, if transient sharpening is off. For other ratios it may
Chris@23 57 * drop samples -- use putInput in a loop followed by getOutput
Chris@23 58 * (when getAvailableOutputSamples reports enough) instead.
Chris@16 59 *
Chris@16 60 * Do not mix process calls with putInput/getOutput calls.
Chris@12 61 */
Chris@16 62 void process(float **input, float **output, size_t samples);
Chris@16 63
Chris@16 64 /**
Chris@16 65 * Return the number of samples that would need to be added via
Chris@16 66 * putInput in order to provoke the time stretcher into doing some
Chris@16 67 * time stretching and making more output samples available.
Chris@23 68 * This will be an estimate, if transient sharpening is on.
Chris@16 69 */
Chris@16 70 size_t getRequiredInputSamples() const;
Chris@16 71
Chris@16 72 /**
Chris@16 73 * Put (and possibly process) a given number of input samples.
Chris@16 74 * Number must not exceed the maxProcessInputBlockSize passed to
Chris@16 75 * constructor.
Chris@16 76 */
Chris@16 77 void putInput(float **input, size_t samples);
Chris@16 78
Chris@23 79 /**
Chris@23 80 * Get the number of processed samples ready for reading.
Chris@23 81 */
Chris@16 82 size_t getAvailableOutputSamples() const;
Chris@16 83
Chris@23 84 /**
Chris@23 85 * Get some processed samples.
Chris@23 86 */
Chris@16 87 void getOutput(float **output, size_t samples);
Chris@16 88
Chris@16 89 //!!! and reset?
Chris@0 90
Chris@0 91 /**
Chris@25 92 * Change the time stretch ratio.
Chris@25 93 */
Chris@25 94 void setRatio(float ratio);
Chris@25 95
Chris@25 96 /**
Chris@15 97 * Get the hop size for input.
Chris@0 98 */
Chris@0 99 size_t getInputIncrement() const { return m_n1; }
Chris@0 100
Chris@0 101 /**
Chris@15 102 * Get the hop size for output.
Chris@15 103 */
Chris@16 104 size_t getOutputIncrement() const { return m_n2; }
Chris@15 105
Chris@15 106 /**
Chris@15 107 * Get the window size for FFT processing.
Chris@0 108 */
Chris@0 109 size_t getWindowSize() const { return m_wlen; }
Chris@0 110
Chris@0 111 /**
Chris@16 112 * Get the stretch ratio.
Chris@15 113 */
Chris@16 114 float getRatio() const { return float(m_n2) / float(m_n1); }
Chris@16 115
Chris@16 116 /**
Chris@16 117 * Return whether this time stretcher will attempt to sharpen transients.
Chris@16 118 */
Chris@16 119 bool getSharpening() const { return m_sharpen; }
Chris@15 120
Chris@15 121 /**
Chris@26 122 * Return the number of channels for this time stretcher.
Chris@26 123 */
Chris@26 124 size_t getChannelCount() const { return m_channels; }
Chris@26 125
Chris@26 126 /**
Chris@15 127 * Get the latency added by the time stretcher, in sample frames.
Chris@23 128 * This will be exact if transient sharpening is off, or approximate
Chris@23 129 * if it is on.
Chris@15 130 */
Chris@0 131 size_t getProcessingLatency() const;
Chris@0 132
Chris@0 133 protected:
Chris@13 134 /**
Chris@23 135 * Process a single phase vocoder frame from "in" into
Chris@23 136 * m_freq[channel].
Chris@13 137 */
Chris@23 138 void analyseBlock(size_t channel, float *in); // into m_freq[channel]
Chris@20 139
Chris@23 140 /**
Chris@23 141 * Examine m_freq[0..m_channels-1] and return whether a percussive
Chris@23 142 * transient is found.
Chris@23 143 */
Chris@23 144 bool isTransient();
Chris@20 145
Chris@23 146 /**
Chris@23 147 * Resynthesise from m_freq[channel] adding in to "out",
Chris@23 148 * adjusting phases on the basis of a prior step size of lastStep.
Chris@23 149 * Also add the window shape in to the modulation array (if
Chris@23 150 * present) -- for use in ensuring the output has the correct
Chris@23 151 * magnitude afterwards.
Chris@23 152 */
Chris@20 153 void synthesiseBlock(size_t channel, float *out, float *modulation,
Chris@20 154 size_t lastStep);
Chris@0 155
Chris@25 156 void initialise();
Chris@25 157 void calculateParameters();
Chris@25 158 void cleanup();
Chris@25 159
Chris@22 160 size_t m_sampleRate;
Chris@16 161 size_t m_channels;
Chris@25 162 size_t m_maxProcessInputBlockSize;
Chris@12 163 float m_ratio;
Chris@16 164 bool m_sharpen;
Chris@0 165 size_t m_n1;
Chris@0 166 size_t m_n2;
Chris@0 167 size_t m_wlen;
Chris@20 168 Window<float> *m_analysisWindow;
Chris@20 169 Window<float> *m_synthesisWindow;
Chris@0 170
Chris@21 171 int m_totalCount;
Chris@21 172 int m_transientCount;
Chris@21 173 int m_n2sum;
Chris@21 174
Chris@16 175 float **m_prevPhase;
Chris@16 176 float **m_prevAdjustedPhase;
Chris@16 177
Chris@20 178 float *m_prevTransientMag;
Chris@21 179 int m_prevTransientScore;
Chris@22 180 int m_transientThreshold;
Chris@20 181 bool m_prevTransient;
Chris@20 182
Chris@20 183 float *m_tempbuf;
Chris@20 184 float **m_time;
Chris@20 185 fftwf_complex **m_freq;
Chris@20 186 fftwf_plan *m_plan;
Chris@20 187 fftwf_plan *m_iplan;
Chris@0 188
Chris@16 189 RingBuffer<float> **m_inbuf;
Chris@16 190 RingBuffer<float> **m_outbuf;
Chris@16 191 float **m_mashbuf;
Chris@13 192 float *m_modulationbuf;
Chris@25 193
Chris@25 194 QMutex *m_mutex;
Chris@0 195 };
Chris@0 196
Chris@0 197 #endif