annotate audioio/PhaseVocoderTimeStretcher.cpp @ 25:e74f508db18c

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