annotate audioio/PhaseVocoderTimeStretcher.cpp @ 77:0535c49069ba

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