comparison audioio/PhaseVocoderTimeStretcher.cpp @ 21:7da85e0b85e9

* Add some internal feedback to the time stretcher to try to make it maintain tempo within variable timestretching situations -- not ideal but perhaps better than nothing. * Better tooltip text for play speeed control; make play sharpening control remember its last state
author Chris Cannam
date Thu, 14 Sep 2006 16:08:23 +0000
parents e125f0dde7a3
children 80126455d169
comparison
equal deleted inserted replaced
20:e125f0dde7a3 21:7da85e0b85e9
24 float ratio, 24 float ratio,
25 bool sharpen, 25 bool sharpen,
26 size_t maxProcessInputBlockSize) : 26 size_t maxProcessInputBlockSize) :
27 m_channels(channels), 27 m_channels(channels),
28 m_ratio(ratio), 28 m_ratio(ratio),
29 m_sharpen(sharpen) 29 m_sharpen(sharpen),
30 m_totalCount(0),
31 m_transientCount(0),
32 m_n2sum(0)
30 { 33 {
31 m_wlen = 1024; 34 m_wlen = 1024;
35
36 //!!! In transient sharpening mode, we need to pick the window
37 //length so as to be more or less fixed in audio duration (i.e. we
38 //need to know the sample rate)
32 39
33 if (ratio < 1) { 40 if (ratio < 1) {
34 if (ratio < 0.4) { 41 if (ratio < 0.4) {
35 m_n1 = 1024; 42 m_n1 = 1024;
36 m_wlen = 2048; 43 m_wlen = 2048;
38 m_n1 = 512; 45 m_n1 = 512;
39 } else { 46 } else {
40 m_n1 = 256; 47 m_n1 = 256;
41 } 48 }
42 if (m_sharpen) { 49 if (m_sharpen) {
43 // m_n1 /= 2;
44 m_wlen = 2048; 50 m_wlen = 2048;
45 } 51 }
46 m_n2 = m_n1 * ratio; 52 m_n2 = m_n1 * ratio;
47 } else { 53 } else {
48 if (ratio > 2) { 54 if (ratio > 2) {
53 m_wlen = 2048; 59 m_wlen = 2048;
54 } else { 60 } else {
55 m_n2 = 256; 61 m_n2 = 256;
56 } 62 }
57 if (m_sharpen) { 63 if (m_sharpen) {
58 // m_n2 /= 2;
59 if (m_wlen < 2048) m_wlen = 2048; 64 if (m_wlen < 2048) m_wlen = 2048;
60 } 65 }
61 m_n1 = m_n2 / ratio; 66 m_n1 = m_n2 / ratio;
62 } 67 }
63 68
66 71
67 m_prevPhase = new float *[m_channels]; 72 m_prevPhase = new float *[m_channels];
68 m_prevAdjustedPhase = new float *[m_channels]; 73 m_prevAdjustedPhase = new float *[m_channels];
69 74
70 m_prevTransientMag = (float *)fftwf_malloc(sizeof(float) * (m_wlen / 2 + 1)); 75 m_prevTransientMag = (float *)fftwf_malloc(sizeof(float) * (m_wlen / 2 + 1));
71 m_prevTransientCount = 0; 76 m_prevTransientScore = 0;
72 m_prevTransient = false; 77 m_prevTransient = false;
73 78
74 m_tempbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen); 79 m_tempbuf = (float *)fftwf_malloc(sizeof(float) * m_wlen);
75 80
76 m_time = new float *[m_channels]; 81 m_time = new float *[m_channels];
247 252
248 if (transient) { 253 if (transient) {
249 n2 = m_n1; 254 n2 = m_n1;
250 } 255 }
251 256
257 ++m_totalCount;
258 if (transient) ++m_transientCount;
259 m_n2sum += n2;
260
261 // std::cerr << "ratio for last 10: " <<last10num << "/" << (10 * m_n1) << " = " << float(last10num) / float(10 * m_n1) << " (should be " << m_ratio << ")" << std::endl;
262
263 if (m_totalCount > 50 && m_transientCount < m_totalCount) {
264
265 int fixed = lrintf(m_transientCount * m_n1);
266 int squashy = m_n2sum - fixed;
267
268 int idealTotal = lrintf(m_totalCount * m_n1 * m_ratio);
269 int idealSquashy = idealTotal - fixed;
270
271 int squashyCount = m_totalCount - m_transientCount;
272
273 n2 = lrintf(idealSquashy / squashyCount);
274
275 if (n2 != m_n2) {
276 std::cerr << m_n2 << " -> " << n2 << std::endl;
277 }
278 }
279
252 for (size_t c = 0; c < m_channels; ++c) { 280 for (size_t c = 0; c < m_channels; ++c) {
253 281
254 synthesiseBlock(c, m_mashbuf[c], 282 synthesiseBlock(c, m_mashbuf[c],
255 c == 0 ? m_modulationbuf : 0, 283 c == 0 ? m_modulationbuf : 0,
256 m_prevTransient ? m_n1 : m_n2); 284 m_prevTransient ? m_n1 : m_n2);
285 } 313 }
286 314
287 for (size_t i = m_wlen - n2; i < m_wlen; ++i) { 315 for (size_t i = m_wlen - n2; i < m_wlen; ++i) {
288 m_modulationbuf[i] = 0.0f; 316 m_modulationbuf[i] = 0.0f;
289 } 317 }
318
319 if (!transient) m_n2 = n2;
290 } 320 }
291 321
292 322
293 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER 323 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
294 std::cerr << "loop ended: inbuf read space " << m_inbuf[0]->getReadSpace() << ", outbuf write space " << m_outbuf[0]->getWriteSpace() << std::endl; 324 std::cerr << "loop ended: inbuf read space " << m_inbuf[0]->getReadSpace() << ", outbuf write space " << m_outbuf[0]->getWriteSpace() << std::endl;
296 } 326 }
297 327
298 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER 328 #ifdef DEBUG_PHASE_VOCODER_TIME_STRETCHER
299 std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl; 329 std::cerr << "PhaseVocoderTimeStretcher::putInput returning" << std::endl;
300 #endif 330 #endif
331
332 // std::cerr << "ratio: nominal: " << getRatio() << " actual: "
333 // << m_total2 << "/" << m_total1 << " = " << float(m_total2) / float(m_total1) << " ideal: " << m_ratio << std::endl;
301 } 334 }
302 335
303 size_t 336 size_t
304 PhaseVocoderTimeStretcher::getAvailableOutputSamples() const 337 PhaseVocoderTimeStretcher::getAvailableOutputSamples() const
305 { 338 {
383 } 416 }
384 417
385 bool isTransient = false; 418 bool isTransient = false;
386 419
387 if (count > m_wlen / 4.5 && //!!! 420 if (count > m_wlen / 4.5 && //!!!
388 count > m_prevTransientCount * 1.2) { 421 count > m_prevTransientScore * 1.2) {
389 isTransient = true; 422 isTransient = true;
390 std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientCount << ")" << std::endl; 423 std::cerr << "isTransient (count = " << count << ", prev = " << m_prevTransientScore << ")" << std::endl;
391 } 424 }
392 425
393 m_prevTransientCount = count; 426 m_prevTransientScore = count;
394 427
395 return isTransient; 428 return isTransient;
396 } 429 }
397 430
398 void 431 void