annotate audioio/PhaseVocoderTimeStretcher.h @ 25:e74f508db18c

* Add setRatio method to the time stretcher, and make it possible to change the ratio without having to construct and replace the time stretcher. This means we can do it seamlessly. Add a lot more ratios to the time stretch control in the main window
author Chris Cannam
date Fri, 15 Sep 2006 15:35:06 +0000
parents a2ad974b0c8c
children d88d117e0c34
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@15 122 * Get the latency added by the time stretcher, in sample frames.
Chris@23 123 * This will be exact if transient sharpening is off, or approximate
Chris@23 124 * if it is on.
Chris@15 125 */
Chris@0 126 size_t getProcessingLatency() const;
Chris@0 127
Chris@0 128 protected:
Chris@13 129 /**
Chris@23 130 * Process a single phase vocoder frame from "in" into
Chris@23 131 * m_freq[channel].
Chris@13 132 */
Chris@23 133 void analyseBlock(size_t channel, float *in); // into m_freq[channel]
Chris@20 134
Chris@23 135 /**
Chris@23 136 * Examine m_freq[0..m_channels-1] and return whether a percussive
Chris@23 137 * transient is found.
Chris@23 138 */
Chris@23 139 bool isTransient();
Chris@20 140
Chris@23 141 /**
Chris@23 142 * Resynthesise from m_freq[channel] adding in to "out",
Chris@23 143 * adjusting phases on the basis of a prior step size of lastStep.
Chris@23 144 * Also add the window shape in to the modulation array (if
Chris@23 145 * present) -- for use in ensuring the output has the correct
Chris@23 146 * magnitude afterwards.
Chris@23 147 */
Chris@20 148 void synthesiseBlock(size_t channel, float *out, float *modulation,
Chris@20 149 size_t lastStep);
Chris@0 150
Chris@25 151 void initialise();
Chris@25 152 void calculateParameters();
Chris@25 153 void cleanup();
Chris@25 154
Chris@22 155 size_t m_sampleRate;
Chris@16 156 size_t m_channels;
Chris@25 157 size_t m_maxProcessInputBlockSize;
Chris@12 158 float m_ratio;
Chris@16 159 bool m_sharpen;
Chris@0 160 size_t m_n1;
Chris@0 161 size_t m_n2;
Chris@0 162 size_t m_wlen;
Chris@20 163 Window<float> *m_analysisWindow;
Chris@20 164 Window<float> *m_synthesisWindow;
Chris@0 165
Chris@21 166 int m_totalCount;
Chris@21 167 int m_transientCount;
Chris@21 168 int m_n2sum;
Chris@21 169
Chris@16 170 float **m_prevPhase;
Chris@16 171 float **m_prevAdjustedPhase;
Chris@16 172
Chris@20 173 float *m_prevTransientMag;
Chris@21 174 int m_prevTransientScore;
Chris@22 175 int m_transientThreshold;
Chris@20 176 bool m_prevTransient;
Chris@20 177
Chris@20 178 float *m_tempbuf;
Chris@20 179 float **m_time;
Chris@20 180 fftwf_complex **m_freq;
Chris@20 181 fftwf_plan *m_plan;
Chris@20 182 fftwf_plan *m_iplan;
Chris@0 183
Chris@16 184 RingBuffer<float> **m_inbuf;
Chris@16 185 RingBuffer<float> **m_outbuf;
Chris@16 186 float **m_mashbuf;
Chris@13 187 float *m_modulationbuf;
Chris@25 188
Chris@25 189 QMutex *m_mutex;
Chris@0 190 };
Chris@0 191
Chris@0 192 #endif