annotate audioio/PhaseVocoderTimeStretcher.cpp @ 78:9918c8a3f904

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