annotate audioio/PhaseVocoderTimeStretcher.cpp @ 201:de783e8ee5f0

* Hoist alignment model set/query up to Model, so any models can be aligned * Add Model::aboutToDelete and aboutToBeDeleted for management of models that are contained by or referred to by other models instead of only the document
author Chris Cannam
date Wed, 24 Oct 2007 15:21:38 +0000
parents 5bde373ad5ca
children
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@100 65 m_prevTransientMag = (float *)fftf_malloc(sizeof(float) * (m_wlen / 2 + 1));
Chris@21 66 m_prevTransientScore = 0;
Chris@20 67 m_prevTransient = false;
Chris@20 68
Chris@100 69 m_tempbuf = (float *)fftf_malloc(sizeof(float) * m_wlen);
Chris@20 70
Chris@20 71 m_time = new float *[m_channels];
Chris@100 72 m_freq = new fftf_complex *[m_channels];
Chris@100 73 m_plan = new fftf_plan[m_channels];
Chris@100 74 m_iplan = new fftf_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@100 80 m_modulationbuf = (float *)fftf_malloc(sizeof(float) * m_wlen);
Chris@16 81
Chris@16 82 for (size_t c = 0; c < m_channels; ++c) {
Chris@16 83
Chris@100 84 m_prevPhase[c] = (float *)fftf_malloc(sizeof(float) * (m_wlen / 2 + 1));
Chris@100 85 m_prevAdjustedPhase[c] = (float *)fftf_malloc(sizeof(float) * (m_wlen / 2 + 1));
Chris@16 86
Chris@100 87 m_time[c] = (float *)fftf_malloc(sizeof(float) * m_wlen);
Chris@100 88 m_freq[c] = (fftf_complex *)fftf_malloc(sizeof(fftf_complex) *
Chris@20 89 (m_wlen / 2 + 1));
Chris@20 90
Chris@177 91 m_plan[c] = fftf_plan_dft_r2c_1d(m_wlen, m_time[c], m_freq[c], FFTW_MEASURE);
Chris@177 92 m_iplan[c] = fftf_plan_dft_c2r_1d(m_wlen, m_freq[c], m_time[c], FFTW_MEASURE);
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@100 102 m_mashbuf[c] = (float *)fftf_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@137 166 m_n2 = lrintf(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@100 191 fftf_destroy_plan(m_plan[c]);
Chris@100 192 fftf_destroy_plan(m_iplan[c]);
Chris@16 193
Chris@100 194 fftf_free(m_time[c]);
Chris@100 195 fftf_free(m_freq[c]);
Chris@16 196
Chris@100 197 fftf_free(m_mashbuf[c]);
Chris@100 198 fftf_free(m_prevPhase[c]);
Chris@100 199 fftf_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@100 205 fftf_free(m_tempbuf);
Chris@100 206 fftf_free(m_modulationbuf);
Chris@100 207 fftf_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
Chris@21 382 int idealTotal = lrintf(m_totalCount * m_n1 * m_ratio);
Chris@21 383 int idealSquashy = idealTotal - fixed;
Chris@21 384
Chris@21 385 int squashyCount = m_totalCount - m_transientCount;
Chris@21 386
Chris@21 387 n2 = lrintf(idealSquashy / squashyCount);
Chris@21 388
Chris@32 389 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@21 390 if (n2 != m_n2) {
Chris@21 391 std::cerr << m_n2 << " -> " << n2 << std::endl;
Chris@21 392 }
Chris@32 393 #endif
Chris@21 394 }
Chris@21 395
Chris@16 396 for (size_t c = 0; c < m_channels; ++c) {
Chris@16 397
Chris@20 398 synthesiseBlock(c, m_mashbuf[c],
Chris@20 399 c == 0 ? m_modulationbuf : 0,
Chris@20 400 m_prevTransient ? m_n1 : m_n2);
Chris@16 401
Chris@0 402
Chris@14 403 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 404 std::cerr << "writing first " << m_n2 << " from mashbuf, skipping " << m_n1 << " on inbuf " << std::endl;
Chris@0 405 #endif
Chris@16 406 m_inbuf[c]->skip(m_n1);
Chris@13 407
Chris@16 408 for (size_t i = 0; i < n2; ++i) {
Chris@16 409 if (m_modulationbuf[i] > 0.f) {
Chris@16 410 m_mashbuf[c][i] /= m_modulationbuf[i];
Chris@16 411 }
Chris@16 412 }
Chris@16 413
Chris@16 414 m_outbuf[c]->write(m_mashbuf[c], n2);
Chris@16 415
Chris@16 416 for (size_t i = 0; i < m_wlen - n2; ++i) {
Chris@16 417 m_mashbuf[c][i] = m_mashbuf[c][i + n2];
Chris@16 418 }
Chris@16 419
Chris@16 420 for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
Chris@16 421 m_mashbuf[c][i] = 0.0f;
Chris@13 422 }
Chris@13 423 }
Chris@13 424
Chris@20 425 m_prevTransient = transient;
Chris@17 426
Chris@16 427 for (size_t i = 0; i < m_wlen - n2; ++i) {
Chris@16 428 m_modulationbuf[i] = m_modulationbuf[i + n2];
Chris@0 429 }
Chris@13 430
Chris@16 431 for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
Chris@13 432 m_modulationbuf[i] = 0.0f;
Chris@0 433 }
Chris@21 434
Chris@21 435 if (!transient) m_n2 = n2;
Chris@0 436 }
Chris@0 437
Chris@0 438
Chris@14 439 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 440 std::cerr << "loop ended: inbuf read space " << m_inbuf[0]->getReadSpace() << ", outbuf write space " << m_outbuf[0]->getWriteSpace() << std::endl;
Chris@0 441 #endif
Chris@0 442 }
Chris@0 443
Chris@16 444 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 445 std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl;
Chris@16 446 #endif
Chris@21 447
Chris@21 448 // std::cerr << "ratio: nominal: " << getRatio() << " actual: "
Chris@21 449 // << m_total2 << "/" << m_total1 << " = " << float(m_total2) / float(m_total1) << " ideal: " << m_ratio << std::endl;
Chris@16 450 }
Chris@12 451
Chris@16 452 size_t
Chris@16 453 PhaseVocoderTimeStretcher::getAvailableOutputSamples() const
Chris@16 454 {
Chris@25 455 QMutexLocker locker(m_mutex);
Chris@25 456
Chris@16 457 return m_outbuf[0]->getReadSpace();
Chris@16 458 }
Chris@16 459
Chris@16 460 void
Chris@16 461 PhaseVocoderTimeStretcher::getOutput(float **output, size_t samples)
Chris@16 462 {
Chris@25 463 QMutexLocker locker(m_mutex);
Chris@25 464
Chris@16 465 if (m_outbuf[0]->getReadSpace() < samples) {
Chris@16 466 std::cerr << "WARNING: PhaseVocoderTimeStretcher::getOutput: not enough data (yet?) (" << m_outbuf[0]->getReadSpace() << " < " << samples << ")" << std::endl;
Chris@16 467 size_t fill = samples - m_outbuf[0]->getReadSpace();
Chris@16 468 for (size_t c = 0; c < m_channels; ++c) {
Chris@16 469 for (size_t i = 0; i < fill; ++i) {
Chris@16 470 output[c][i] = 0.0;
Chris@16 471 }
Chris@16 472 m_outbuf[c]->read(output[c] + fill, m_outbuf[c]->getReadSpace());
Chris@16 473 }
Chris@0 474 } else {
Chris@14 475 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 476 std::cerr << "enough data - writing " << samples << " from outbuf" << std::endl;
Chris@0 477 #endif
Chris@16 478 for (size_t c = 0; c < m_channels; ++c) {
Chris@16 479 m_outbuf[c]->read(output[c], samples);
Chris@16 480 }
Chris@0 481 }
Chris@0 482
Chris@14 483 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@16 484 std::cerr << "PhaseVocoderTimeStretcher::getOutput returning" << std::endl;
Chris@0 485 #endif
Chris@0 486 }
Chris@0 487
Chris@20 488 void
Chris@20 489 PhaseVocoderTimeStretcher::analyseBlock(size_t c, float *buf)
Chris@0 490 {
Chris@0 491 size_t i;
Chris@0 492
Chris@20 493 // buf contains m_wlen samples
Chris@0 494
Chris@14 495 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
Chris@20 496 std::cerr << "PhaseVocoderTimeStretcher::analyseBlock (channel " << c << ")" << std::endl;
Chris@0 497 #endif
Chris@0 498
Chris@20 499 m_analysisWindow->cut(buf);
Chris@0 500
Chris@0 501 for (i = 0; i < m_wlen/2; ++i) {
Chris@0 502 float temp = buf[i];
Chris@0 503 buf[i] = buf[i + m_wlen/2];
Chris@0 504 buf[i + m_wlen/2] = temp;
Chris@0 505 }
Chris@19 506
Chris@0 507 for (i = 0; i < m_wlen; ++i) {
Chris@20 508 m_time[c][i] = buf[i];
Chris@0 509 }
Chris@0 510
Chris@100 511 fftf_execute(m_plan[c]); // m_time -> m_freq
Chris@20 512 }
Chris@0 513
Chris@20 514 bool
Chris@20 515 PhaseVocoderTimeStretcher::isTransient()
Chris@20 516 {
Chris@20 517 int count = 0;
Chris@16 518
Chris@31 519 for (size_t i = 0; i <= m_wlen/2; ++i) {
Chris@16 520
Chris@20 521 float real = 0.f, imag = 0.f;
Chris@20 522
Chris@20 523 for (size_t c = 0; c < m_channels; ++c) {
Chris@20 524 real += m_freq[c][i][0];
Chris@20 525 imag += m_freq[c][i][1];
Chris@16 526 }
Chris@16 527
Chris@20 528 float sqrmag = (real * real + imag * imag);
Chris@20 529
Chris@20 530 if (m_prevTransientMag[i] > 0.f) {
Chris@20 531 float diff = 10.f * log10f(sqrmag / m_prevTransientMag[i]);
Chris@20 532 if (diff > 3.f) ++count;
Chris@20 533 }
Chris@20 534
Chris@20 535 m_prevTransientMag[i] = sqrmag;
Chris@16 536 }
Chris@16 537
Chris@20 538 bool isTransient = false;
Chris@16 539
Chris@26 540 // if (count > m_transientThreshold &&
Chris@26 541 // count > m_prevTransientScore * 1.2) {
Chris@26 542 if (count > m_prevTransientScore &&
Chris@26 543 count > m_transientThreshold &&
Chris@137 544 count - m_prevTransientScore > int(m_wlen) / 20) {
Chris@20 545 isTransient = true;
Chris@26 546
Chris@26 547
Chris@155 548 // std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ", ratio = " << (m_totalCount > 0 ? (float (m_n2sum) / float(m_totalCount * m_n1)) : 1.f) << ", ideal = " << m_ratio << ")" << std::endl;
Chris@26 549 // } else {
Chris@26 550 // std::cerr << " !transient (count = " << count << ", prev = " << m_prevTransientScore << ", diff = " << count - m_prevTransientScore << ")" << std::endl;
Chris@20 551 }
Chris@16 552
Chris@21 553 m_prevTransientScore = count;
Chris@20 554
Chris@20 555 return isTransient;
Chris@20 556 }
Chris@20 557
Chris@20 558 void
Chris@20 559 PhaseVocoderTimeStretcher::synthesiseBlock(size_t c,
Chris@20 560 float *out,
Chris@20 561 float *modulation,
Chris@20 562 size_t lastStep)
Chris@20 563 {
Chris@20 564 bool unchanged = (lastStep == m_n1);
Chris@20 565
Chris@31 566 for (size_t i = 0; i <= m_wlen/2; ++i) {
Chris@0 567
Chris@20 568 float phase = princargf(atan2f(m_freq[c][i][1], m_freq[c][i][0]));
Chris@19 569 float adjustedPhase = phase;
Chris@12 570
Chris@20 571 if (!unchanged) {
Chris@16 572
Chris@20 573 float omega = (2 * M_PI * m_n1 * i) / m_wlen;
Chris@20 574
Chris@20 575 float expectedPhase = m_prevPhase[c][i] + omega;
Chris@20 576
Chris@20 577 float phaseError = princargf(phase - expectedPhase);
Chris@20 578
Chris@20 579 float phaseIncrement = (omega + phaseError) / m_n1;
Chris@20 580
Chris@20 581 adjustedPhase = m_prevAdjustedPhase[c][i] +
Chris@20 582 lastStep * phaseIncrement;
Chris@20 583
Chris@78 584 float mag = sqrtf(m_freq[c][i][0] * m_freq[c][i][0] +
Chris@78 585 m_freq[c][i][1] * m_freq[c][i][1]);
Chris@78 586
Chris@20 587 float real = mag * cosf(adjustedPhase);
Chris@20 588 float imag = mag * sinf(adjustedPhase);
Chris@20 589 m_freq[c][i][0] = real;
Chris@20 590 m_freq[c][i][1] = imag;
Chris@19 591 }
Chris@19 592
Chris@16 593 m_prevPhase[c][i] = phase;
Chris@16 594 m_prevAdjustedPhase[c][i] = adjustedPhase;
Chris@0 595 }
Chris@20 596
Chris@100 597 fftf_execute(m_iplan[c]); // m_freq -> m_time, inverse fft
Chris@19 598
Chris@31 599 for (size_t i = 0; i < m_wlen/2; ++i) {
Chris@20 600 float temp = m_time[c][i];
Chris@20 601 m_time[c][i] = m_time[c][i + m_wlen/2];
Chris@20 602 m_time[c][i + m_wlen/2] = temp;
Chris@20 603 }
Chris@20 604
Chris@31 605 for (size_t i = 0; i < m_wlen; ++i) {
Chris@20 606 m_time[c][i] = m_time[c][i] / m_wlen;
Chris@0 607 }
Chris@15 608
Chris@20 609 m_synthesisWindow->cut(m_time[c]);
Chris@19 610
Chris@31 611 for (size_t i = 0; i < m_wlen; ++i) {
Chris@20 612 out[i] += m_time[c][i];
Chris@0 613 }
Chris@16 614
Chris@16 615 if (modulation) {
Chris@16 616
Chris@20 617 float area = m_analysisWindow->getArea();
Chris@16 618
Chris@31 619 for (size_t i = 0; i < m_wlen; ++i) {
Chris@20 620 float val = m_synthesisWindow->getValue(i);
Chris@16 621 modulation[i] += val * area;
Chris@16 622 }
Chris@16 623 }
Chris@0 624 }
Chris@15 625
Chris@20 626