annotate audioio/PhaseVocoderTimeStretcher.cpp @ 35:06787742542a

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents e3b32dc5180b
children 76cc2c424268
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 #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@25 164 }
Chris@25 165
Chris@31 166 m_transientThreshold = lrintf(m_wlen / 4.5);
Chris@26 167
Chris@26 168 m_totalCount = 0;
Chris@26 169 m_transientCount = 0;
Chris@26 170 m_n2sum = 0;
Chris@26 171
Chris@26 172
Chris@26 173 std::cerr << "PhaseVocoderTimeStretcher: channels = " << m_channels
Chris@26 174 << ", ratio = " << m_ratio
Chris@26 175 << ", n1 = " << m_n1 << ", n2 = " << m_n2 << ", wlen = "
Chris@31 176 << m_wlen << ", max = " << m_maxOutputBlockSize << std::endl;
Chris@26 177 // << ", outbuflen = " << m_outbuf[0]->getSize() << std::endl;
Chris@25 178 }
Chris@25 179
Chris@25 180 void
Chris@25 181 PhaseVocoderTimeStretcher::cleanup()
Chris@25 182 {
Chris@25 183 std::cerr << "PhaseVocoderTimeStretcher::cleanup" << std::endl;
Chris@0 184
Chris@20 185 for (size_t c = 0; c < m_channels; ++c) {
Chris@0 186
Chris@20 187 fftwf_destroy_plan(m_plan[c]);
Chris@20 188 fftwf_destroy_plan(m_iplan[c]);
Chris@16 189
Chris@20 190 fftwf_free(m_time[c]);
Chris@20 191 fftwf_free(m_freq[c]);
Chris@16 192
Chris@16 193 fftwf_free(m_mashbuf[c]);
Chris@16 194 fftwf_free(m_prevPhase[c]);
Chris@16 195 fftwf_free(m_prevAdjustedPhase[c]);
Chris@16 196
Chris@16 197 delete m_inbuf[c];
Chris@16 198 delete m_outbuf[c];
Chris@16 199 }
Chris@16 200
Chris@20 201 fftwf_free(m_tempbuf);
Chris@13 202 fftwf_free(m_modulationbuf);
Chris@20 203 fftwf_free(m_prevTransientMag);
Chris@0 204
Chris@16 205 delete[] m_prevPhase;
Chris@16 206 delete[] m_prevAdjustedPhase;
Chris@16 207 delete[] m_inbuf;
Chris@16 208 delete[] m_outbuf;
Chris@16 209 delete[] m_mashbuf;
Chris@20 210 delete[] m_time;
Chris@20 211 delete[] m_freq;
Chris@20 212 delete[] m_plan;
Chris@20 213 delete[] m_iplan;
Chris@15 214
Chris@20 215 delete m_analysisWindow;
Chris@20 216 delete m_synthesisWindow;
Chris@0 217 }
Chris@0 218
Chris@25 219 void
Chris@25 220 PhaseVocoderTimeStretcher::setRatio(float ratio)
Chris@25 221 {
Chris@25 222 QMutexLocker locker(m_mutex);
Chris@25 223
Chris@25 224 size_t formerWlen = m_wlen;
Chris@25 225 m_ratio = ratio;
Chris@25 226
Chris@25 227 calculateParameters();
Chris@25 228
Chris@25 229 if (m_wlen == formerWlen) {
Chris@25 230
Chris@25 231 // This is the only container whose size depends on m_ratio
Chris@25 232
Chris@31 233 RingBuffer<float> **newin = new RingBuffer<float> *[m_channels];
Chris@25 234
Chris@31 235 size_t formerSize = m_inbuf[0]->getSize();
Chris@31 236 size_t newSize = lrintf(m_outbuf[0]->getSize() / m_ratio) + m_wlen;
Chris@25 237
Chris@31 238 std::cerr << "resizing inbuf from " << formerSize << " to "
Chris@31 239 << newSize << " (outbuf size is " << m_outbuf[0]->getSize() << ", ratio " << m_ratio << ")" << std::endl;
Chris@25 240
Chris@31 241 if (formerSize != newSize) {
Chris@25 242
Chris@31 243 size_t ready = m_inbuf[0]->getReadSpace();
Chris@25 244
Chris@25 245 for (size_t c = 0; c < m_channels; ++c) {
Chris@31 246 newin[c] = new RingBuffer<float>(newSize);
Chris@25 247 }
Chris@25 248
Chris@31 249 if (ready > 0) {
Chris@31 250
Chris@31 251 size_t copy = std::min(ready, newSize);
Chris@31 252 float *tmp = new float[ready];
Chris@31 253
Chris@31 254 for (size_t c = 0; c < m_channels; ++c) {
Chris@31 255 m_inbuf[c]->read(tmp, ready);
Chris@31 256 newin[c]->write(tmp + ready - copy, copy);
Chris@31 257 }
Chris@31 258
Chris@31 259 delete[] tmp;
Chris@31 260 }
Chris@31 261
Chris@31 262 for (size_t c = 0; c < m_channels; ++c) {
Chris@31 263 delete m_inbuf[c];
Chris@31 264 }
Chris@31 265
Chris@31 266 delete[] m_inbuf;
Chris@31 267 m_inbuf = newin;
Chris@25 268 }
Chris@25 269
Chris@25 270 } else {
Chris@25 271
Chris@25 272 std::cerr << "wlen changed" << std::endl;
Chris@25 273 cleanup();
Chris@25 274 initialise();
Chris@25 275 }
Chris@25 276 }
Chris@25 277
Chris@0 278 size_t
Chris@14 279 PhaseVocoderTimeStretcher::getProcessingLatency() const
Chris@0 280 {
Chris@0 281 return getWindowSize() - getInputIncrement();
Chris@0 282 }
Chris@0 283
Chris@16 284 size_t
Chris@16 285 PhaseVocoderTimeStretcher::getRequiredInputSamples() const
Chris@16 286 {
Chris@25 287 QMutexLocker locker(m_mutex);
Chris@25 288
Chris@16 289 if (m_inbuf[0]->getReadSpace() >= m_wlen) return 0;
Chris@16 290 return m_wlen - m_inbuf[0]->getReadSpace();
Chris@16 291 }
Chris@16 292
Chris@16 293 void
Chris@16 294 PhaseVocoderTimeStretcher::putInput(float **input, size_t samples)
Chris@0 295 {
Chris@25 296 QMutexLocker locker(m_mutex);
Chris@25 297
Chris@0 298 // We need to add samples from input to our internal buffer. When
Chris@0 299 // we have m_windowSize samples in the buffer, we can process it,
Chris@0 300 // move the samples back by m_n1 and write the output onto our
Chris@0 301 // internal output buffer. If we have (samples * ratio) samples
Chris@0 302 // in that, we can write m_n2 of them back to output and return
Chris@0 303 // (otherwise we have to write zeroes).
Chris@0 304
Chris@0 305 // When we process, we write m_wlen to our fixed output buffer
Chris@0 306 // (m_mashbuf). We then pull out the first m_n2 samples from that
Chris@0 307 // buffer, push them into the output ring buffer, and shift
Chris@0 308 // m_mashbuf left by that amount.
Chris@0 309
Chris@0 310 // The processing latency is then m_wlen - m_n2.
Chris@0 311
Chris@0 312 size_t consumed = 0;
Chris@0 313
Chris@0 314 while (consumed < samples) {
Chris@0 315
Chris@16 316 size_t writable = m_inbuf[0]->getWriteSpace();
Chris@0 317 writable = std::min(writable, samples - consumed);
Chris@0 318
Chris@0 319 if (writable == 0) {
Chris@32 320 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@31 321 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 322 #endif
Chris@31 323 if (m_inbuf[0]->getReadSpace() < m_wlen ||
Chris@31 324 m_outbuf[0]->getWriteSpace() < m_n2) {
Chris@32 325 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 326 break;
Chris@31 327 }
Chris@31 328 } else {
Chris@0 329
Chris@14 330 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@31 331 std::cerr << "writing " << writable << " from index " << consumed << " to inbuf, consumed will be " << consumed + writable << std::endl;
Chris@0 332 #endif
Chris@16 333
Chris@31 334 for (size_t c = 0; c < m_channels; ++c) {
Chris@31 335 m_inbuf[c]->write(input[c] + consumed, writable);
Chris@31 336 }
Chris@31 337 consumed += writable;
Chris@16 338 }
Chris@0 339
Chris@16 340 while (m_inbuf[0]->getReadSpace() >= m_wlen &&
Chris@16 341 m_outbuf[0]->getWriteSpace() >= m_n2) {
Chris@0 342
Chris@0 343 // We know we have at least m_wlen samples available
Chris@16 344 // in m_inbuf. We need to peek m_wlen of them for
Chris@0 345 // processing, and then read m_n1 to advance the read
Chris@0 346 // pointer.
Chris@16 347
Chris@20 348 for (size_t c = 0; c < m_channels; ++c) {
Chris@20 349
Chris@20 350 size_t got = m_inbuf[c]->peek(m_tempbuf, m_wlen);
Chris@20 351 assert(got == m_wlen);
Chris@20 352
Chris@20 353 analyseBlock(c, m_tempbuf);
Chris@20 354 }
Chris@20 355
Chris@20 356 bool transient = false;
Chris@32 357 if (shouldSharpen()) transient = isTransient();
Chris@20 358
Chris@16 359 size_t n2 = m_n2;
Chris@20 360
Chris@20 361 if (transient) {
Chris@20 362 n2 = m_n1;
Chris@20 363 }
Chris@0 364
Chris@21 365 ++m_totalCount;
Chris@21 366 if (transient) ++m_transientCount;
Chris@21 367 m_n2sum += n2;
Chris@21 368
Chris@21 369 // std::cerr << "ratio for last 10: " <<last10num << "/" << (10 * m_n1) << " = " << float(last10num) / float(10 * m_n1) << " (should be " << m_ratio << ")" << std::endl;
Chris@21 370
Chris@21 371 if (m_totalCount > 50 && m_transientCount < m_totalCount) {
Chris@21 372
Chris@21 373 int fixed = lrintf(m_transientCount * m_n1);
Chris@21 374 int squashy = m_n2sum - fixed;
Chris@21 375
Chris@21 376 int idealTotal = lrintf(m_totalCount * m_n1 * m_ratio);
Chris@21 377 int idealSquashy = idealTotal - fixed;
Chris@21 378
Chris@21 379 int squashyCount = m_totalCount - m_transientCount;
Chris@21 380
Chris@21 381 n2 = lrintf(idealSquashy / squashyCount);
Chris@21 382
Chris@32 383 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@21 384 if (n2 != m_n2) {
Chris@21 385 std::cerr << m_n2 << " -> " << n2 << std::endl;
Chris@21 386 }
Chris@32 387 #endif
Chris@21 388 }
Chris@21 389
Chris@16 390 for (size_t c = 0; c < m_channels; ++c) {
Chris@16 391
Chris@20 392 synthesiseBlock(c, m_mashbuf[c],
Chris@20 393 c == 0 ? m_modulationbuf : 0,
Chris@20 394 m_prevTransient ? m_n1 : m_n2);
Chris@16 395
Chris@0 396
Chris@14 397 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 398 std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl;
Chris@0 399 #endif
Chris@16 400 m_inbuf[c]->skip(m_n1);
Chris@13 401
Chris@16 402 for (size_t i = 0; i < n2; ++i) {
Chris@16 403 if (m_modulationbuf[i] > 0.f) {
Chris@16 404 m_mashbuf[c][i] /= m_modulationbuf[i];
Chris@16 405 }
Chris@16 406 }
Chris@16 407
Chris@16 408 m_outbuf[c]->write(m_mashbuf[c], n2);
Chris@16 409
Chris@16 410 for (size_t i = 0; i < m_wlen - n2; ++i) {
Chris@16 411 m_mashbuf[c][i] = m_mashbuf[c][i + n2];
Chris@16 412 }
Chris@16 413
Chris@16 414 for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
Chris@16 415 m_mashbuf[c][i] = 0.0f;
Chris@13 416 }
Chris@13 417 }
Chris@13 418
Chris@20 419 m_prevTransient = transient;
Chris@17 420
Chris@16 421 for (size_t i = 0; i < m_wlen - n2; ++i) {
Chris@16 422 m_modulationbuf[i] = m_modulationbuf[i + n2];
Chris@0 423 }
Chris@13 424
Chris@16 425 for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
Chris@13 426 m_modulationbuf[i] = 0.0f;
Chris@0 427 }
Chris@21 428
Chris@21 429 if (!transient) m_n2 = n2;
Chris@0 430 }
Chris@0 431
Chris@0 432
Chris@14 433 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 434 std::cerr << "loop ended: inbuf read space " << m_inbuf[0]->getReadSpace() << ", outbuf write space " << m_outbuf[0]->getWriteSpace() << std::endl;
Chris@0 435 #endif
Chris@0 436 }
Chris@0 437
Chris@16 438 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 439 std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl;
Chris@16 440 #endif
Chris@21 441
Chris@21 442 // std::cerr << "ratio: nominal: " << getRatio() << " actual: "
Chris@21 443 // << m_total2 << "/" << m_total1 << " = " << float(m_total2) / float(m_total1) << " ideal: " << m_ratio << std::endl;
Chris@16 444 }
Chris@12 445
Chris@16 446 size_t
Chris@16 447 PhaseVocoderTimeStretcher::getAvailableOutputSamples() const
Chris@16 448 {
Chris@25 449 QMutexLocker locker(m_mutex);
Chris@25 450
Chris@16 451 return m_outbuf[0]->getReadSpace();
Chris@16 452 }
Chris@16 453
Chris@16 454 void
Chris@16 455 PhaseVocoderTimeStretcher::getOutput(float **output, size_t samples)
Chris@16 456 {
Chris@25 457 QMutexLocker locker(m_mutex);
Chris@25 458
Chris@16 459 if (m_outbuf[0]->getReadSpace() < samples) {
Chris@16 460 std::cerr << "WARNING: PhaseVocoderTimeStretcher::getOutput: not enough data (yet?) (" << m_outbuf[0]->getReadSpace() << " < " << samples << ")" << std::endl;
Chris@16 461 size_t fill = samples - m_outbuf[0]->getReadSpace();
Chris@16 462 for (size_t c = 0; c < m_channels; ++c) {
Chris@16 463 for (size_t i = 0; i < fill; ++i) {
Chris@16 464 output[c][i] = 0.0;
Chris@16 465 }
Chris@16 466 m_outbuf[c]->read(output[c] + fill, m_outbuf[c]->getReadSpace());
Chris@16 467 }
Chris@0 468 } else {
Chris@14 469 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 470 std::cerr << "enough data - writing " << samples << " from outbuf" << std::endl;
Chris@0 471 #endif
Chris@16 472 for (size_t c = 0; c < m_channels; ++c) {
Chris@16 473 m_outbuf[c]->read(output[c], samples);
Chris@16 474 }
Chris@0 475 }
Chris@0 476
Chris@14 477 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 478 std::cerr << "PhaseVocoderTimeStretcher::getOutput returning" << std::endl;
Chris@0 479 #endif
Chris@0 480 }
Chris@0 481
Chris@20 482 void
Chris@20 483 PhaseVocoderTimeStretcher::analyseBlock(size_t c, float *buf)
Chris@0 484 {
Chris@0 485 size_t i;
Chris@0 486
Chris@20 487 // buf contains m_wlen samples
Chris@0 488
Chris@14 489 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@20 490 std::cerr << "PhaseVocoderTimeStretcher::analyseBlock (channel " << c << ")" << std::endl;
Chris@0 491 #endif
Chris@0 492
Chris@20 493 m_analysisWindow->cut(buf);
Chris@0 494
Chris@0 495 for (i = 0; i < m_wlen/2; ++i) {
Chris@0 496 float temp = buf[i];
Chris@0 497 buf[i] = buf[i + m_wlen/2];
Chris@0 498 buf[i + m_wlen/2] = temp;
Chris@0 499 }
Chris@19 500
Chris@0 501 for (i = 0; i < m_wlen; ++i) {
Chris@20 502 m_time[c][i] = buf[i];
Chris@0 503 }
Chris@0 504
Chris@20 505 fftwf_execute(m_plan[c]); // m_time -> m_freq
Chris@20 506 }
Chris@0 507
Chris@20 508 bool
Chris@20 509 PhaseVocoderTimeStretcher::isTransient()
Chris@20 510 {
Chris@20 511 int count = 0;
Chris@16 512
Chris@31 513 for (size_t i = 0; i <= m_wlen/2; ++i) {
Chris@16 514
Chris@20 515 float real = 0.f, imag = 0.f;
Chris@20 516
Chris@20 517 for (size_t c = 0; c < m_channels; ++c) {
Chris@20 518 real += m_freq[c][i][0];
Chris@20 519 imag += m_freq[c][i][1];
Chris@16 520 }
Chris@16 521
Chris@20 522 float sqrmag = (real * real + imag * imag);
Chris@20 523
Chris@20 524 if (m_prevTransientMag[i] > 0.f) {
Chris@20 525 float diff = 10.f * log10f(sqrmag / m_prevTransientMag[i]);
Chris@20 526 if (diff > 3.f) ++count;
Chris@20 527 }
Chris@20 528
Chris@20 529 m_prevTransientMag[i] = sqrmag;
Chris@16 530 }
Chris@16 531
Chris@20 532 bool isTransient = false;
Chris@16 533
Chris@26 534 // if (count > m_transientThreshold &&
Chris@26 535 // count > m_prevTransientScore * 1.2) {
Chris@26 536 if (count > m_prevTransientScore &&
Chris@26 537 count > m_transientThreshold &&
Chris@26 538 count - m_prevTransientScore > m_wlen / 20) {
Chris@20 539 isTransient = true;
Chris@26 540
Chris@26 541
Chris@26 542 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 543 // } else {
Chris@26 544 // std::cerr << " !transient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ")" << std::endl;
Chris@20 545 }
Chris@16 546
Chris@21 547 m_prevTransientScore = count;
Chris@20 548
Chris@20 549 return isTransient;
Chris@20 550 }
Chris@20 551
Chris@20 552 void
Chris@20 553 PhaseVocoderTimeStretcher::synthesiseBlock(size_t c,
Chris@20 554 float *out,
Chris@20 555 float *modulation,
Chris@20 556 size_t lastStep)
Chris@20 557 {
Chris@20 558 bool unchanged = (lastStep == m_n1);
Chris@20 559
Chris@31 560 for (size_t i = 0; i <= m_wlen/2; ++i) {
Chris@0 561
Chris@20 562 float phase = princargf(atan2f(m_freq[c][i][1], m_freq[c][i][0]));
Chris@19 563 float adjustedPhase = phase;
Chris@12 564
Chris@20 565 if (!unchanged) {
Chris@16 566
Chris@20 567 float mag = sqrtf(m_freq[c][i][0] * m_freq[c][i][0] +
Chris@20 568 m_freq[c][i][1] * m_freq[c][i][1]);
Chris@19 569
Chris@20 570 float omega = (2 * M_PI * m_n1 * i) / m_wlen;
Chris@20 571
Chris@20 572 float expectedPhase = m_prevPhase[c][i] + omega;
Chris@20 573
Chris@20 574 float phaseError = princargf(phase - expectedPhase);
Chris@20 575
Chris@20 576 float phaseIncrement = (omega + phaseError) / m_n1;
Chris@20 577
Chris@20 578 adjustedPhase = m_prevAdjustedPhase[c][i] +
Chris@20 579 lastStep * phaseIncrement;
Chris@20 580
Chris@20 581 float real = mag * cosf(adjustedPhase);
Chris@20 582 float imag = mag * sinf(adjustedPhase);
Chris@20 583 m_freq[c][i][0] = real;
Chris@20 584 m_freq[c][i][1] = imag;
Chris@19 585 }
Chris@19 586
Chris@16 587 m_prevPhase[c][i] = phase;
Chris@16 588 m_prevAdjustedPhase[c][i] = adjustedPhase;
Chris@0 589 }
Chris@20 590
Chris@20 591 fftwf_execute(m_iplan[c]); // m_freq -> m_time, inverse fft
Chris@19 592
Chris@31 593 for (size_t i = 0; i < m_wlen/2; ++i) {
Chris@20 594 float temp = m_time[c][i];
Chris@20 595 m_time[c][i] = m_time[c][i + m_wlen/2];
Chris@20 596 m_time[c][i + m_wlen/2] = temp;
Chris@20 597 }
Chris@20 598
Chris@31 599 for (size_t i = 0; i < m_wlen; ++i) {
Chris@20 600 m_time[c][i] = m_time[c][i] / m_wlen;
Chris@0 601 }
Chris@15 602
Chris@20 603 m_synthesisWindow->cut(m_time[c]);
Chris@19 604
Chris@31 605 for (size_t i = 0; i < m_wlen; ++i) {
Chris@20 606 out[i] += m_time[c][i];
Chris@0 607 }
Chris@16 608
Chris@16 609 if (modulation) {
Chris@16 610
Chris@20 611 float area = m_analysisWindow->getArea();
Chris@16 612
Chris@31 613 for (size_t i = 0; i < m_wlen; ++i) {
Chris@20 614 float val = m_synthesisWindow->getValue(i);
Chris@16 615 modulation[i] += val * area;
Chris@16 616 }
Chris@16 617 }
Chris@0 618 }
Chris@15 619
Chris@20 620