comparison audioio/AudioCallbackPlaySource.cpp @ 100:22bf057ea151 1.2-stable

* merge from trunk (1.2 ended up being tracked from trunk, but we may want this branch for fixes later)
author Chris Cannam
date Wed, 27 Feb 2008 10:32:45 +0000
parents ae2627ac7db2
children
comparison
equal deleted inserted replaced
71:a8acc7841d70 100:22bf057ea151
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 28
29 #ifdef HAVE_RUBBERBAND 29 #include "AudioCallbackPlayTarget.h"
30
30 #include <rubberband/RubberBandStretcher.h> 31 #include <rubberband/RubberBandStretcher.h>
31 using namespace RubberBand; 32 using namespace RubberBand;
32 #else
33 #include "PhaseVocoderTimeStretcher.h"
34 #endif
35 33
36 #include <iostream> 34 #include <iostream>
37 #include <cassert> 35 #include <cassert>
38 36
39 //#define DEBUG_AUDIO_PLAY_SOURCE 1 37 //#define DEBUG_AUDIO_PLAY_SOURCE 1
54 m_sourceChannelCount(0), 52 m_sourceChannelCount(0),
55 m_blockSize(1024), 53 m_blockSize(1024),
56 m_sourceSampleRate(0), 54 m_sourceSampleRate(0),
57 m_targetSampleRate(0), 55 m_targetSampleRate(0),
58 m_playLatency(0), 56 m_playLatency(0),
57 m_target(0),
58 m_lastRetrievalTimestamp(0.0),
59 m_lastRetrievedBlockSize(0),
59 m_playing(false), 60 m_playing(false),
60 m_exiting(false), 61 m_exiting(false),
61 m_lastModelEndFrame(0), 62 m_lastModelEndFrame(0),
62 m_outputLeft(0.0), 63 m_outputLeft(0.0),
63 m_outputRight(0.0), 64 m_outputRight(0.0),
64 m_auditioningPlugin(0), 65 m_auditioningPlugin(0),
65 m_auditioningPluginBypassed(false), 66 m_auditioningPluginBypassed(false),
67 m_playStartFrame(0),
68 m_playStartFramePassed(false),
66 m_timeStretcher(0), 69 m_timeStretcher(0),
70 m_stretchRatio(1.0),
71 m_stretcherInputCount(0),
72 m_stretcherInputs(0),
73 m_stretcherInputSizes(0),
67 m_fillThread(0), 74 m_fillThread(0),
68 m_converter(0), 75 m_converter(0),
69 m_crapConverter(0), 76 m_crapConverter(0),
70 m_resampleQuality(Preferences::getInstance()->getResampleQuality()) 77 m_resampleQuality(Preferences::getInstance()->getResampleQuality())
71 { 78 {
105 112
106 delete m_writeBuffers; 113 delete m_writeBuffers;
107 114
108 delete m_audioGenerator; 115 delete m_audioGenerator;
109 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
110 m_bufferScavenger.scavenge(true); 123 m_bufferScavenger.scavenge(true);
111 m_pluginScavenger.scavenge(true); 124 m_pluginScavenger.scavenge(true);
112 #ifndef HAVE_RUBBERBAND
113 m_timeStretcherScavenger.scavenge(true);
114 #endif
115 } 125 }
116 126
117 void 127 void
118 AudioCallbackPlaySource::addModel(Model *model) 128 AudioCallbackPlaySource::addModel(Model *model)
119 { 129 {
234 AudioCallbackPlaySource::modelChanged(size_t startFrame, size_t endFrame) 244 AudioCallbackPlaySource::modelChanged(size_t startFrame, size_t endFrame)
235 { 245 {
236 #ifdef DEBUG_AUDIO_PLAY_SOURCE 246 #ifdef DEBUG_AUDIO_PLAY_SOURCE
237 std::cerr << "AudioCallbackPlaySource::modelChanged(" << startFrame << "," << endFrame << ")" << std::endl; 247 std::cerr << "AudioCallbackPlaySource::modelChanged(" << startFrame << "," << endFrame << ")" << std::endl;
238 #endif 248 #endif
239 if (endFrame > m_lastModelEndFrame) m_lastModelEndFrame = endFrame; 249 if (endFrame > m_lastModelEndFrame) {
250 m_lastModelEndFrame = endFrame;
251 rebuildRangeLists();
252 }
240 } 253 }
241 254
242 void 255 void
243 AudioCallbackPlaySource::removeModel(Model *model) 256 AudioCallbackPlaySource::removeModel(Model *model)
244 { 257 {
302 m_sourceSampleRate = 0; 315 m_sourceSampleRate = 0;
303 316
304 m_mutex.unlock(); 317 m_mutex.unlock();
305 318
306 m_audioGenerator->clearModels(); 319 m_audioGenerator->clearModels();
320
321 clearRingBuffers();
307 } 322 }
308 323
309 void 324 void
310 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, size_t count) 325 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, size_t count)
311 { 326 {
312 if (!haveLock) m_mutex.lock(); 327 if (!haveLock) m_mutex.lock();
328
329 rebuildRangeLists();
313 330
314 if (count == 0) { 331 if (count == 0) {
315 if (m_writeBuffers) count = m_writeBuffers->size(); 332 if (m_writeBuffers) count = m_writeBuffers->size();
316 } 333 }
317 334
318 size_t sf = m_readBufferFill; 335 m_writeBufferFill = getCurrentBufferedFrame();
319 RingBuffer<float> *rb = getReadRingBuffer(0);
320 if (rb) {
321 //!!! This is incorrect if we're in a non-contiguous selection
322 //Same goes for all related code (subtracting the read space
323 //from the fill frame to try to establish where the effective
324 //pre-resample/timestretch read pointer is)
325 size_t rs = rb->getReadSpace();
326 if (rs < sf) sf -= rs;
327 else sf = 0;
328 }
329 m_writeBufferFill = sf;
330 336
331 if (m_readBuffers != m_writeBuffers) { 337 if (m_readBuffers != m_writeBuffers) {
332 delete m_writeBuffers; 338 delete m_writeBuffers;
333 } 339 }
334 340
350 AudioCallbackPlaySource::play(size_t startFrame) 356 AudioCallbackPlaySource::play(size_t startFrame)
351 { 357 {
352 if (m_viewManager->getPlaySelectionMode() && 358 if (m_viewManager->getPlaySelectionMode() &&
353 !m_viewManager->getSelections().empty()) { 359 !m_viewManager->getSelections().empty()) {
354 360
361 std::cerr << "AudioCallbackPlaySource::play: constraining frame " << startFrame << " to selection = ";
362
355 startFrame = m_viewManager->constrainFrameToSelection(startFrame); 363 startFrame = m_viewManager->constrainFrameToSelection(startFrame);
364
365 std::cerr << startFrame << std::endl;
356 366
357 } else { 367 } else {
358 if (startFrame >= m_lastModelEndFrame) { 368 if (startFrame >= m_lastModelEndFrame) {
359 startFrame = 0; 369 startFrame = 0;
360 } 370 }
369 // The fill thread will automatically empty its buffers before 379 // The fill thread will automatically empty its buffers before
370 // 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
371 // we're just re-seeking. 381 // we're just re-seeking.
372 382
373 m_mutex.lock(); 383 m_mutex.lock();
384 if (m_timeStretcher) {
385 m_timeStretcher->reset();
386 }
374 if (m_playing) { 387 if (m_playing) {
388 std::cerr << "playing already, resetting" << std::endl;
375 m_readBufferFill = m_writeBufferFill = startFrame; 389 m_readBufferFill = m_writeBufferFill = startFrame;
376 if (m_readBuffers) { 390 if (m_readBuffers) {
377 for (size_t c = 0; c < getTargetChannelCount(); ++c) { 391 for (size_t c = 0; c < getTargetChannelCount(); ++c) {
378 RingBuffer<float> *rb = getReadRingBuffer(c); 392 RingBuffer<float> *rb = getReadRingBuffer(c);
393 std::cerr << "reset ring buffer for channel " << c << std::endl;
379 if (rb) rb->reset(); 394 if (rb) rb->reset();
380 } 395 }
381 } 396 }
382 if (m_converter) src_reset(m_converter); 397 if (m_converter) src_reset(m_converter);
383 if (m_crapConverter) src_reset(m_crapConverter); 398 if (m_crapConverter) src_reset(m_crapConverter);
388 } 403 }
389 m_mutex.unlock(); 404 m_mutex.unlock();
390 405
391 m_audioGenerator->reset(); 406 m_audioGenerator->reset();
392 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
393 bool changed = !m_playing; 415 bool changed = !m_playing;
416 m_lastRetrievalTimestamp = 0;
394 m_playing = true; 417 m_playing = true;
395 m_condition.wakeAll(); 418 m_condition.wakeAll();
396 if (changed) emit playStatusChanged(m_playing); 419 if (changed) emit playStatusChanged(m_playing);
397 } 420 }
398 421
400 AudioCallbackPlaySource::stop() 423 AudioCallbackPlaySource::stop()
401 { 424 {
402 bool changed = m_playing; 425 bool changed = m_playing;
403 m_playing = false; 426 m_playing = false;
404 m_condition.wakeAll(); 427 m_condition.wakeAll();
428 m_lastRetrievalTimestamp = 0;
405 if (changed) emit playStatusChanged(m_playing); 429 if (changed) emit playStatusChanged(m_playing);
406 } 430 }
407 431
408 void 432 void
409 AudioCallbackPlaySource::selectionChanged() 433 AudioCallbackPlaySource::selectionChanged()
450 emit audioOverloadPluginDisabled(); 474 emit audioOverloadPluginDisabled();
451 } 475 }
452 } 476 }
453 477
454 void 478 void
455 AudioCallbackPlaySource::setTargetBlockSize(size_t size) 479 AudioCallbackPlaySource::setTarget(AudioCallbackPlayTarget *target, size_t size)
456 { 480 {
481 m_target = target;
457 // std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; 482 // std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
458 assert(size < m_ringBufferSize); 483 assert(size < m_ringBufferSize);
459 m_blockSize = size; 484 m_blockSize = size;
460 } 485 }
461 486
479 } 504 }
480 505
481 size_t 506 size_t
482 AudioCallbackPlaySource::getCurrentPlayingFrame() 507 AudioCallbackPlaySource::getCurrentPlayingFrame()
483 { 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 {
484 bool resample = false; 528 bool resample = false;
485 double ratio = 1.0; 529 double resampleRatio = 1.0;
486 530
487 if (getSourceSampleRate() != getTargetSampleRate()) { 531 // We resample when filling the ring buffer, and time-stretch when
488 resample = true; 532 // draining it. The buffer contains data at the "target rate" and
489 ratio = double(getSourceSampleRate()) / double(getTargetSampleRate()); 533 // the latency provided by the target is also at the target rate.
490 } 534 // Because of the multiple rates involved, we do the actual
491 535 // calculation using RealTime instead.
492 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
493 for (size_t c = 0; c < getTargetChannelCount(); ++c) { 544 for (size_t c = 0; c < getTargetChannelCount(); ++c) {
494 RingBuffer<float> *rb = getReadRingBuffer(c); 545 RingBuffer<float> *rb = getReadRingBuffer(c);
495 if (rb) { 546 if (rb) {
496 size_t spaceHere = rb->getReadSpace(); 547 size_t here = rb->getReadSpace();
497 if (c == 0 || spaceHere < readSpace) readSpace = spaceHere; 548 if (c == 0 || here < inbuffer) inbuffer = here;
498 } 549 }
499 } 550 }
500 551
501 if (resample) { 552 size_t readBufferFill = m_readBufferFill;
502 readSpace = size_t(readSpace * ratio + 0.1); 553 size_t lastRetrievedBlockSize = m_lastRetrievedBlockSize;
503 } 554 double lastRetrievalTimestamp = m_lastRetrievalTimestamp;
504 555 double currentTime = 0.0;
505 size_t latency = m_playLatency; 556 if (m_target) currentTime = m_target->getCurrentTime();
506 if (resample) latency = size_t(m_playLatency * ratio + 0.1); 557
507 558 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate);
508 #ifdef HAVE_RUBBERBAND 559
560 size_t stretchlat = 0;
561 double timeRatio = 1.0;
562
509 if (m_timeStretcher) { 563 if (m_timeStretcher) {
510 latency += m_timeStretcher->getLatency(); 564 stretchlat = m_timeStretcher->getLatency();
511 } 565 timeRatio = m_timeStretcher->getTimeRatio();
512 #else 566 }
513 PhaseVocoderTimeStretcher *timeStretcher = m_timeStretcher; 567
514 if (timeStretcher) { 568 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate);
515 latency += timeStretcher->getProcessingLatency(); 569
516 } 570 // When the target has just requested a block from us, the last
517 #endif 571 // sample it obtained was our buffer fill frame count minus the
518 572 // amount of read space (converted back to source sample rate)
519 latency += readSpace; 573 // remaining now. That sample is not expected to be played until
520 size_t bufferedFrame = m_readBufferFill; 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 }
521 608
522 bool looping = m_viewManager->getPlayLoopMode(); 609 bool looping = m_viewManager->getPlayLoopMode();
523 bool constrained = (m_viewManager->getPlaySelectionMode() && 610
524 !m_viewManager->getSelections().empty()); 611 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
525 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;
526 size_t framePlaying = bufferedFrame; 613 #endif
527 614
528 if (looping && !constrained) { 615 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
529 while (framePlaying < latency) framePlaying += m_lastModelEndFrame; 616
530 } 617 // Normally the range lists should contain at least one item each
531 618 // -- if playback is unconstrained, that item should report the
532 if (framePlaying > latency) framePlaying -= latency; 619 // entire source audio duration.
533 else framePlaying = 0; 620
534 621 if (m_rangeStarts.empty()) {
535 // std::cerr << "framePlaying = " << framePlaying << " -> reference "; 622 rebuildRangeLists();
536 623 }
537 framePlaying = m_viewManager->alignPlaybackFrameToReference(framePlaying); 624
538 625 if (m_rangeStarts.empty()) {
539 // std::cerr << framePlaying << std::endl; 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;
540 737
541 if (!constrained) { 738 if (!constrained) {
542 if (!looping && framePlaying > m_lastModelEndFrame) { 739 m_rangeStarts.push_back(RealTime::zeroTime);
543 framePlaying = m_lastModelEndFrame; 740 m_rangeDurations.push_back(end);
544 stop(); 741 return;
545 } 742 }
546 return framePlaying;
547 }
548
549 bufferedFrame = m_viewManager->alignPlaybackFrameToReference(bufferedFrame);
550 743
551 MultiSelection::SelectionList selections = m_viewManager->getSelections(); 744 MultiSelection::SelectionList selections = m_viewManager->getSelections();
552 MultiSelection::SelectionList::const_iterator i; 745 MultiSelection::SelectionList::const_iterator i;
553 746
554 // i = selections.begin(); 747 #ifdef DEBUG_AUDIO_PLAY_SOURCE
555 // size_t rangeStart = i->getStartFrame(); 748 std::cerr << "AudioCallbackPlaySource::rebuildRangeLists" << std::endl;
556 749 #endif
557 i = selections.end(); 750
558 --i; 751 if (!selections.empty()) {
559 size_t rangeEnd = i->getEndFrame(); 752
560 753 for (i = selections.begin(); i != selections.end(); ++i) {
561 for (i = selections.begin(); i != selections.end(); ++i) { 754
562 if (i->contains(bufferedFrame)) break; 755 RealTime start =
563 } 756 (RealTime::frame2RealTime
564 757 (m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
565 size_t f = bufferedFrame; 758 sourceRate));
566 759 RealTime duration =
567 // std::cout << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl; 760 (RealTime::frame2RealTime
568 761 (m_viewManager->alignReferenceToPlaybackFrame(i->getEndFrame()) -
569 if (i == selections.end()) { 762 m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
570 --i; 763 sourceRate));
571 if (i->getEndFrame() + latency < f) { 764
572 // std::cout << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl; 765 m_rangeStarts.push_back(start);
573 766 m_rangeDurations.push_back(duration);
574 if (!looping && (framePlaying > rangeEnd)) { 767 }
575 // std::cout << "STOPPING" << std::endl; 768 } else {
576 stop(); 769 m_rangeStarts.push_back(RealTime::zeroTime);
577 return rangeEnd; 770 m_rangeDurations.push_back(end);
578 } else { 771 }
579 return framePlaying; 772
580 } 773 #ifdef DEBUG_AUDIO_PLAY_SOURCE
581 } else { 774 std::cerr << "Now have " << m_rangeStarts.size() << " play ranges" << std::endl;
582 // std::cout << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl; 775 #endif
583 latency -= (f - i->getEndFrame());
584 f = i->getEndFrame();
585 }
586 }
587
588 // std::cout << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl;
589
590 while (latency > 0) {
591 size_t offset = f - i->getStartFrame();
592 if (offset >= latency) {
593 if (f > latency) {
594 framePlaying = f - latency;
595 } else {
596 framePlaying = 0;
597 }
598 break;
599 } else {
600 if (i == selections.begin()) {
601 if (looping) {
602 i = selections.end();
603 }
604 }
605 latency -= offset;
606 --i;
607 f = i->getEndFrame();
608 }
609 }
610
611 return framePlaying;
612 } 776 }
613 777
614 void 778 void
615 AudioCallbackPlaySource::setOutputLevels(float left, float right) 779 AudioCallbackPlaySource::setOutputLevels(float left, float right)
616 { 780 {
756 { 920 {
757 return m_sourceSampleRate; 921 return m_sourceSampleRate;
758 } 922 }
759 923
760 void 924 void
761 AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono) 925 AudioCallbackPlaySource::setTimeStretch(float factor)
762 { 926 {
763 #ifdef HAVE_RUBBERBAND 927 m_stretchRatio = factor;
764 if (m_timeStretcher) { 928
765 m_timeStretchRatioMutex.lock(); 929 if (m_timeStretcher || (factor == 1.f)) {
766 m_timeStretcher->setTimeRatio(factor); 930 // stretch ratio will be set in next process call if appropriate
767 m_timeStretchRatioMutex.unlock();
768 return; 931 return;
769 } else { 932 } else {
933 m_stretcherInputCount = getTargetChannelCount();
770 RubberBandStretcher *stretcher = new RubberBandStretcher 934 RubberBandStretcher *stretcher = new RubberBandStretcher
771 (getTargetSampleRate(), 935 (getTargetSampleRate(),
772 getTargetChannelCount(), 936 m_stretcherInputCount,
773 RubberBandStretcher::OptionProcessRealTime, 937 RubberBandStretcher::OptionProcessRealTime,
774 factor); 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 }
775 m_timeStretcher = stretcher; 945 m_timeStretcher = stretcher;
776 return; 946 return;
777 } 947 }
778 #else
779 // Avoid locks -- create, assign, mark old one for scavenging
780 // later (as a call to getSourceSamples may still be using it)
781
782 PhaseVocoderTimeStretcher *existingStretcher = m_timeStretcher;
783
784 size_t channels = getTargetChannelCount();
785 if (mono) channels = 1;
786
787 if (existingStretcher &&
788 existingStretcher->getRatio() == factor &&
789 existingStretcher->getSharpening() == sharpen &&
790 existingStretcher->getChannelCount() == channels) {
791 return;
792 }
793
794 if (factor != 1) {
795
796 if (existingStretcher &&
797 existingStretcher->getSharpening() == sharpen &&
798 existingStretcher->getChannelCount() == channels) {
799 existingStretcher->setRatio(factor);
800 return;
801 }
802
803 PhaseVocoderTimeStretcher *newStretcher = new PhaseVocoderTimeStretcher
804 (getTargetSampleRate(),
805 channels,
806 factor,
807 sharpen,
808 getTargetBlockSize());
809
810 m_timeStretcher = newStretcher;
811
812 } else {
813 m_timeStretcher = 0;
814 }
815
816 if (existingStretcher) {
817 m_timeStretcherScavenger.claim(existingStretcher);
818 }
819 #endif
820 } 948 }
821 949
822 size_t 950 size_t
823 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) 951 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer)
824 { 952 {
858 } 986 }
859 } 987 }
860 988
861 if (count == 0) return 0; 989 if (count == 0) return 0;
862 990
863 #ifdef HAVE_RUBBERBAND
864 RubberBandStretcher *ts = m_timeStretcher; 991 RubberBandStretcher *ts = m_timeStretcher;
865 float ratio = ts ? ts->getTimeRatio() : 1.f; 992 float ratio = ts ? ts->getTimeRatio() : 1.f;
866 #else 993
867 PhaseVocoderTimeStretcher *ts = m_timeStretcher; 994 if (ratio != m_stretchRatio) {
868 float ratio = ts ? ts->getRatio() : 1.f; 995 if (!ts) {
869 #endif 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 }
870 1007
871 if (!ts || ratio == 1.f) { 1008 if (!ts || ratio == 1.f) {
872 1009
873 size_t got = 0; 1010 size_t got = 0;
874 1011
898 } 1035 }
899 1036
900 applyAuditioningEffect(count, buffer); 1037 applyAuditioningEffect(count, buffer);
901 1038
902 m_condition.wakeAll(); 1039 m_condition.wakeAll();
1040
903 return got; 1041 return got;
904 } 1042 }
905 1043
906 size_t channels = getTargetChannelCount(); 1044 size_t channels = getTargetChannelCount();
907
908 #ifdef HAVE_RUBBERBAND
909 bool mix = false;
910 #else
911 bool mix = (channels > 1 && ts->getChannelCount() == 1);
912 #endif
913
914 size_t available; 1045 size_t available;
915
916 int warned = 0; 1046 int warned = 0;
917 1047 size_t fedToStretcher = 0;
918 // We want output blocks of e.g. 1024 (probably fixed, certainly 1048
919 // bounded). We can provide input blocks of any size (unbounded) 1049 // The input block for a given output is approx output / ratio,
920 // at the timestretcher's request. The input block for a given 1050 // but we can't predict it exactly, for an adaptive timestretcher.
921 // output is approx output / ratio, but we can't predict it 1051
922 // exactly, for an adaptive timestretcher. The stretcher will
923 // need some additional buffer space. See the time stretcher code
924 // and comments.
925
926 #ifdef HAVE_RUBBERBAND
927 m_timeStretchRatioMutex.lock();
928 while ((available = ts->available()) < count) { 1052 while ((available = ts->available()) < count) {
929 #else
930 while ((available = ts->getAvailableOutputSamples()) < count) {
931 #endif
932 1053
933 size_t reqd = lrintf((count - available) / ratio); 1054 size_t reqd = lrintf((count - available) / ratio);
934 #ifdef HAVE_RUBBERBAND
935 reqd = std::max(reqd, ts->getSamplesRequired()); 1055 reqd = std::max(reqd, ts->getSamplesRequired());
936 #else
937 reqd = std::max(reqd, ts->getRequiredInputSamples());
938 #endif
939 if (reqd == 0) reqd = 1; 1056 if (reqd == 0) reqd = 1;
940 1057
941 float *ib[channels];
942
943 size_t got = reqd; 1058 size_t got = reqd;
944 1059
945 if (mix) { 1060 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
946 for (size_t c = 0; c < channels; ++c) { 1061 std::cerr << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << std::endl;
947 if (c == 0) ib[c] = new float[reqd]; //!!! fix -- this is a rt function 1062 #endif
948 else ib[c] = 0; 1063
949 RingBuffer<float> *rb = getReadRingBuffer(c); 1064 for (size_t c = 0; c < channels; ++c) {
950 if (rb) { 1065 if (c >= m_stretcherInputCount) continue;
951 size_t gotHere; 1066 if (reqd > m_stretcherInputSizes[c]) {
952 if (c > 0) gotHere = rb->readAdding(ib[0], got); 1067 if (c == 0) {
953 else gotHere = rb->read(ib[0], got); 1068 std::cerr << "WARNING: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << std::endl;
954 if (gotHere < got) got = gotHere;
955 } 1069 }
1070 delete[] m_stretcherInputs[c];
1071 m_stretcherInputSizes[c] = reqd * 2;
1072 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
956 } 1073 }
957 } else { 1074 }
958 for (size_t c = 0; c < channels; ++c) { 1075
959 ib[c] = new float[reqd]; //!!! fix -- this is a rt function 1076 for (size_t c = 0; c < channels; ++c) {
960 RingBuffer<float> *rb = getReadRingBuffer(c); 1077 if (c >= m_stretcherInputCount) continue;
961 if (rb) { 1078 RingBuffer<float> *rb = getReadRingBuffer(c);
962 size_t gotHere = rb->read(ib[c], got); 1079 if (rb) {
963 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;
964 } 1087 }
1088 #endif
1089
1090 } else {
1091 std::cerr << "WARNING: No ring buffer available for channel " << c << " in stretcher input block" << std::endl;
965 } 1092 }
966 } 1093 }
967 1094
968 if (got < reqd) { 1095 if (got < reqd) {
969 std::cerr << "WARNING: Read underrun in playback (" 1096 std::cerr << "WARNING: Read underrun in playback ("
970 << got << " < " << reqd << ")" << std::endl; 1097 << got << " < " << reqd << ")" << std::endl;
971 } 1098 }
972 1099
973 #ifdef HAVE_RUBBERBAND 1100 ts->process(m_stretcherInputs, got, false);
974 ts->process(ib, got, false); 1101
975 #else 1102 fedToStretcher += got;
976 ts->putInput(ib, got);
977 #endif
978
979 for (size_t c = 0; c < channels; ++c) {
980 delete[] ib[c];
981 }
982 1103
983 if (got == 0) break; 1104 if (got == 0) break;
984 1105
985 #ifdef HAVE_RUBBERBAND
986 if (ts->available() == available) { 1106 if (ts->available() == available) {
987 #else
988 if (ts->getAvailableOutputSamples() == available) {
989 #endif
990 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;
991 if (++warned == 5) break; 1108 if (++warned == 5) break;
992 } 1109 }
993 } 1110 }
994 1111
995 #ifdef HAVE_RUBBERBAND
996 ts->retrieve(buffer, count); 1112 ts->retrieve(buffer, count);
997 m_timeStretchRatioMutex.unlock();
998 #else
999 ts->getOutput(buffer, count);
1000 #endif
1001
1002 if (mix) {
1003 for (size_t c = 1; c < channels; ++c) {
1004 for (size_t i = 0; i < count; ++i) {
1005 buffer[c][i] = buffer[0][i] / channels;
1006 }
1007 }
1008 for (size_t i = 0; i < count; ++i) {
1009 buffer[0][i] /= channels;
1010 }
1011 }
1012 1113
1013 applyAuditioningEffect(count, buffer); 1114 applyAuditioningEffect(count, buffer);
1014 1115
1015 m_condition.wakeAll(); 1116 m_condition.wakeAll();
1016 1117
1182 data.src_ratio = ratio; 1283 data.src_ratio = ratio;
1183 data.end_of_input = 0; 1284 data.end_of_input = 0;
1184 1285
1185 int err = 0; 1286 int err = 0;
1186 1287
1187 #ifdef HAVE_RUBBERBAND
1188 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) { 1288 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) {
1189 #else
1190 if (m_timeStretcher && m_timeStretcher->getRatio() < 0.4) {
1191 #endif
1192 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1289 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1193 std::cout << "Using crappy converter" << std::endl; 1290 std::cout << "Using crappy converter" << std::endl;
1194 #endif 1291 #endif
1195 err = src_process(m_crapConverter, &data); 1292 err = src_process(m_crapConverter, &data);
1196 } else { 1293 } else {
1225 1322
1226 } else { 1323 } else {
1227 1324
1228 // space must be a multiple of generatorBlockSize 1325 // space must be a multiple of generatorBlockSize
1229 space = (space / generatorBlockSize) * generatorBlockSize; 1326 space = (space / generatorBlockSize) * generatorBlockSize;
1230 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 }
1231 1334
1232 if (tmpSize < channels * space) { 1335 if (tmpSize < channels * space) {
1233 delete[] tmp; 1336 delete[] tmp;
1234 tmp = new float[channels * space]; 1337 tmp = new float[channels * space];
1235 tmpSize = channels * space; 1338 tmpSize = channels * space;
1511 while (!s.m_exiting) { 1614 while (!s.m_exiting) {
1512 1615
1513 s.unifyRingBuffers(); 1616 s.unifyRingBuffers();
1514 s.m_bufferScavenger.scavenge(); 1617 s.m_bufferScavenger.scavenge();
1515 s.m_pluginScavenger.scavenge(); 1618 s.m_pluginScavenger.scavenge();
1516 #ifndef HAVE_RUBBERBAND
1517 s.m_timeStretcherScavenger.scavenge();
1518 #endif
1519 1619
1520 if (work && s.m_playing && s.getSourceSampleRate()) { 1620 if (work && s.m_playing && s.getSourceSampleRate()) {
1521 1621
1522 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1622 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1523 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl; 1623 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl;