comparison audioio/AudioCallbackPlaySource.cpp @ 101:89a689720ee9 spectrogram-cache-rejig

* Merge from trunk
author Chris Cannam
date Wed, 27 Feb 2008 11:59:42 +0000
parents eb596ef12041
children
comparison
equal deleted inserted replaced
59:bf1a53489ccc 101:89a689720ee9
23 #include "base/Preferences.h" 23 #include "base/Preferences.h"
24 #include "data/model/DenseTimeValueModel.h" 24 #include "data/model/DenseTimeValueModel.h"
25 #include "data/model/WaveFileModel.h" 25 #include "data/model/WaveFileModel.h"
26 #include "data/model/SparseOneDimensionalModel.h" 26 #include "data/model/SparseOneDimensionalModel.h"
27 #include "plugin/RealTimePluginInstance.h" 27 #include "plugin/RealTimePluginInstance.h"
28 #include "PhaseVocoderTimeStretcher.h" 28
29 #include "AudioCallbackPlayTarget.h"
30
31 #include <rubberband/RubberBandStretcher.h>
32 using namespace RubberBand;
29 33
30 #include <iostream> 34 #include <iostream>
31 #include <cassert> 35 #include <cassert>
32 36
33 //#define DEBUG_AUDIO_PLAY_SOURCE 1 37 //#define DEBUG_AUDIO_PLAY_SOURCE 1
48 m_sourceChannelCount(0), 52 m_sourceChannelCount(0),
49 m_blockSize(1024), 53 m_blockSize(1024),
50 m_sourceSampleRate(0), 54 m_sourceSampleRate(0),
51 m_targetSampleRate(0), 55 m_targetSampleRate(0),
52 m_playLatency(0), 56 m_playLatency(0),
57 m_target(0),
58 m_lastRetrievalTimestamp(0.0),
59 m_lastRetrievedBlockSize(0),
53 m_playing(false), 60 m_playing(false),
54 m_exiting(false), 61 m_exiting(false),
55 m_lastModelEndFrame(0), 62 m_lastModelEndFrame(0),
56 m_outputLeft(0.0), 63 m_outputLeft(0.0),
57 m_outputRight(0.0), 64 m_outputRight(0.0),
58 m_auditioningPlugin(0), 65 m_auditioningPlugin(0),
59 m_auditioningPluginBypassed(false), 66 m_auditioningPluginBypassed(false),
67 m_playStartFrame(0),
68 m_playStartFramePassed(false),
60 m_timeStretcher(0), 69 m_timeStretcher(0),
70 m_stretchRatio(1.0),
71 m_stretcherInputCount(0),
72 m_stretcherInputs(0),
73 m_stretcherInputSizes(0),
61 m_fillThread(0), 74 m_fillThread(0),
62 m_converter(0), 75 m_converter(0),
63 m_crapConverter(0), 76 m_crapConverter(0),
64 m_resampleQuality(Preferences::getInstance()->getResampleQuality()) 77 m_resampleQuality(Preferences::getInstance()->getResampleQuality())
65 { 78 {
99 112
100 delete m_writeBuffers; 113 delete m_writeBuffers;
101 114
102 delete m_audioGenerator; 115 delete m_audioGenerator;
103 116
117 for (size_t i = 0; i < m_stretcherInputCount; ++i) {
118 delete[] m_stretcherInputs[i];
119 }
120 delete[] m_stretcherInputSizes;
121 delete[] m_stretcherInputs;
122
104 m_bufferScavenger.scavenge(true); 123 m_bufferScavenger.scavenge(true);
105 m_pluginScavenger.scavenge(true); 124 m_pluginScavenger.scavenge(true);
106 m_timeStretcherScavenger.scavenge(true);
107 } 125 }
108 126
109 void 127 void
110 AudioCallbackPlaySource::addModel(Model *model) 128 AudioCallbackPlaySource::addModel(Model *model)
111 { 129 {
226 AudioCallbackPlaySource::modelChanged(size_t startFrame, size_t endFrame) 244 AudioCallbackPlaySource::modelChanged(size_t startFrame, size_t endFrame)
227 { 245 {
228 #ifdef DEBUG_AUDIO_PLAY_SOURCE 246 #ifdef DEBUG_AUDIO_PLAY_SOURCE
229 std::cerr << "AudioCallbackPlaySource::modelChanged(" << startFrame << "," << endFrame << ")" << std::endl; 247 std::cerr << "AudioCallbackPlaySource::modelChanged(" << startFrame << "," << endFrame << ")" << std::endl;
230 #endif 248 #endif
231 if (endFrame > m_lastModelEndFrame) m_lastModelEndFrame = endFrame; 249 if (endFrame > m_lastModelEndFrame) {
250 m_lastModelEndFrame = endFrame;
251 rebuildRangeLists();
252 }
232 } 253 }
233 254
234 void 255 void
235 AudioCallbackPlaySource::removeModel(Model *model) 256 AudioCallbackPlaySource::removeModel(Model *model)
236 { 257 {
294 m_sourceSampleRate = 0; 315 m_sourceSampleRate = 0;
295 316
296 m_mutex.unlock(); 317 m_mutex.unlock();
297 318
298 m_audioGenerator->clearModels(); 319 m_audioGenerator->clearModels();
320
321 clearRingBuffers();
299 } 322 }
300 323
301 void 324 void
302 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, size_t count) 325 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, size_t count)
303 { 326 {
304 if (!haveLock) m_mutex.lock(); 327 if (!haveLock) m_mutex.lock();
328
329 rebuildRangeLists();
305 330
306 if (count == 0) { 331 if (count == 0) {
307 if (m_writeBuffers) count = m_writeBuffers->size(); 332 if (m_writeBuffers) count = m_writeBuffers->size();
308 } 333 }
309 334
310 size_t sf = m_readBufferFill; 335 m_writeBufferFill = getCurrentBufferedFrame();
311 RingBuffer<float> *rb = getReadRingBuffer(0);
312 if (rb) {
313 //!!! This is incorrect if we're in a non-contiguous selection
314 //Same goes for all related code (subtracting the read space
315 //from the fill frame to try to establish where the effective
316 //pre-resample/timestretch read pointer is)
317 size_t rs = rb->getReadSpace();
318 if (rs < sf) sf -= rs;
319 else sf = 0;
320 }
321 m_writeBufferFill = sf;
322 336
323 if (m_readBuffers != m_writeBuffers) { 337 if (m_readBuffers != m_writeBuffers) {
324 delete m_writeBuffers; 338 delete m_writeBuffers;
325 } 339 }
326 340
341 void 355 void
342 AudioCallbackPlaySource::play(size_t startFrame) 356 AudioCallbackPlaySource::play(size_t startFrame)
343 { 357 {
344 if (m_viewManager->getPlaySelectionMode() && 358 if (m_viewManager->getPlaySelectionMode() &&
345 !m_viewManager->getSelections().empty()) { 359 !m_viewManager->getSelections().empty()) {
346 MultiSelection::SelectionList selections = m_viewManager->getSelections(); 360
347 MultiSelection::SelectionList::iterator i = selections.begin(); 361 std::cerr << "AudioCallbackPlaySource::play: constraining frame " << startFrame << " to selection = ";
348 if (i != selections.end()) { 362
349 if (startFrame < i->getStartFrame()) { 363 startFrame = m_viewManager->constrainFrameToSelection(startFrame);
350 startFrame = i->getStartFrame(); 364
351 } else { 365 std::cerr << startFrame << std::endl;
352 MultiSelection::SelectionList::iterator j = selections.end(); 366
353 --j;
354 if (startFrame >= j->getEndFrame()) {
355 startFrame = i->getStartFrame();
356 }
357 }
358 }
359 } else { 367 } else {
360 if (startFrame >= m_lastModelEndFrame) { 368 if (startFrame >= m_lastModelEndFrame) {
361 startFrame = 0; 369 startFrame = 0;
362 } 370 }
363 } 371 }
364 372
373 std::cerr << "play(" << startFrame << ") -> playback model ";
374
375 startFrame = m_viewManager->alignReferenceToPlaybackFrame(startFrame);
376
377 std::cerr << startFrame << std::endl;
378
365 // The fill thread will automatically empty its buffers before 379 // The fill thread will automatically empty its buffers before
366 // starting again if we have not so far been playing, but not if 380 // starting again if we have not so far been playing, but not if
367 // we're just re-seeking. 381 // we're just re-seeking.
368 382
369 m_mutex.lock(); 383 m_mutex.lock();
384 if (m_timeStretcher) {
385 m_timeStretcher->reset();
386 }
370 if (m_playing) { 387 if (m_playing) {
388 std::cerr << "playing already, resetting" << std::endl;
371 m_readBufferFill = m_writeBufferFill = startFrame; 389 m_readBufferFill = m_writeBufferFill = startFrame;
372 if (m_readBuffers) { 390 if (m_readBuffers) {
373 for (size_t c = 0; c < getTargetChannelCount(); ++c) { 391 for (size_t c = 0; c < getTargetChannelCount(); ++c) {
374 RingBuffer<float> *rb = getReadRingBuffer(c); 392 RingBuffer<float> *rb = getReadRingBuffer(c);
393 std::cerr << "reset ring buffer for channel " << c << std::endl;
375 if (rb) rb->reset(); 394 if (rb) rb->reset();
376 } 395 }
377 } 396 }
378 if (m_converter) src_reset(m_converter); 397 if (m_converter) src_reset(m_converter);
379 if (m_crapConverter) src_reset(m_crapConverter); 398 if (m_crapConverter) src_reset(m_crapConverter);
384 } 403 }
385 m_mutex.unlock(); 404 m_mutex.unlock();
386 405
387 m_audioGenerator->reset(); 406 m_audioGenerator->reset();
388 407
408 m_playStartFrame = startFrame;
409 m_playStartFramePassed = false;
410 m_playStartedAt = RealTime::zeroTime;
411 if (m_target) {
412 m_playStartedAt = RealTime::fromSeconds(m_target->getCurrentTime());
413 }
414
389 bool changed = !m_playing; 415 bool changed = !m_playing;
416 m_lastRetrievalTimestamp = 0;
390 m_playing = true; 417 m_playing = true;
391 m_condition.wakeAll(); 418 m_condition.wakeAll();
392 if (changed) emit playStatusChanged(m_playing); 419 if (changed) emit playStatusChanged(m_playing);
393 } 420 }
394 421
396 AudioCallbackPlaySource::stop() 423 AudioCallbackPlaySource::stop()
397 { 424 {
398 bool changed = m_playing; 425 bool changed = m_playing;
399 m_playing = false; 426 m_playing = false;
400 m_condition.wakeAll(); 427 m_condition.wakeAll();
428 m_lastRetrievalTimestamp = 0;
401 if (changed) emit playStatusChanged(m_playing); 429 if (changed) emit playStatusChanged(m_playing);
402 } 430 }
403 431
404 void 432 void
405 AudioCallbackPlaySource::selectionChanged() 433 AudioCallbackPlaySource::selectionChanged()
446 emit audioOverloadPluginDisabled(); 474 emit audioOverloadPluginDisabled();
447 } 475 }
448 } 476 }
449 477
450 void 478 void
451 AudioCallbackPlaySource::setTargetBlockSize(size_t size) 479 AudioCallbackPlaySource::setTarget(AudioCallbackPlayTarget *target, size_t size)
452 { 480 {
481 m_target = target;
453 // std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; 482 // std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
454 assert(size < m_ringBufferSize); 483 assert(size < m_ringBufferSize);
455 m_blockSize = size; 484 m_blockSize = size;
456 } 485 }
457 486
475 } 504 }
476 505
477 size_t 506 size_t
478 AudioCallbackPlaySource::getCurrentPlayingFrame() 507 AudioCallbackPlaySource::getCurrentPlayingFrame()
479 { 508 {
509 // This method attempts to estimate which audio sample frame is
510 // "currently coming through the speakers".
511
512 size_t targetRate = getTargetSampleRate();
513 size_t latency = m_playLatency; // at target rate
514 RealTime latency_t = RealTime::frame2RealTime(latency, targetRate);
515
516 return getCurrentFrame(latency_t);
517 }
518
519 size_t
520 AudioCallbackPlaySource::getCurrentBufferedFrame()
521 {
522 return getCurrentFrame(RealTime::zeroTime);
523 }
524
525 size_t
526 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t)
527 {
480 bool resample = false; 528 bool resample = false;
481 double ratio = 1.0; 529 double resampleRatio = 1.0;
482 530
483 if (getSourceSampleRate() != getTargetSampleRate()) { 531 // We resample when filling the ring buffer, and time-stretch when
484 resample = true; 532 // draining it. The buffer contains data at the "target rate" and
485 ratio = double(getSourceSampleRate()) / double(getTargetSampleRate()); 533 // the latency provided by the target is also at the target rate.
486 } 534 // Because of the multiple rates involved, we do the actual
487 535 // calculation using RealTime instead.
488 size_t readSpace = 0; 536
537 size_t sourceRate = getSourceSampleRate();
538 size_t targetRate = getTargetSampleRate();
539
540 if (sourceRate == 0 || targetRate == 0) return 0;
541
542 size_t inbuffer = 0; // at target rate
543
489 for (size_t c = 0; c < getTargetChannelCount(); ++c) { 544 for (size_t c = 0; c < getTargetChannelCount(); ++c) {
490 RingBuffer<float> *rb = getReadRingBuffer(c); 545 RingBuffer<float> *rb = getReadRingBuffer(c);
491 if (rb) { 546 if (rb) {
492 size_t spaceHere = rb->getReadSpace(); 547 size_t here = rb->getReadSpace();
493 if (c == 0 || spaceHere < readSpace) readSpace = spaceHere; 548 if (c == 0 || here < inbuffer) inbuffer = here;
494 } 549 }
495 } 550 }
496 551
497 if (resample) { 552 size_t readBufferFill = m_readBufferFill;
498 readSpace = size_t(readSpace * ratio + 0.1); 553 size_t lastRetrievedBlockSize = m_lastRetrievedBlockSize;
499 } 554 double lastRetrievalTimestamp = m_lastRetrievalTimestamp;
500 555 double currentTime = 0.0;
501 size_t latency = m_playLatency; 556 if (m_target) currentTime = m_target->getCurrentTime();
502 if (resample) latency = size_t(m_playLatency * ratio + 0.1); 557
503 558 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate);
504 PhaseVocoderTimeStretcher *timeStretcher = m_timeStretcher; 559
505 if (timeStretcher) { 560 size_t stretchlat = 0;
506 latency += timeStretcher->getProcessingLatency(); 561 double timeRatio = 1.0;
507 } 562
508 563 if (m_timeStretcher) {
509 latency += readSpace; 564 stretchlat = m_timeStretcher->getLatency();
510 size_t bufferedFrame = m_readBufferFill; 565 timeRatio = m_timeStretcher->getTimeRatio();
566 }
567
568 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate);
569
570 // When the target has just requested a block from us, the last
571 // sample it obtained was our buffer fill frame count minus the
572 // amount of read space (converted back to source sample rate)
573 // remaining now. That sample is not expected to be played until
574 // the target's play latency has elapsed. By the time the
575 // following block is requested, that sample will be at the
576 // target's play latency minus the last requested block size away
577 // from being played.
578
579 RealTime sincerequest_t = RealTime::zeroTime;
580 RealTime lastretrieved_t = RealTime::zeroTime;
581
582 if (m_target && lastRetrievalTimestamp != 0.0) {
583
584 lastretrieved_t = RealTime::frame2RealTime
585 (lastRetrievedBlockSize, targetRate);
586
587 // calculate number of frames at target rate that have elapsed
588 // since the end of the last call to getSourceSamples
589
590 double elapsed = currentTime - lastRetrievalTimestamp;
591
592 if (elapsed > 0.0) {
593 sincerequest_t = RealTime::fromSeconds(elapsed);
594 }
595
596 } else {
597
598 lastretrieved_t = RealTime::frame2RealTime
599 (getTargetBlockSize(), targetRate);
600 }
601
602 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, sourceRate);
603
604 if (timeRatio != 1.0) {
605 lastretrieved_t = lastretrieved_t / timeRatio;
606 sincerequest_t = sincerequest_t / timeRatio;
607 }
511 608
512 bool looping = m_viewManager->getPlayLoopMode(); 609 bool looping = m_viewManager->getPlayLoopMode();
513 bool constrained = (m_viewManager->getPlaySelectionMode() && 610
514 !m_viewManager->getSelections().empty()); 611 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
515 612 std::cerr << "\nbuffered to: " << bufferedto_t << ", in buffer: " << inbuffer_t << ", time ratio " << timeRatio << "\n stretcher latency: " << stretchlat_t << ", device latency: " << latency_t << "\n since request: " << sincerequest_t << ", last retrieved: " << lastretrieved_t << std::endl;
516 size_t framePlaying = bufferedFrame; 613 #endif
517 614
518 if (looping && !constrained) { 615 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
519 while (framePlaying < latency) framePlaying += m_lastModelEndFrame; 616
520 } 617 // Normally the range lists should contain at least one item each
521 618 // -- if playback is unconstrained, that item should report the
522 if (framePlaying > latency) framePlaying -= latency; 619 // entire source audio duration.
523 else framePlaying = 0; 620
621 if (m_rangeStarts.empty()) {
622 rebuildRangeLists();
623 }
624
625 if (m_rangeStarts.empty()) {
626 // this code is only used in case of error in rebuildRangeLists
627 RealTime playing_t = bufferedto_t
628 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
629 + sincerequest_t;
630 size_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
631 return m_viewManager->alignPlaybackFrameToReference(frame);
632 }
633
634 int inRange = 0;
635 int index = 0;
636
637 for (size_t i = 0; i < m_rangeStarts.size(); ++i) {
638 if (bufferedto_t >= m_rangeStarts[i]) {
639 inRange = index;
640 } else {
641 break;
642 }
643 ++index;
644 }
645
646 if (inRange >= m_rangeStarts.size()) inRange = m_rangeStarts.size()-1;
647
648 RealTime playing_t = bufferedto_t;
649
650 playing_t = playing_t
651 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
652 + sincerequest_t;
653
654 // This rather gross little hack is used to ensure that latency
655 // compensation doesn't result in the playback pointer appearing
656 // to start earlier than the actual playback does. It doesn't
657 // work properly (hence the bail-out in the middle) because if we
658 // are playing a relatively short looped region, the playing time
659 // estimated from the buffer fill frame may have wrapped around
660 // the region boundary and end up being much smaller than the
661 // theoretical play start frame, perhaps even for the entire
662 // duration of playback!
663
664 if (!m_playStartFramePassed) {
665 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame,
666 sourceRate);
667 if (playing_t < playstart_t) {
668 // std::cerr << "playing_t " << playing_t << " < playstart_t "
669 // << playstart_t << std::endl;
670 if (sincerequest_t > RealTime::zeroTime &&
671 m_playStartedAt + latency_t + stretchlat_t <
672 RealTime::fromSeconds(currentTime)) {
673 // std::cerr << "but we've been playing for long enough that I think we should disregard it (it probably results from loop wrapping)" << std::endl;
674 m_playStartFramePassed = true;
675 } else {
676 playing_t = playstart_t;
677 }
678 } else {
679 m_playStartFramePassed = true;
680 }
681 }
682
683 playing_t = playing_t - m_rangeStarts[inRange];
684
685 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
686 std::cerr << "playing_t as offset into range " << inRange << " (with start = " << m_rangeStarts[inRange] << ") = " << playing_t << std::endl;
687 #endif
688
689 while (playing_t < RealTime::zeroTime) {
690
691 if (inRange == 0) {
692 if (looping) {
693 inRange = m_rangeStarts.size() - 1;
694 } else {
695 break;
696 }
697 } else {
698 --inRange;
699 }
700
701 playing_t = playing_t + m_rangeDurations[inRange];
702 }
703
704 playing_t = playing_t + m_rangeStarts[inRange];
705
706 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
707 std::cerr << " playing time: " << playing_t << std::endl;
708 #endif
709
710 if (!looping) {
711 if (inRange == m_rangeStarts.size()-1 &&
712 playing_t >= m_rangeStarts[inRange] + m_rangeDurations[inRange]) {
713 std::cerr << "Not looping, inRange " << inRange << " == rangeStarts.size()-1, playing_t " << playing_t << " >= m_rangeStarts[inRange] " << m_rangeStarts[inRange] << " + m_rangeDurations[inRange] " << m_rangeDurations[inRange] << " -- stopping" << std::endl;
714 stop();
715 }
716 }
717
718 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
719
720 size_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
721 return m_viewManager->alignPlaybackFrameToReference(frame);
722 }
723
724 void
725 AudioCallbackPlaySource::rebuildRangeLists()
726 {
727 bool constrained = (m_viewManager->getPlaySelectionMode());
728
729 m_rangeStarts.clear();
730 m_rangeDurations.clear();
731
732 size_t sourceRate = getSourceSampleRate();
733 if (sourceRate == 0) return;
734
735 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
736 if (end == RealTime::zeroTime) return;
524 737
525 if (!constrained) { 738 if (!constrained) {
526 if (!looping && framePlaying > m_lastModelEndFrame) { 739 m_rangeStarts.push_back(RealTime::zeroTime);
527 framePlaying = m_lastModelEndFrame; 740 m_rangeDurations.push_back(end);
528 stop(); 741 return;
529 }
530 return framePlaying;
531 } 742 }
532 743
533 MultiSelection::SelectionList selections = m_viewManager->getSelections(); 744 MultiSelection::SelectionList selections = m_viewManager->getSelections();
534 MultiSelection::SelectionList::const_iterator i; 745 MultiSelection::SelectionList::const_iterator i;
535 746
536 // i = selections.begin(); 747 #ifdef DEBUG_AUDIO_PLAY_SOURCE
537 // size_t rangeStart = i->getStartFrame(); 748 std::cerr << "AudioCallbackPlaySource::rebuildRangeLists" << std::endl;
538 749 #endif
539 i = selections.end(); 750
540 --i; 751 if (!selections.empty()) {
541 size_t rangeEnd = i->getEndFrame(); 752
542 753 for (i = selections.begin(); i != selections.end(); ++i) {
543 for (i = selections.begin(); i != selections.end(); ++i) { 754
544 if (i->contains(bufferedFrame)) break; 755 RealTime start =
545 } 756 (RealTime::frame2RealTime
546 757 (m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
547 size_t f = bufferedFrame; 758 sourceRate));
548 759 RealTime duration =
549 // std::cout << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl; 760 (RealTime::frame2RealTime
550 761 (m_viewManager->alignReferenceToPlaybackFrame(i->getEndFrame()) -
551 if (i == selections.end()) { 762 m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
552 --i; 763 sourceRate));
553 if (i->getEndFrame() + latency < f) { 764
554 // std::cout << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl; 765 m_rangeStarts.push_back(start);
555 766 m_rangeDurations.push_back(duration);
556 if (!looping && (framePlaying > rangeEnd)) { 767 }
557 // std::cout << "STOPPING" << std::endl; 768 } else {
558 stop(); 769 m_rangeStarts.push_back(RealTime::zeroTime);
559 return rangeEnd; 770 m_rangeDurations.push_back(end);
560 } else { 771 }
561 return framePlaying; 772
562 } 773 #ifdef DEBUG_AUDIO_PLAY_SOURCE
563 } else { 774 std::cerr << "Now have " << m_rangeStarts.size() << " play ranges" << std::endl;
564 // std::cout << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl; 775 #endif
565 latency -= (f - i->getEndFrame());
566 f = i->getEndFrame();
567 }
568 }
569
570 // std::cout << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl;
571
572 while (latency > 0) {
573 size_t offset = f - i->getStartFrame();
574 if (offset >= latency) {
575 if (f > latency) {
576 framePlaying = f - latency;
577 } else {
578 framePlaying = 0;
579 }
580 break;
581 } else {
582 if (i == selections.begin()) {
583 if (looping) {
584 i = selections.end();
585 }
586 }
587 latency -= offset;
588 --i;
589 f = i->getEndFrame();
590 }
591 }
592
593 return framePlaying;
594 } 776 }
595 777
596 void 778 void
597 AudioCallbackPlaySource::setOutputLevels(float left, float right) 779 AudioCallbackPlaySource::setOutputLevels(float left, float right)
598 { 780 {
738 { 920 {
739 return m_sourceSampleRate; 921 return m_sourceSampleRate;
740 } 922 }
741 923
742 void 924 void
743 AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono) 925 AudioCallbackPlaySource::setTimeStretch(float factor)
744 { 926 {
745 // Avoid locks -- create, assign, mark old one for scavenging 927 m_stretchRatio = factor;
746 // later (as a call to getSourceSamples may still be using it) 928
747 929 if (m_timeStretcher || (factor == 1.f)) {
748 PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher; 930 // stretch ratio will be set in next process call if appropriate
749 931 return;
750 size_t channels = getTargetChannelCount();
751 if (mono) channels = 1;
752
753 if (existingStretcher &&
754 existingStretcher->getRatio() == factor &&
755 existingStretcher->getSharpening() == sharpen &&
756 existingStretcher->getChannelCount() == channels) {
757 return;
758 }
759
760 if (factor != 1) {
761
762 if (existingStretcher &&
763 existingStretcher->getSharpening() == sharpen &&
764 existingStretcher->getChannelCount() == channels) {
765 existingStretcher->setRatio(factor);
766 return;
767 }
768
769 PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher
770 (getTargetSampleRate(),
771 channels,
772 factor,
773 sharpen,
774 getTargetBlockSize());
775
776 m_timeStretcher = newStretcher;
777
778 } else { 932 } else {
779 m_timeStretcher = 0; 933 m_stretcherInputCount = getTargetChannelCount();
780 } 934 RubberBandStretcher *stretcher = new RubberBandStretcher
781 935 (getTargetSampleRate(),
782 if (existingStretcher) { 936 m_stretcherInputCount,
783 m_timeStretcherScavenger.claim(existingStretcher); 937 RubberBandStretcher::OptionProcessRealTime,
938 factor);
939 m_stretcherInputs = new float *[m_stretcherInputCount];
940 m_stretcherInputSizes = new size_t[m_stretcherInputCount];
941 for (size_t c = 0; c < m_stretcherInputCount; ++c) {
942 m_stretcherInputSizes[c] = 16384;
943 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
944 }
945 m_timeStretcher = stretcher;
946 return;
784 } 947 }
785 } 948 }
786 949
787 size_t 950 size_t
788 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) 951 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer)
823 } 986 }
824 } 987 }
825 988
826 if (count == 0) return 0; 989 if (count == 0) return 0;
827 990
828 PhaseVocoderTimeStretcher *ts = m_timeStretcher; 991 RubberBandStretcher *ts = m_timeStretcher;
829 992 float ratio = ts ? ts->getTimeRatio() : 1.f;
830 if (!ts || ts->getRatio() == 1) { 993
994 if (ratio != m_stretchRatio) {
995 if (!ts) {
996 std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << std::endl;
997 m_stretchRatio = 1.f;
998 } else {
999 ts->setTimeRatio(m_stretchRatio);
1000 }
1001 }
1002
1003 if (m_target) {
1004 m_lastRetrievedBlockSize = count;
1005 m_lastRetrievalTimestamp = m_target->getCurrentTime();
1006 }
1007
1008 if (!ts || ratio == 1.f) {
831 1009
832 size_t got = 0; 1010 size_t got = 0;
833 1011
834 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) { 1012 for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
835 1013
857 } 1035 }
858 1036
859 applyAuditioningEffect(count, buffer); 1037 applyAuditioningEffect(count, buffer);
860 1038
861 m_condition.wakeAll(); 1039 m_condition.wakeAll();
1040
862 return got; 1041 return got;
863 } 1042 }
864 1043
865 float ratio = ts->getRatio();
866
867 // std::cout << "ratio = " << ratio << std::endl;
868
869 size_t channels = getTargetChannelCount(); 1044 size_t channels = getTargetChannelCount();
870 bool mix = (channels > 1 && ts->getChannelCount() == 1);
871
872 size_t available; 1045 size_t available;
873
874 int warned = 0; 1046 int warned = 0;
875 1047 size_t fedToStretcher = 0;
876 // We want output blocks of e.g. 1024 (probably fixed, certainly 1048
877 // bounded). We can provide input blocks of any size (unbounded) 1049 // The input block for a given output is approx output / ratio,
878 // at the timestretcher's request. The input block for a given 1050 // but we can't predict it exactly, for an adaptive timestretcher.
879 // output is approx output / ratio, but we can't predict it 1051
880 // exactly, for an adaptive timestretcher. The stretcher will 1052 while ((available = ts->available()) < count) {
881 // need some additional buffer space. See the time stretcher code
882 // and comments.
883
884 while ((available = ts->getAvailableOutputSamples()) < count) {
885 1053
886 size_t reqd = lrintf((count - available) / ratio); 1054 size_t reqd = lrintf((count - available) / ratio);
887 reqd = std::max(reqd, ts->getRequiredInputSamples()); 1055 reqd = std::max(reqd, ts->getSamplesRequired());
888 if (reqd == 0) reqd = 1; 1056 if (reqd == 0) reqd = 1;
889 1057
890 float *ib[channels];
891
892 size_t got = reqd; 1058 size_t got = reqd;
893 1059
894 if (mix) { 1060 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
895 for (size_t c = 0; c < channels; ++c) { 1061 std::cerr << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << std::endl;
896 if (c == 0) ib[c] = new float[reqd]; //!!! fix -- this is a rt function 1062 #endif
897 else ib[c] = 0; 1063
898 RingBuffer<float> *rb = getReadRingBuffer(c); 1064 for (size_t c = 0; c < channels; ++c) {
899 if (rb) { 1065 if (c >= m_stretcherInputCount) continue;
900 size_t gotHere; 1066 if (reqd > m_stretcherInputSizes[c]) {
901 if (c > 0) gotHere = rb->readAdding(ib[0], got); 1067 if (c == 0) {
902 else gotHere = rb->read(ib[0], got); 1068 std::cerr << "WARNING: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << std::endl;
903 if (gotHere < got) got = gotHere;
904 } 1069 }
1070 delete[] m_stretcherInputs[c];
1071 m_stretcherInputSizes[c] = reqd * 2;
1072 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
905 } 1073 }
906 } else { 1074 }
907 for (size_t c = 0; c < channels; ++c) { 1075
908 ib[c] = new float[reqd]; //!!! fix -- this is a rt function 1076 for (size_t c = 0; c < channels; ++c) {
909 RingBuffer<float> *rb = getReadRingBuffer(c); 1077 if (c >= m_stretcherInputCount) continue;
910 if (rb) { 1078 RingBuffer<float> *rb = getReadRingBuffer(c);
911 size_t gotHere = rb->read(ib[c], got); 1079 if (rb) {
912 if (gotHere < got) got = gotHere; 1080 size_t gotHere = rb->read(m_stretcherInputs[c], got);
1081 if (gotHere < got) got = gotHere;
1082
1083 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
1084 if (c == 0) {
1085 std::cerr << "feeding stretcher: got " << gotHere
1086 << ", " << rb->getReadSpace() << " remain" << std::endl;
913 } 1087 }
1088 #endif
1089
1090 } else {
1091 std::cerr << "WARNING: No ring buffer available for channel " << c << " in stretcher input block" << std::endl;
914 } 1092 }
915 } 1093 }
916 1094
917 if (got < reqd) { 1095 if (got < reqd) {
918 std::cerr << "WARNING: Read underrun in playback (" 1096 std::cerr << "WARNING: Read underrun in playback ("
919 << got << " < " << reqd << ")" << std::endl; 1097 << got << " < " << reqd << ")" << std::endl;
920 } 1098 }
921 1099
922 ts->putInput(ib, got); 1100 ts->process(m_stretcherInputs, got, false);
923 1101
924 for (size_t c = 0; c < channels; ++c) { 1102 fedToStretcher += got;
925 delete[] ib[c];
926 }
927 1103
928 if (got == 0) break; 1104 if (got == 0) break;
929 1105
930 if (ts->getAvailableOutputSamples() == available) { 1106 if (ts->available() == available) {
931 std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << std::endl; 1107 std::cerr << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << std::endl;
932 if (++warned == 5) break; 1108 if (++warned == 5) break;
933 } 1109 }
934 } 1110 }
935 1111
936 ts->getOutput(buffer, count); 1112 ts->retrieve(buffer, count);
937
938 if (mix) {
939 for (size_t c = 1; c < channels; ++c) {
940 for (size_t i = 0; i < count; ++i) {
941 buffer[c][i] = buffer[0][i] / channels;
942 }
943 }
944 for (size_t i = 0; i < count; ++i) {
945 buffer[0][i] /= channels;
946 }
947 }
948 1113
949 applyAuditioningEffect(count, buffer); 1114 applyAuditioningEffect(count, buffer);
950 1115
951 m_condition.wakeAll(); 1116 m_condition.wakeAll();
952 1117
1118 data.src_ratio = ratio; 1283 data.src_ratio = ratio;
1119 data.end_of_input = 0; 1284 data.end_of_input = 0;
1120 1285
1121 int err = 0; 1286 int err = 0;
1122 1287
1123 if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) { 1288 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) {
1124 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1289 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1125 std::cout << "Using crappy converter" << std::endl; 1290 std::cout << "Using crappy converter" << std::endl;
1126 #endif 1291 #endif
1127 err = src_process(m_crapConverter, &data); 1292 err = src_process(m_crapConverter, &data);
1128 } else { 1293 } else {
1157 1322
1158 } else { 1323 } else {
1159 1324
1160 // space must be a multiple of generatorBlockSize 1325 // space must be a multiple of generatorBlockSize
1161 space = (space / generatorBlockSize) * generatorBlockSize; 1326 space = (space / generatorBlockSize) * generatorBlockSize;
1162 if (space == 0) return false; 1327 if (space == 0) {
1328 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1329 std::cout << "requested fill is less than generator block size of "
1330 << generatorBlockSize << ", leaving it" << std::endl;
1331 #endif
1332 return false;
1333 }
1163 1334
1164 if (tmpSize < channels * space) { 1335 if (tmpSize < channels * space) {
1165 delete[] tmp; 1336 delete[] tmp;
1166 tmp = new float[channels * space]; 1337 tmp = new float[channels * space];
1167 tmpSize = channels * space; 1338 tmpSize = channels * space;
1243 selectionSize = 0; 1414 selectionSize = 0;
1244 1415
1245 size_t fadeIn = 0, fadeOut = 0; 1416 size_t fadeIn = 0, fadeOut = 0;
1246 1417
1247 if (constrained) { 1418 if (constrained) {
1419
1420 size_t rChunkStart =
1421 m_viewManager->alignPlaybackFrameToReference(chunkStart);
1248 1422
1249 Selection selection = 1423 Selection selection =
1250 m_viewManager->getContainingSelection(chunkStart, true); 1424 m_viewManager->getContainingSelection(rChunkStart, true);
1251 1425
1252 if (selection.isEmpty()) { 1426 if (selection.isEmpty()) {
1253 if (looping) { 1427 if (looping) {
1254 selection = *m_viewManager->getSelections().begin(); 1428 selection = *m_viewManager->getSelections().begin();
1255 chunkStart = selection.getStartFrame(); 1429 chunkStart = m_viewManager->alignReferenceToPlaybackFrame
1430 (selection.getStartFrame());
1256 fadeIn = 50; 1431 fadeIn = 50;
1257 } 1432 }
1258 } 1433 }
1259 1434
1260 if (selection.isEmpty()) { 1435 if (selection.isEmpty()) {
1262 chunkSize = 0; 1437 chunkSize = 0;
1263 nextChunkStart = chunkStart; 1438 nextChunkStart = chunkStart;
1264 1439
1265 } else { 1440 } else {
1266 1441
1267 selectionSize = 1442 size_t sf = m_viewManager->alignReferenceToPlaybackFrame
1268 selection.getEndFrame() - 1443 (selection.getStartFrame());
1269 selection.getStartFrame(); 1444 size_t ef = m_viewManager->alignReferenceToPlaybackFrame
1270 1445 (selection.getEndFrame());
1271 if (chunkStart < selection.getStartFrame()) { 1446
1272 chunkStart = selection.getStartFrame(); 1447 selectionSize = ef - sf;
1448
1449 if (chunkStart < sf) {
1450 chunkStart = sf;
1273 fadeIn = 50; 1451 fadeIn = 50;
1274 } 1452 }
1275 1453
1276 nextChunkStart = chunkStart + chunkSize; 1454 nextChunkStart = chunkStart + chunkSize;
1277 1455
1278 if (nextChunkStart >= selection.getEndFrame()) { 1456 if (nextChunkStart >= ef) {
1279 nextChunkStart = selection.getEndFrame(); 1457 nextChunkStart = ef;
1280 fadeOut = 50; 1458 fadeOut = 50;
1281 } 1459 }
1282 1460
1283 chunkSize = nextChunkStart - chunkStart; 1461 chunkSize = nextChunkStart - chunkStart;
1284 } 1462 }
1436 while (!s.m_exiting) { 1614 while (!s.m_exiting) {
1437 1615
1438 s.unifyRingBuffers(); 1616 s.unifyRingBuffers();
1439 s.m_bufferScavenger.scavenge(); 1617 s.m_bufferScavenger.scavenge();
1440 s.m_pluginScavenger.scavenge(); 1618 s.m_pluginScavenger.scavenge();
1441 s.m_timeStretcherScavenger.scavenge();
1442 1619
1443 if (work && s.m_playing && s.getSourceSampleRate()) { 1620 if (work && s.m_playing && s.getSourceSampleRate()) {
1444 1621
1445 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1622 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1446 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl; 1623 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl;