annotate sv/audioio/PhaseVocoderTimeStretcher.cpp @ 282:d9319859a4cf tip

(none)
author benoitrigolleau
date Fri, 31 Oct 2008 11:00:24 +0000
parents 61681a2bc1e6
children
rev   line source
lbajardsilogic@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
lbajardsilogic@0 2
lbajardsilogic@0 3 /*
lbajardsilogic@0 4 Sonic Visualiser
lbajardsilogic@0 5 An audio file viewer and annotation editor.
lbajardsilogic@0 6 Centre for Digital Music, Queen Mary, University of London.
lbajardsilogic@0 7 This file copyright 2006 Chris Cannam and QMUL.
lbajardsilogic@0 8
lbajardsilogic@0 9 This program is free software; you can redistribute it and/or
lbajardsilogic@0 10 modify it under the terms of the GNU General Public License as
lbajardsilogic@0 11 published by the Free Software Foundation; either version 2 of the
lbajardsilogic@0 12 License, or (at your option) any later version. See the file
lbajardsilogic@0 13 COPYING included with this distribution for more information.
lbajardsilogic@0 14 */
lbajardsilogic@0 15
lbajardsilogic@0 16 #include "PhaseVocoderTimeStretcher.h"
lbajardsilogic@0 17
lbajardsilogic@0 18 #include <iostream>
lbajardsilogic@0 19 #include <cassert>
lbajardsilogic@0 20
lbajardsilogic@0 21 #include <QMutexLocker>
lbajardsilogic@0 22
lbajardsilogic@0 23 //#define DEBUG_PHASE_VOCODER_TIME_STRETCHER 1
lbajardsilogic@0 24
lbajardsilogic@0 25 PhaseVocoderTimeStretcher::PhaseVocoderTimeStretcher(size_t sampleRate,
lbajardsilogic@0 26 size_t channels,
lbajardsilogic@0 27 float ratio,
lbajardsilogic@0 28 bool sharpen,
lbajardsilogic@0 29 size_t maxOutputBlockSize) :
lbajardsilogic@0 30 m_sampleRate(sampleRate),
lbajardsilogic@0 31 m_channels(channels),
lbajardsilogic@0 32 m_maxOutputBlockSize(maxOutputBlockSize),
lbajardsilogic@0 33 m_ratio(ratio),
lbajardsilogic@0 34 m_sharpen(sharpen),
lbajardsilogic@0 35 m_totalCount(0),
lbajardsilogic@0 36 m_transientCount(0),
lbajardsilogic@0 37 m_n2sum(0),
lbajardsilogic@0 38 m_mutex(new QMutex())
lbajardsilogic@0 39 {
lbajardsilogic@0 40 initialise();
lbajardsilogic@0 41 }
lbajardsilogic@0 42
lbajardsilogic@0 43 PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher()
lbajardsilogic@0 44 {
lbajardsilogic@0 45 std::cerr << "PhaseVocoderTimeStretcher::~PhaseVocoderTimeStretcher" << std::endl;
lbajardsilogic@0 46
lbajardsilogic@0 47 cleanup();
lbajardsilogic@0 48
lbajardsilogic@0 49 delete m_mutex;
lbajardsilogic@0 50 }
lbajardsilogic@0 51
lbajardsilogic@0 52 void
lbajardsilogic@0 53 PhaseVocoderTimeStretcher::initialise()
lbajardsilogic@0 54 {
lbajardsilogic@0 55 std::cerr << "PhaseVocoderTimeStretcher::initialise" << std::endl;
lbajardsilogic@0 56
lbajardsilogic@0 57 calculateParameters();
lbajardsilogic@0 58
lbajardsilogic@0 59 m_analysisWindow = new Window<float>(HanningWindow, m_wlen);
lbajardsilogic@0 60 m_synthesisWindow = new Window<float>(HanningWindow, m_wlen);
lbajardsilogic@0 61
lbajardsilogic@0 62 m_prevPhase = new float *[m_channels];
lbajardsilogic@0 63 m_prevAdjustedPhase = new float *[m_channels];
lbajardsilogic@0 64
lbajardsilogic@0 65 m_prevTransientMag = (float *)fftf_malloc(sizeof(float) * (m_wlen / 2 + 1));
lbajardsilogic@0 66 m_prevTransientScore = 0;
lbajardsilogic@0 67 m_prevTransient = false;
lbajardsilogic@0 68
lbajardsilogic@0 69 m_tempbuf = (float *)fftf_malloc(sizeof(float) * m_wlen);
lbajardsilogic@0 70
lbajardsilogic@0 71 m_time = new float *[m_channels];
lbajardsilogic@0 72 m_freq = new fftf_complex *[m_channels];
lbajardsilogic@0 73 m_plan = new fftf_plan[m_channels];
lbajardsilogic@0 74 m_iplan = new fftf_plan[m_channels];
lbajardsilogic@0 75
lbajardsilogic@0 76 m_inbuf = new RingBuffer<float> *[m_channels];
lbajardsilogic@0 77 m_outbuf = new RingBuffer<float> *[m_channels];
lbajardsilogic@0 78 m_mashbuf = new float *[m_channels];
lbajardsilogic@0 79
lbajardsilogic@0 80 m_modulationbuf = (float *)fftf_malloc(sizeof(float) * m_wlen);
lbajardsilogic@0 81
lbajardsilogic@0 82 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 83
lbajardsilogic@0 84 m_prevPhase[c] = (float *)fftf_malloc(sizeof(float) * (m_wlen / 2 + 1));
lbajardsilogic@0 85 m_prevAdjustedPhase[c] = (float *)fftf_malloc(sizeof(float) * (m_wlen / 2 + 1));
lbajardsilogic@0 86
lbajardsilogic@0 87 m_time[c] = (float *)fftf_malloc(sizeof(float) * m_wlen);
lbajardsilogic@0 88 m_freq[c] = (fftf_complex *)fftf_malloc(sizeof(fftf_complex) *
lbajardsilogic@0 89 (m_wlen / 2 + 1));
lbajardsilogic@0 90
lbajardsilogic@0 91 m_plan[c] = fftf_plan_dft_r2c_1d(m_wlen, m_time[c], m_freq[c], FFTW_ESTIMATE);
lbajardsilogic@0 92 m_iplan[c] = fftf_plan_dft_c2r_1d(m_wlen, m_freq[c], m_time[c], FFTW_ESTIMATE);
lbajardsilogic@0 93
lbajardsilogic@0 94 m_outbuf[c] = new RingBuffer<float>
lbajardsilogic@0 95 ((m_maxOutputBlockSize + m_wlen) * 2);
lbajardsilogic@0 96 m_inbuf[c] = new RingBuffer<float>
lbajardsilogic@0 97 (lrintf(m_outbuf[c]->getSize() / m_ratio) + m_wlen);
lbajardsilogic@0 98
lbajardsilogic@0 99 std::cerr << "making inbuf size " << m_inbuf[c]->getSize() << " (outbuf size is " << m_outbuf[c]->getSize() << ", ratio " << m_ratio << ")" << std::endl;
lbajardsilogic@0 100
lbajardsilogic@0 101
lbajardsilogic@0 102 m_mashbuf[c] = (float *)fftf_malloc(sizeof(float) * m_wlen);
lbajardsilogic@0 103
lbajardsilogic@0 104 for (size_t i = 0; i < m_wlen; ++i) {
lbajardsilogic@0 105 m_mashbuf[c][i] = 0.0;
lbajardsilogic@0 106 }
lbajardsilogic@0 107
lbajardsilogic@0 108 for (size_t i = 0; i <= m_wlen/2; ++i) {
lbajardsilogic@0 109 m_prevPhase[c][i] = 0.0;
lbajardsilogic@0 110 m_prevAdjustedPhase[c][i] = 0.0;
lbajardsilogic@0 111 }
lbajardsilogic@0 112 }
lbajardsilogic@0 113
lbajardsilogic@0 114 for (size_t i = 0; i < m_wlen; ++i) {
lbajardsilogic@0 115 m_modulationbuf[i] = 0.0;
lbajardsilogic@0 116 }
lbajardsilogic@0 117
lbajardsilogic@0 118 for (size_t i = 0; i <= m_wlen/2; ++i) {
lbajardsilogic@0 119 m_prevTransientMag[i] = 0.0;
lbajardsilogic@0 120 }
lbajardsilogic@0 121 }
lbajardsilogic@0 122
lbajardsilogic@0 123 void
lbajardsilogic@0 124 PhaseVocoderTimeStretcher::calculateParameters()
lbajardsilogic@0 125 {
lbajardsilogic@0 126 std::cerr << "PhaseVocoderTimeStretcher::calculateParameters" << std::endl;
lbajardsilogic@0 127
lbajardsilogic@0 128 m_wlen = 1024;
lbajardsilogic@0 129
lbajardsilogic@0 130 //!!! In transient sharpening mode, we need to pick the window
lbajardsilogic@0 131 //length so as to be more or less fixed in audio duration (i.e. we
lbajardsilogic@0 132 //need to exploit the sample rate)
lbajardsilogic@0 133
lbajardsilogic@0 134 //!!! have to work out the relationship between wlen and transient
lbajardsilogic@0 135 //threshold
lbajardsilogic@0 136
lbajardsilogic@0 137 if (m_ratio < 1) {
lbajardsilogic@0 138 if (m_ratio < 0.4) {
lbajardsilogic@0 139 m_n1 = 1024;
lbajardsilogic@0 140 m_wlen = 2048;
lbajardsilogic@0 141 } else if (m_ratio < 0.8) {
lbajardsilogic@0 142 m_n1 = 512;
lbajardsilogic@0 143 } else {
lbajardsilogic@0 144 m_n1 = 256;
lbajardsilogic@0 145 }
lbajardsilogic@0 146 if (shouldSharpen()) {
lbajardsilogic@0 147 m_wlen = 2048;
lbajardsilogic@0 148 }
lbajardsilogic@0 149 m_n2 = lrintf(m_n1 * m_ratio);
lbajardsilogic@0 150 } else {
lbajardsilogic@0 151 if (m_ratio > 2) {
lbajardsilogic@0 152 m_n2 = 512;
lbajardsilogic@0 153 m_wlen = 4096;
lbajardsilogic@0 154 } else if (m_ratio > 1.6) {
lbajardsilogic@0 155 m_n2 = 384;
lbajardsilogic@0 156 m_wlen = 2048;
lbajardsilogic@0 157 } else {
lbajardsilogic@0 158 m_n2 = 256;
lbajardsilogic@0 159 }
lbajardsilogic@0 160 if (shouldSharpen()) {
lbajardsilogic@0 161 if (m_wlen < 2048) m_wlen = 2048;
lbajardsilogic@0 162 }
lbajardsilogic@0 163 m_n1 = lrintf(m_n2 / m_ratio);
lbajardsilogic@0 164 if (m_n1 == 0) {
lbajardsilogic@0 165 m_n1 = 1;
lbajardsilogic@0 166 m_n2 = lrintf(m_ratio);
lbajardsilogic@0 167 }
lbajardsilogic@0 168 }
lbajardsilogic@0 169
lbajardsilogic@0 170 m_transientThreshold = lrintf(m_wlen / 4.5);
lbajardsilogic@0 171
lbajardsilogic@0 172 m_totalCount = 0;
lbajardsilogic@0 173 m_transientCount = 0;
lbajardsilogic@0 174 m_n2sum = 0;
lbajardsilogic@0 175
lbajardsilogic@0 176
lbajardsilogic@0 177 std::cerr << "PhaseVocoderTimeStretcher: channels = " << m_channels
lbajardsilogic@0 178 << ", ratio = " << m_ratio
lbajardsilogic@0 179 << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = "
lbajardsilogic@0 180 << m_wlen << ", max = " << m_maxOutputBlockSize << std::endl;
lbajardsilogic@0 181 // << ", outbuflen = " << m_outbuf[0]->getSize() << std::endl;
lbajardsilogic@0 182 }
lbajardsilogic@0 183
lbajardsilogic@0 184 void
lbajardsilogic@0 185 PhaseVocoderTimeStretcher::cleanup()
lbajardsilogic@0 186 {
lbajardsilogic@0 187 std::cerr << "PhaseVocoderTimeStretcher::cleanup" << std::endl;
lbajardsilogic@0 188
lbajardsilogic@0 189 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 190
lbajardsilogic@0 191 fftf_destroy_plan(m_plan[c]);
lbajardsilogic@0 192 fftf_destroy_plan(m_iplan[c]);
lbajardsilogic@0 193
lbajardsilogic@0 194 fftf_free(m_time[c]);
lbajardsilogic@0 195 fftf_free(m_freq[c]);
lbajardsilogic@0 196
lbajardsilogic@0 197 fftf_free(m_mashbuf[c]);
lbajardsilogic@0 198 fftf_free(m_prevPhase[c]);
lbajardsilogic@0 199 fftf_free(m_prevAdjustedPhase[c]);
lbajardsilogic@0 200
lbajardsilogic@0 201 delete m_inbuf[c];
lbajardsilogic@0 202 delete m_outbuf[c];
lbajardsilogic@0 203 }
lbajardsilogic@0 204
lbajardsilogic@0 205 fftf_free(m_tempbuf);
lbajardsilogic@0 206 fftf_free(m_modulationbuf);
lbajardsilogic@0 207 fftf_free(m_prevTransientMag);
lbajardsilogic@0 208
lbajardsilogic@0 209 delete[] m_prevPhase;
lbajardsilogic@0 210 delete[] m_prevAdjustedPhase;
lbajardsilogic@0 211 delete[] m_inbuf;
lbajardsilogic@0 212 delete[] m_outbuf;
lbajardsilogic@0 213 delete[] m_mashbuf;
lbajardsilogic@0 214 delete[] m_time;
lbajardsilogic@0 215 delete[] m_freq;
lbajardsilogic@0 216 delete[] m_plan;
lbajardsilogic@0 217 delete[] m_iplan;
lbajardsilogic@0 218
lbajardsilogic@0 219 delete m_analysisWindow;
lbajardsilogic@0 220 delete m_synthesisWindow;
lbajardsilogic@0 221 }
lbajardsilogic@0 222
lbajardsilogic@0 223 void
lbajardsilogic@0 224 PhaseVocoderTimeStretcher::setRatio(float ratio)
lbajardsilogic@0 225 {
lbajardsilogic@0 226 QMutexLocker locker(m_mutex);
lbajardsilogic@0 227
lbajardsilogic@0 228 size_t formerWlen = m_wlen;
lbajardsilogic@0 229 m_ratio = ratio;
lbajardsilogic@0 230
lbajardsilogic@0 231 std::cerr << "PhaseVocoderTimeStretcher::setRatio: new ratio " << ratio
lbajardsilogic@0 232 << std::endl;
lbajardsilogic@0 233
lbajardsilogic@0 234 calculateParameters();
lbajardsilogic@0 235
lbajardsilogic@0 236 if (m_wlen == formerWlen) {
lbajardsilogic@0 237
lbajardsilogic@0 238 // This is the only container whose size depends on m_ratio
lbajardsilogic@0 239
lbajardsilogic@0 240 RingBuffer<float> **newin = new RingBuffer<float> *[m_channels];
lbajardsilogic@0 241
lbajardsilogic@0 242 size_t formerSize = m_inbuf[0]->getSize();
lbajardsilogic@0 243 size_t newSize = lrintf(m_outbuf[0]->getSize() / m_ratio) + m_wlen;
lbajardsilogic@0 244
lbajardsilogic@0 245 std::cerr << "resizing inbuf from " << formerSize << " to "
lbajardsilogic@0 246 << newSize << " (outbuf size is " << m_outbuf[0]->getSize() << ", ratio " << m_ratio << ")" << std::endl;
lbajardsilogic@0 247
lbajardsilogic@0 248 if (formerSize != newSize) {
lbajardsilogic@0 249
lbajardsilogic@0 250 size_t ready = m_inbuf[0]->getReadSpace();
lbajardsilogic@0 251
lbajardsilogic@0 252 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 253 newin[c] = new RingBuffer<float>(newSize);
lbajardsilogic@0 254 }
lbajardsilogic@0 255
lbajardsilogic@0 256 if (ready > 0) {
lbajardsilogic@0 257
lbajardsilogic@190 258 size_t copy = MIN(ready, newSize);
lbajardsilogic@0 259 float *tmp = new float[ready];
lbajardsilogic@0 260
lbajardsilogic@0 261 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 262 m_inbuf[c]->read(tmp, ready);
lbajardsilogic@0 263 newin[c]->write(tmp + ready - copy, copy);
lbajardsilogic@0 264 }
lbajardsilogic@0 265
lbajardsilogic@0 266 delete[] tmp;
lbajardsilogic@0 267 }
lbajardsilogic@0 268
lbajardsilogic@0 269 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 270 delete m_inbuf[c];
lbajardsilogic@0 271 }
lbajardsilogic@0 272
lbajardsilogic@0 273 delete[] m_inbuf;
lbajardsilogic@0 274 m_inbuf = newin;
lbajardsilogic@0 275 }
lbajardsilogic@0 276
lbajardsilogic@0 277 } else {
lbajardsilogic@0 278
lbajardsilogic@0 279 std::cerr << "wlen changed" << std::endl;
lbajardsilogic@0 280 cleanup();
lbajardsilogic@0 281 initialise();
lbajardsilogic@0 282 }
lbajardsilogic@0 283 }
lbajardsilogic@0 284
lbajardsilogic@0 285 size_t
lbajardsilogic@0 286 PhaseVocoderTimeStretcher::getProcessingLatency() const
lbajardsilogic@0 287 {
lbajardsilogic@0 288 return getWindowSize() - getInputIncrement();
lbajardsilogic@0 289 }
lbajardsilogic@0 290
lbajardsilogic@0 291 size_t
lbajardsilogic@0 292 PhaseVocoderTimeStretcher::getRequiredInputSamples() const
lbajardsilogic@0 293 {
lbajardsilogic@0 294 QMutexLocker locker(m_mutex);
lbajardsilogic@0 295
lbajardsilogic@0 296 if (m_inbuf[0]->getReadSpace() >= m_wlen) return 0;
lbajardsilogic@0 297 return m_wlen - m_inbuf[0]->getReadSpace();
lbajardsilogic@0 298 }
lbajardsilogic@0 299
lbajardsilogic@0 300 void
lbajardsilogic@0 301 PhaseVocoderTimeStretcher::putInput(float **input, size_t samples)
lbajardsilogic@0 302 {
lbajardsilogic@0 303 QMutexLocker locker(m_mutex);
lbajardsilogic@0 304
lbajardsilogic@0 305 // We need to add samples from input to our internal buffer. When
lbajardsilogic@0 306 // we have m_windowSize samples in the buffer, we can process it,
lbajardsilogic@0 307 // move the samples back by m_n1 and write the output onto our
lbajardsilogic@0 308 // internal output buffer. If we have (samples * ratio) samples
lbajardsilogic@0 309 // in that, we can write m_n2 of them back to output and return
lbajardsilogic@0 310 // (otherwise we have to write zeroes).
lbajardsilogic@0 311
lbajardsilogic@0 312 // When we process, we write m_wlen to our fixed output buffer
lbajardsilogic@0 313 // (m_mashbuf). We then pull out the first m_n2 samples from that
lbajardsilogic@0 314 // buffer, push them into the output ring buffer, and shift
lbajardsilogic@0 315 // m_mashbuf left by that amount.
lbajardsilogic@0 316
lbajardsilogic@0 317 // The processing latency is then m_wlen - m_n2.
lbajardsilogic@0 318
lbajardsilogic@0 319 size_t consumed = 0;
lbajardsilogic@0 320
lbajardsilogic@0 321 while (consumed < samples) {
lbajardsilogic@0 322
lbajardsilogic@0 323 size_t writable = m_inbuf[0]->getWriteSpace();
lbajardsilogic@190 324 writable = MIN(writable, samples - consumed);
lbajardsilogic@0 325
lbajardsilogic@0 326 if (writable == 0) {
lbajardsilogic@0 327 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 328 std::cerr << "WARNING: PhaseVocoderTimeStretcher::putInput: writable == 0 (inbuf has " << m_inbuf[0]->getReadSpace() << " samples available for reading, space for " << m_inbuf[0]->getWriteSpace() << " more)" << std::endl;
lbajardsilogic@0 329 #endif
lbajardsilogic@0 330 if (m_inbuf[0]->getReadSpace() < m_wlen ||
lbajardsilogic@0 331 m_outbuf[0]->getWriteSpace() < m_n2) {
lbajardsilogic@0 332 std::cerr << "WARNING: PhaseVocoderTimeStretcher::putInput: Inbuf has " << m_inbuf[0]->getReadSpace() << ", outbuf has space for " << m_outbuf[0]->getWriteSpace() << " (n2 = " << m_n2 << ", wlen = " << m_wlen << "), won't be able to process" << std::endl;
lbajardsilogic@0 333 break;
lbajardsilogic@0 334 }
lbajardsilogic@0 335 } else {
lbajardsilogic@0 336
lbajardsilogic@0 337 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 338 std::cerr << "writing " << writable << " from index " << consumed << " to inbuf, consumed will be " << consumed + writable << std::endl;
lbajardsilogic@0 339 #endif
lbajardsilogic@0 340
lbajardsilogic@0 341 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 342 m_inbuf[c]->write(input[c] + consumed, writable);
lbajardsilogic@0 343 }
lbajardsilogic@0 344 consumed += writable;
lbajardsilogic@0 345 }
lbajardsilogic@0 346
lbajardsilogic@0 347 while (m_inbuf[0]->getReadSpace() >= m_wlen &&
lbajardsilogic@0 348 m_outbuf[0]->getWriteSpace() >= m_n2) {
lbajardsilogic@0 349
lbajardsilogic@0 350 // We know we have at least m_wlen samples available
lbajardsilogic@0 351 // in m_inbuf. We need to peek m_wlen of them for
lbajardsilogic@0 352 // processing, and then read m_n1 to advance the read
lbajardsilogic@0 353 // pointer.
lbajardsilogic@0 354
lbajardsilogic@0 355 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 356
lbajardsilogic@0 357 size_t got = m_inbuf[c]->peek(m_tempbuf, m_wlen);
lbajardsilogic@0 358 assert(got == m_wlen);
lbajardsilogic@0 359
lbajardsilogic@0 360 analyseBlock(c, m_tempbuf);
lbajardsilogic@0 361 }
lbajardsilogic@0 362
lbajardsilogic@0 363 bool transient = false;
lbajardsilogic@0 364 if (shouldSharpen()) transient = isTransient();
lbajardsilogic@0 365
lbajardsilogic@0 366 size_t n2 = m_n2;
lbajardsilogic@0 367
lbajardsilogic@0 368 if (transient) {
lbajardsilogic@0 369 n2 = m_n1;
lbajardsilogic@0 370 }
lbajardsilogic@0 371
lbajardsilogic@0 372 ++m_totalCount;
lbajardsilogic@0 373 if (transient) ++m_transientCount;
lbajardsilogic@0 374 m_n2sum += n2;
lbajardsilogic@0 375
lbajardsilogic@0 376 // std::cerr << "ratio for last 10: " <<last10num << "/" << (10 * m_n1) << " = " << float(last10num) / float(10 * m_n1) << " (should be " << m_ratio << ")" << std::endl;
lbajardsilogic@0 377
lbajardsilogic@0 378 if (m_totalCount > 50 && m_transientCount < m_totalCount) {
lbajardsilogic@0 379
lbajardsilogic@0 380 int fixed = lrintf(m_transientCount * m_n1);
lbajardsilogic@0 381
lbajardsilogic@0 382 int idealTotal = lrintf(m_totalCount * m_n1 * m_ratio);
lbajardsilogic@0 383 int idealSquashy = idealTotal - fixed;
lbajardsilogic@0 384
lbajardsilogic@0 385 int squashyCount = m_totalCount - m_transientCount;
lbajardsilogic@0 386
lbajardsilogic@0 387 n2 = lrintf(idealSquashy / squashyCount);
lbajardsilogic@0 388
lbajardsilogic@0 389 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 390 if (n2 != m_n2) {
lbajardsilogic@0 391 std::cerr << m_n2 << " -> " << n2 << std::endl;
lbajardsilogic@0 392 }
lbajardsilogic@0 393 #endif
lbajardsilogic@0 394 }
lbajardsilogic@0 395
lbajardsilogic@0 396 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 397
lbajardsilogic@0 398 synthesiseBlock(c, m_mashbuf[c],
lbajardsilogic@0 399 c == 0 ? m_modulationbuf : 0,
lbajardsilogic@0 400 m_prevTransient ? m_n1 : m_n2);
lbajardsilogic@0 401
lbajardsilogic@0 402
lbajardsilogic@0 403 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 404 std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl;
lbajardsilogic@0 405 #endif
lbajardsilogic@0 406 m_inbuf[c]->skip(m_n1);
lbajardsilogic@0 407
lbajardsilogic@0 408 for (size_t i = 0; i < n2; ++i) {
lbajardsilogic@0 409 if (m_modulationbuf[i] > 0.f) {
lbajardsilogic@0 410 m_mashbuf[c][i] /= m_modulationbuf[i];
lbajardsilogic@0 411 }
lbajardsilogic@0 412 }
lbajardsilogic@0 413
lbajardsilogic@0 414 m_outbuf[c]->write(m_mashbuf[c], n2);
lbajardsilogic@0 415
lbajardsilogic@0 416 for (size_t i = 0; i < m_wlen - n2; ++i) {
lbajardsilogic@0 417 m_mashbuf[c][i] = m_mashbuf[c][i + n2];
lbajardsilogic@0 418 }
lbajardsilogic@0 419
lbajardsilogic@0 420 for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
lbajardsilogic@0 421 m_mashbuf[c][i] = 0.0f;
lbajardsilogic@0 422 }
lbajardsilogic@0 423 }
lbajardsilogic@0 424
lbajardsilogic@0 425 m_prevTransient = transient;
lbajardsilogic@0 426
lbajardsilogic@0 427 for (size_t i = 0; i < m_wlen - n2; ++i) {
lbajardsilogic@0 428 m_modulationbuf[i] = m_modulationbuf[i + n2];
lbajardsilogic@0 429 }
lbajardsilogic@0 430
lbajardsilogic@0 431 for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
lbajardsilogic@0 432 m_modulationbuf[i] = 0.0f;
lbajardsilogic@0 433 }
lbajardsilogic@0 434
lbajardsilogic@0 435 if (!transient) m_n2 = n2;
lbajardsilogic@0 436 }
lbajardsilogic@0 437
lbajardsilogic@0 438
lbajardsilogic@0 439 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 440 std::cerr << "loop ended: inbuf read space " << m_inbuf[0]->getReadSpace() << ", outbuf write space " << m_outbuf[0]->getWriteSpace() << std::endl;
lbajardsilogic@0 441 #endif
lbajardsilogic@0 442 }
lbajardsilogic@0 443
lbajardsilogic@0 444 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 445 std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl;
lbajardsilogic@0 446 #endif
lbajardsilogic@0 447
lbajardsilogic@0 448 // std::cerr << "ratio: nominal: " << getRatio() << " actual: "
lbajardsilogic@0 449 // << m_total2 << "/" << m_total1 << " = " << float(m_total2) / float(m_total1) << " ideal: " << m_ratio << std::endl;
lbajardsilogic@0 450 }
lbajardsilogic@0 451
lbajardsilogic@0 452 size_t
lbajardsilogic@0 453 PhaseVocoderTimeStretcher::getAvailableOutputSamples() const
lbajardsilogic@0 454 {
lbajardsilogic@0 455 QMutexLocker locker(m_mutex);
lbajardsilogic@0 456
lbajardsilogic@0 457 return m_outbuf[0]->getReadSpace();
lbajardsilogic@0 458 }
lbajardsilogic@0 459
lbajardsilogic@0 460 void
lbajardsilogic@0 461 PhaseVocoderTimeStretcher::getOutput(float **output, size_t samples)
lbajardsilogic@0 462 {
lbajardsilogic@0 463 QMutexLocker locker(m_mutex);
lbajardsilogic@0 464
lbajardsilogic@0 465 if (m_outbuf[0]->getReadSpace() < samples) {
lbajardsilogic@0 466 std::cerr << "WARNING: PhaseVocoderTimeStretcher::getOutput: not enough data (yet?) (" << m_outbuf[0]->getReadSpace() << " < " << samples << ")" << std::endl;
lbajardsilogic@0 467 size_t fill = samples - m_outbuf[0]->getReadSpace();
lbajardsilogic@0 468 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 469 for (size_t i = 0; i < fill; ++i) {
lbajardsilogic@0 470 output[c][i] = 0.0;
lbajardsilogic@0 471 }
lbajardsilogic@0 472 m_outbuf[c]->read(output[c] + fill, m_outbuf[c]->getReadSpace());
lbajardsilogic@0 473 }
lbajardsilogic@0 474 } else {
lbajardsilogic@0 475 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 476 std::cerr << "enough data - writing " << samples << " from outbuf" << std::endl;
lbajardsilogic@0 477 #endif
lbajardsilogic@0 478 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 479 m_outbuf[c]->read(output[c], samples);
lbajardsilogic@0 480 }
lbajardsilogic@0 481 }
lbajardsilogic@0 482
lbajardsilogic@0 483 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 484 std::cerr << "PhaseVocoderTimeStretcher::getOutput returning" << std::endl;
lbajardsilogic@0 485 #endif
lbajardsilogic@0 486 }
lbajardsilogic@0 487
lbajardsilogic@0 488 void
lbajardsilogic@0 489 PhaseVocoderTimeStretcher::analyseBlock(size_t c, float *buf)
lbajardsilogic@0 490 {
lbajardsilogic@0 491 size_t i;
lbajardsilogic@0 492
lbajardsilogic@0 493 // buf contains m_wlen samples
lbajardsilogic@0 494
lbajardsilogic@0 495 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
lbajardsilogic@0 496 std::cerr << "PhaseVocoderTimeStretcher::analyseBlock (channel " << c << ")" << std::endl;
lbajardsilogic@0 497 #endif
lbajardsilogic@0 498
lbajardsilogic@0 499 m_analysisWindow->cut(buf);
lbajardsilogic@0 500
lbajardsilogic@0 501 for (i = 0; i < m_wlen/2; ++i) {
lbajardsilogic@0 502 float temp = buf[i];
lbajardsilogic@0 503 buf[i] = buf[i + m_wlen/2];
lbajardsilogic@0 504 buf[i + m_wlen/2] = temp;
lbajardsilogic@0 505 }
lbajardsilogic@0 506
lbajardsilogic@0 507 for (i = 0; i < m_wlen; ++i) {
lbajardsilogic@0 508 m_time[c][i] = buf[i];
lbajardsilogic@0 509 }
lbajardsilogic@0 510
lbajardsilogic@0 511 fftf_execute(m_plan[c]); // m_time -> m_freq
lbajardsilogic@0 512 }
lbajardsilogic@0 513
lbajardsilogic@0 514 bool
lbajardsilogic@0 515 PhaseVocoderTimeStretcher::isTransient()
lbajardsilogic@0 516 {
lbajardsilogic@0 517 int count = 0;
lbajardsilogic@0 518
lbajardsilogic@0 519 for (size_t i = 0; i <= m_wlen/2; ++i) {
lbajardsilogic@0 520
lbajardsilogic@0 521 float real = 0.f, imag = 0.f;
lbajardsilogic@0 522
lbajardsilogic@0 523 for (size_t c = 0; c < m_channels; ++c) {
lbajardsilogic@0 524 real += m_freq[c][i][0];
lbajardsilogic@0 525 imag += m_freq[c][i][1];
lbajardsilogic@0 526 }
lbajardsilogic@0 527
lbajardsilogic@0 528 float sqrmag = (real * real + imag * imag);
lbajardsilogic@0 529
lbajardsilogic@0 530 if (m_prevTransientMag[i] > 0.f) {
lbajardsilogic@0 531 float diff = 10.f * log10f(sqrmag / m_prevTransientMag[i]);
lbajardsilogic@0 532 if (diff > 3.f) ++count;
lbajardsilogic@0 533 }
lbajardsilogic@0 534
lbajardsilogic@0 535 m_prevTransientMag[i] = sqrmag;
lbajardsilogic@0 536 }
lbajardsilogic@0 537
lbajardsilogic@0 538 bool isTransient = false;
lbajardsilogic@0 539
lbajardsilogic@0 540 // if (count > m_transientThreshold &&
lbajardsilogic@0 541 // count > m_prevTransientScore * 1.2) {
lbajardsilogic@0 542 if (count > m_prevTransientScore &&
lbajardsilogic@0 543 count > m_transientThreshold &&
lbajardsilogic@0 544 count - m_prevTransientScore > int(m_wlen) / 20) {
lbajardsilogic@0 545 isTransient = true;
lbajardsilogic@0 546
lbajardsilogic@0 547
lbajardsilogic@0 548 std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ", ratio = " << (m_totalCount > 0 ? (float (m_n2sum) / float(m_totalCount * m_n1)) : 1.f) << ", ideal = " << m_ratio << ")" << std::endl;
lbajardsilogic@0 549 // } else {
lbajardsilogic@0 550 // std::cerr << " !transient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ")" << std::endl;
lbajardsilogic@0 551 }
lbajardsilogic@0 552
lbajardsilogic@0 553 m_prevTransientScore = count;
lbajardsilogic@0 554
lbajardsilogic@0 555 return isTransient;
lbajardsilogic@0 556 }
lbajardsilogic@0 557
lbajardsilogic@0 558 void
lbajardsilogic@0 559 PhaseVocoderTimeStretcher::synthesiseBlock(size_t c,
lbajardsilogic@0 560 float *out,
lbajardsilogic@0 561 float *modulation,
lbajardsilogic@0 562 size_t lastStep)
lbajardsilogic@0 563 {
lbajardsilogic@0 564 bool unchanged = (lastStep == m_n1);
lbajardsilogic@0 565
lbajardsilogic@0 566 for (size_t i = 0; i <= m_wlen/2; ++i) {
lbajardsilogic@0 567
lbajardsilogic@0 568 float phase = princargf(atan2f(m_freq[c][i][1], m_freq[c][i][0]));
lbajardsilogic@0 569 float adjustedPhase = phase;
lbajardsilogic@0 570
lbajardsilogic@0 571 if (!unchanged) {
lbajardsilogic@0 572
lbajardsilogic@0 573 float omega = (2 * M_PI * m_n1 * i) / m_wlen;
lbajardsilogic@0 574
lbajardsilogic@0 575 float expectedPhase = m_prevPhase[c][i] + omega;
lbajardsilogic@0 576
lbajardsilogic@0 577 float phaseError = princargf(phase - expectedPhase);
lbajardsilogic@0 578
lbajardsilogic@0 579 float phaseIncrement = (omega + phaseError) / m_n1;
lbajardsilogic@0 580
lbajardsilogic@0 581 adjustedPhase = m_prevAdjustedPhase[c][i] +
lbajardsilogic@0 582 lastStep * phaseIncrement;
lbajardsilogic@0 583
lbajardsilogic@0 584 float mag = sqrtf(m_freq[c][i][0] * m_freq[c][i][0] +
lbajardsilogic@0 585 m_freq[c][i][1] * m_freq[c][i][1]);
lbajardsilogic@0 586
lbajardsilogic@0 587 float real = mag * cosf(adjustedPhase);
lbajardsilogic@0 588 float imag = mag * sinf(adjustedPhase);
lbajardsilogic@0 589 m_freq[c][i][0] = real;
lbajardsilogic@0 590 m_freq[c][i][1] = imag;
lbajardsilogic@0 591 }
lbajardsilogic@0 592
lbajardsilogic@0 593 m_prevPhase[c][i] = phase;
lbajardsilogic@0 594 m_prevAdjustedPhase[c][i] = adjustedPhase;
lbajardsilogic@0 595 }
lbajardsilogic@0 596
lbajardsilogic@0 597 fftf_execute(m_iplan[c]); // m_freq -> m_time, inverse fft
lbajardsilogic@0 598
lbajardsilogic@0 599 for (size_t i = 0; i < m_wlen/2; ++i) {
lbajardsilogic@0 600 float temp = m_time[c][i];
lbajardsilogic@0 601 m_time[c][i] = m_time[c][i + m_wlen/2];
lbajardsilogic@0 602 m_time[c][i + m_wlen/2] = temp;
lbajardsilogic@0 603 }
lbajardsilogic@0 604
lbajardsilogic@0 605 for (size_t i = 0; i < m_wlen; ++i) {
lbajardsilogic@0 606 m_time[c][i] = m_time[c][i] / m_wlen;
lbajardsilogic@0 607 }
lbajardsilogic@0 608
lbajardsilogic@0 609 m_synthesisWindow->cut(m_time[c]);
lbajardsilogic@0 610
lbajardsilogic@0 611 for (size_t i = 0; i < m_wlen; ++i) {
lbajardsilogic@0 612 out[i] += m_time[c][i];
lbajardsilogic@0 613 }
lbajardsilogic@0 614
lbajardsilogic@0 615 if (modulation) {
lbajardsilogic@0 616
lbajardsilogic@0 617 float area = m_analysisWindow->getArea();
lbajardsilogic@0 618
lbajardsilogic@0 619 for (size_t i = 0; i < m_wlen; ++i) {
lbajardsilogic@0 620 float val = m_synthesisWindow->getValue(i);
lbajardsilogic@0 621 modulation[i] += val * area;
lbajardsilogic@0 622 }
lbajardsilogic@0 623 }
lbajardsilogic@0 624 }
lbajardsilogic@0 625
lbajardsilogic@0 626