comparison audioio/AudioCallbackPlaySource.cpp @ 91:9fc4b256c283

* PortAudio driver: do not specify frames per buffer, let PA decide * Remove old non-RubberBand time stretcher -- it doesn't work with varying buffer sizes such as the PA driver may now be using * Rewrite getCurrentPlayingFrame for greater correctness when using long buffer sizes (interpolating according to audio stream timestamp) * Several changes to make the timestretch management RT safe(r)
author Chris Cannam
date Fri, 08 Feb 2008 17:51:15 +0000
parents ae2627ac7db2
children 792bca285459
comparison
equal deleted inserted replaced
90:db267a315058 91:9fc4b256c283
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),
66 m_timeStretcher(0), 67 m_timeStretcher(0),
68 m_stretchRatio(1.0),
69 m_stretcherInputCount(0),
70 m_stretcherInputs(0),
71 m_stretcherInputSizes(0),
67 m_fillThread(0), 72 m_fillThread(0),
68 m_converter(0), 73 m_converter(0),
69 m_crapConverter(0), 74 m_crapConverter(0),
70 m_resampleQuality(Preferences::getInstance()->getResampleQuality()) 75 m_resampleQuality(Preferences::getInstance()->getResampleQuality())
71 { 76 {
105 110
106 delete m_writeBuffers; 111 delete m_writeBuffers;
107 112
108 delete m_audioGenerator; 113 delete m_audioGenerator;
109 114
115 for (size_t i = 0; i < m_stretcherInputCount; ++i) {
116 delete[] m_stretcherInputs[i];
117 }
118 delete[] m_stretcherInputSizes;
119 delete[] m_stretcherInputs;
120
110 m_bufferScavenger.scavenge(true); 121 m_bufferScavenger.scavenge(true);
111 m_pluginScavenger.scavenge(true); 122 m_pluginScavenger.scavenge(true);
112 #ifndef HAVE_RUBBERBAND
113 m_timeStretcherScavenger.scavenge(true);
114 #endif
115 } 123 }
116 124
117 void 125 void
118 AudioCallbackPlaySource::addModel(Model *model) 126 AudioCallbackPlaySource::addModel(Model *model)
119 { 127 {
369 // The fill thread will automatically empty its buffers before 377 // The fill thread will automatically empty its buffers before
370 // starting again if we have not so far been playing, but not if 378 // starting again if we have not so far been playing, but not if
371 // we're just re-seeking. 379 // we're just re-seeking.
372 380
373 m_mutex.lock(); 381 m_mutex.lock();
382 if (m_timeStretcher) {
383 m_timeStretcher->reset();
384 }
374 if (m_playing) { 385 if (m_playing) {
375 m_readBufferFill = m_writeBufferFill = startFrame; 386 m_readBufferFill = m_writeBufferFill = startFrame;
376 if (m_readBuffers) { 387 if (m_readBuffers) {
377 for (size_t c = 0; c < getTargetChannelCount(); ++c) { 388 for (size_t c = 0; c < getTargetChannelCount(); ++c) {
378 RingBuffer<float> *rb = getReadRingBuffer(c); 389 RingBuffer<float> *rb = getReadRingBuffer(c);
389 m_mutex.unlock(); 400 m_mutex.unlock();
390 401
391 m_audioGenerator->reset(); 402 m_audioGenerator->reset();
392 403
393 bool changed = !m_playing; 404 bool changed = !m_playing;
405 m_lastRetrievalTimestamp = 0;
394 m_playing = true; 406 m_playing = true;
395 m_condition.wakeAll(); 407 m_condition.wakeAll();
396 if (changed) emit playStatusChanged(m_playing); 408 if (changed) emit playStatusChanged(m_playing);
397 } 409 }
398 410
400 AudioCallbackPlaySource::stop() 412 AudioCallbackPlaySource::stop()
401 { 413 {
402 bool changed = m_playing; 414 bool changed = m_playing;
403 m_playing = false; 415 m_playing = false;
404 m_condition.wakeAll(); 416 m_condition.wakeAll();
417 m_lastRetrievalTimestamp = 0;
405 if (changed) emit playStatusChanged(m_playing); 418 if (changed) emit playStatusChanged(m_playing);
406 } 419 }
407 420
408 void 421 void
409 AudioCallbackPlaySource::selectionChanged() 422 AudioCallbackPlaySource::selectionChanged()
450 emit audioOverloadPluginDisabled(); 463 emit audioOverloadPluginDisabled();
451 } 464 }
452 } 465 }
453 466
454 void 467 void
455 AudioCallbackPlaySource::setTargetBlockSize(size_t size) 468 AudioCallbackPlaySource::setTarget(AudioCallbackPlayTarget *target, size_t size)
456 { 469 {
470 m_target = target;
457 // std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; 471 // std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
458 assert(size < m_ringBufferSize); 472 assert(size < m_ringBufferSize);
459 m_blockSize = size; 473 m_blockSize = size;
460 } 474 }
461 475
479 } 493 }
480 494
481 size_t 495 size_t
482 AudioCallbackPlaySource::getCurrentPlayingFrame() 496 AudioCallbackPlaySource::getCurrentPlayingFrame()
483 { 497 {
498 // This method attempts to estimate which audio sample frame is
499 // "currently coming through the speakers".
500
484 bool resample = false; 501 bool resample = false;
485 double ratio = 1.0; 502 double resampleRatio = 1.0;
486 503
487 if (getSourceSampleRate() != getTargetSampleRate()) { 504 // We resample when filling the ring buffer, and time-stretch when
488 resample = true; 505 // draining it. The buffer contains data at the "target rate" and
489 ratio = double(getSourceSampleRate()) / double(getTargetSampleRate()); 506 // the latency provided by the target is also at the target rate.
490 } 507 // Because of the multiple rates involved, we do the actual
491 508 // calculation using RealTime instead.
492 size_t readSpace = 0; 509
510 size_t sourceRate = getSourceSampleRate();
511 size_t targetRate = getTargetSampleRate();
512
513 if (sourceRate == 0 || targetRate == 0) return 0;
514
515 size_t inbuffer = 0; // at target rate
516
493 for (size_t c = 0; c < getTargetChannelCount(); ++c) { 517 for (size_t c = 0; c < getTargetChannelCount(); ++c) {
494 RingBuffer<float> *rb = getReadRingBuffer(c); 518 RingBuffer<float> *rb = getReadRingBuffer(c);
495 if (rb) { 519 if (rb) {
496 size_t spaceHere = rb->getReadSpace(); 520 size_t here = rb->getReadSpace();
497 if (c == 0 || spaceHere < readSpace) readSpace = spaceHere; 521 if (c == 0 || here < inbuffer) inbuffer = here;
498 } 522 }
499 } 523 }
500 524
501 if (resample) { 525 size_t readBufferFill = m_readBufferFill;
502 readSpace = size_t(readSpace * ratio + 0.1); 526 size_t lastRetrievedBlockSize = m_lastRetrievedBlockSize;
503 } 527 double lastRetrievalTimestamp = m_lastRetrievalTimestamp;
504 528 double currentTime = 0.0;
505 size_t latency = m_playLatency; 529 if (m_target) currentTime = m_target->getCurrentTime();
506 if (resample) latency = size_t(m_playLatency * ratio + 0.1); 530
507 531 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate);
508 #ifdef HAVE_RUBBERBAND 532
533 size_t latency = m_playLatency; // at target rate
534 RealTime latency_t = RealTime::frame2RealTime(latency, targetRate);
535
536 size_t stretchlat = 0;
537 double timeRatio = 1.0;
538
509 if (m_timeStretcher) { 539 if (m_timeStretcher) {
510 latency += m_timeStretcher->getLatency(); 540 stretchlat = m_timeStretcher->getLatency();
511 } 541 timeRatio = m_timeStretcher->getTimeRatio();
512 #else 542 }
513 PhaseVocoderTimeStretcher *timeStretcher = m_timeStretcher; 543
514 if (timeStretcher) { 544 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate);
515 latency += timeStretcher->getProcessingLatency(); 545
516 } 546 // When the target has just requested a block from us, the last
517 #endif 547 // sample it obtained was our buffer fill frame count minus the
518 548 // amount of read space (converted back to source sample rate)
519 latency += readSpace; 549 // remaining now. That sample is not expected to be played until
520 size_t bufferedFrame = m_readBufferFill; 550 // the target's play latency has elapsed. By the time the
551 // following block is requested, that sample will be at the
552 // target's play latency minus the last requested block size away
553 // from being played.
554
555 RealTime sincerequest_t = RealTime::zeroTime;
556 RealTime lastretrieved_t = RealTime::zeroTime;
557
558 if (m_target && lastRetrievalTimestamp != 0.0) {
559
560 lastretrieved_t = RealTime::frame2RealTime
561 (lastRetrievedBlockSize, targetRate);
562
563 // calculate number of frames at target rate that have elapsed
564 // since the end of the last call to getSourceSamples
565
566 double elapsed = currentTime - lastRetrievalTimestamp;
567
568 if (elapsed > 0.0) {
569 sincerequest_t = RealTime::fromSeconds(elapsed);
570 }
571
572 } else {
573
574 lastretrieved_t = RealTime::frame2RealTime
575 (getTargetBlockSize(), targetRate);
576 }
577
578 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, sourceRate);
579
580 if (timeRatio != 1.0) {
581 lastretrieved_t = lastretrieved_t / timeRatio;
582 sincerequest_t = sincerequest_t / timeRatio;
583 }
521 584
522 bool looping = m_viewManager->getPlayLoopMode(); 585 bool looping = m_viewManager->getPlayLoopMode();
523 bool constrained = (m_viewManager->getPlaySelectionMode() && 586 bool constrained = (m_viewManager->getPlaySelectionMode() &&
524 !m_viewManager->getSelections().empty()); 587 !m_viewManager->getSelections().empty());
525 588
526 size_t framePlaying = bufferedFrame; 589 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
527 590 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;
528 if (looping && !constrained) { 591 #endif
529 while (framePlaying < latency) framePlaying += m_lastModelEndFrame; 592
530 } 593 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate);
531
532 if (framePlaying > latency) framePlaying -= latency;
533 else framePlaying = 0;
534
535 // std::cerr << "framePlaying = " << framePlaying << " -> reference ";
536
537 framePlaying = m_viewManager->alignPlaybackFrameToReference(framePlaying);
538
539 // std::cerr << framePlaying << std::endl;
540
541 if (!constrained) {
542 if (!looping && framePlaying > m_lastModelEndFrame) {
543 framePlaying = m_lastModelEndFrame;
544 stop();
545 }
546 return framePlaying;
547 }
548
549 bufferedFrame = m_viewManager->alignPlaybackFrameToReference(bufferedFrame);
550 594
551 MultiSelection::SelectionList selections = m_viewManager->getSelections(); 595 MultiSelection::SelectionList selections = m_viewManager->getSelections();
552 MultiSelection::SelectionList::const_iterator i; 596 MultiSelection::SelectionList::const_iterator i;
553 597
554 // i = selections.begin(); 598 // these could be cached from one call to the next, if the
555 // size_t rangeStart = i->getStartFrame(); 599 // selection has not changed... but some of the work would still
556 600 // need to be done because the playback model may have changed
557 i = selections.end(); 601
558 --i; 602 std::vector<RealTime> rangeStarts;
559 size_t rangeEnd = i->getEndFrame(); 603 std::vector<RealTime> rangeDurations;
560 604
561 for (i = selections.begin(); i != selections.end(); ++i) { 605 int inRange = 0;
562 if (i->contains(bufferedFrame)) break; 606 int index = 0;
563 } 607
564 608 if (constrained) {
565 size_t f = bufferedFrame; 609
566 610 for (i = selections.begin(); i != selections.end(); ++i) {
567 // std::cout << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl; 611
568 612 RealTime start =
569 if (i == selections.end()) { 613 (RealTime::frame2RealTime
570 --i; 614 (m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
571 if (i->getEndFrame() + latency < f) { 615 sourceRate));
572 // std::cout << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl; 616 RealTime duration =
573 617 (RealTime::frame2RealTime
574 if (!looping && (framePlaying > rangeEnd)) { 618 (m_viewManager->alignReferenceToPlaybackFrame(i->getEndFrame()) -
575 // std::cout << "STOPPING" << std::endl; 619 m_viewManager->alignReferenceToPlaybackFrame(i->getStartFrame()),
576 stop(); 620 sourceRate));
577 return rangeEnd; 621
578 } else { 622 rangeStarts.push_back(start);
579 return framePlaying; 623 rangeDurations.push_back(duration);
580 } 624
581 } else { 625 if (bufferedto_t >= start) {
582 // std::cout << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl; 626 inRange = index;
583 latency -= (f - i->getEndFrame()); 627 }
584 f = i->getEndFrame(); 628
585 } 629 ++index;
586 } 630 }
587 631 }
588 // std::cout << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl; 632
589 633 if (rangeStarts.empty()) {
590 while (latency > 0) { 634 rangeStarts.push_back(RealTime::zeroTime);
591 size_t offset = f - i->getStartFrame(); 635 rangeDurations.push_back(end);
592 if (offset >= latency) { 636 }
593 if (f > latency) { 637
594 framePlaying = f - latency; 638 if (inRange >= rangeStarts.size()) inRange = rangeStarts.size()-1;
595 } else { 639
596 framePlaying = 0; 640 RealTime playing_t = bufferedto_t - rangeStarts[inRange];
597 } 641
598 break; 642 playing_t = playing_t
599 } else { 643 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
600 if (i == selections.begin()) { 644 + sincerequest_t;
601 if (looping) { 645
602 i = selections.end(); 646 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
603 } 647 std::cerr << "playing_t as offset into range " << inRange << " (with start = " << rangeStarts[inRange] << ") = " << playing_t << std::endl;
604 } 648 #endif
605 latency -= offset; 649
606 --i; 650 while (playing_t < RealTime::zeroTime) {
607 f = i->getEndFrame(); 651
608 } 652 if (inRange == 0) {
609 } 653 if (looping) {
610 654 inRange = rangeStarts.size() - 1;
611 return framePlaying; 655 } else {
656 break;
657 }
658 } else {
659 --inRange;
660 }
661
662 playing_t = playing_t + rangeDurations[inRange];
663 }
664
665 playing_t = playing_t + rangeStarts[inRange];
666
667 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
668 std::cerr << " playing time: " << playing_t << std::endl;
669 #endif
670
671 if (!looping) {
672 if (inRange == rangeStarts.size()-1 &&
673 playing_t >= rangeStarts[inRange] + rangeDurations[inRange]) {
674 stop();
675 }
676 }
677
678 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
679
680 size_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
681 return m_viewManager->alignPlaybackFrameToReference(frame);
612 } 682 }
613 683
614 void 684 void
615 AudioCallbackPlaySource::setOutputLevels(float left, float right) 685 AudioCallbackPlaySource::setOutputLevels(float left, float right)
616 { 686 {
756 { 826 {
757 return m_sourceSampleRate; 827 return m_sourceSampleRate;
758 } 828 }
759 829
760 void 830 void
761 AudioCallbackPlaySource::setTimeStretch(float factor, bool sharpen, bool mono) 831 AudioCallbackPlaySource::setTimeStretch(float factor)
762 { 832 {
763 #ifdef HAVE_RUBBERBAND 833 m_stretchRatio = factor;
764 if (m_timeStretcher) { 834
765 m_timeStretchRatioMutex.lock(); 835 if (m_timeStretcher || (factor == 1.f)) {
766 m_timeStretcher->setTimeRatio(factor); 836 // stretch ratio will be set in next process call if appropriate
767 m_timeStretchRatioMutex.unlock();
768 return; 837 return;
769 } else { 838 } else {
839 m_stretcherInputCount = getTargetChannelCount();
770 RubberBandStretcher *stretcher = new RubberBandStretcher 840 RubberBandStretcher *stretcher = new RubberBandStretcher
771 (getTargetSampleRate(), 841 (getTargetSampleRate(),
772 getTargetChannelCount(), 842 m_stretcherInputCount,
773 RubberBandStretcher::OptionProcessRealTime, 843 RubberBandStretcher::OptionProcessRealTime,
774 factor); 844 factor);
845 m_stretcherInputs = new float *[m_stretcherInputCount];
846 m_stretcherInputSizes = new size_t[m_stretcherInputCount];
847 for (size_t c = 0; c < m_stretcherInputCount; ++c) {
848 m_stretcherInputSizes[c] = 16384;
849 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
850 }
775 m_timeStretcher = stretcher; 851 m_timeStretcher = stretcher;
776 return; 852 return;
777 } 853 }
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 } 854 }
821 855
822 size_t 856 size_t
823 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer) 857 AudioCallbackPlaySource::getSourceSamples(size_t count, float **buffer)
824 { 858 {
858 } 892 }
859 } 893 }
860 894
861 if (count == 0) return 0; 895 if (count == 0) return 0;
862 896
863 #ifdef HAVE_RUBBERBAND
864 RubberBandStretcher *ts = m_timeStretcher; 897 RubberBandStretcher *ts = m_timeStretcher;
865 float ratio = ts ? ts->getTimeRatio() : 1.f; 898 float ratio = ts ? ts->getTimeRatio() : 1.f;
866 #else 899
867 PhaseVocoderTimeStretcher *ts = m_timeStretcher; 900 if (ratio != m_stretchRatio) {
868 float ratio = ts ? ts->getRatio() : 1.f; 901 if (!ts) {
869 #endif 902 std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << std::endl;
903 m_stretchRatio = 1.f;
904 } else {
905 ts->setTimeRatio(m_stretchRatio);
906 }
907 }
908
909 if (m_target) {
910 m_lastRetrievedBlockSize = count;
911 m_lastRetrievalTimestamp = m_target->getCurrentTime();
912 }
870 913
871 if (!ts || ratio == 1.f) { 914 if (!ts || ratio == 1.f) {
872 915
873 size_t got = 0; 916 size_t got = 0;
874 917
898 } 941 }
899 942
900 applyAuditioningEffect(count, buffer); 943 applyAuditioningEffect(count, buffer);
901 944
902 m_condition.wakeAll(); 945 m_condition.wakeAll();
946
903 return got; 947 return got;
904 } 948 }
905 949
906 size_t channels = getTargetChannelCount(); 950 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; 951 size_t available;
915
916 int warned = 0; 952 int warned = 0;
917 953 size_t fedToStretcher = 0;
918 // We want output blocks of e.g. 1024 (probably fixed, certainly 954
919 // bounded). We can provide input blocks of any size (unbounded) 955 // The input block for a given output is approx output / ratio,
920 // at the timestretcher's request. The input block for a given 956 // but we can't predict it exactly, for an adaptive timestretcher.
921 // output is approx output / ratio, but we can't predict it 957
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) { 958 while ((available = ts->available()) < count) {
929 #else
930 while ((available = ts->getAvailableOutputSamples()) < count) {
931 #endif
932 959
933 size_t reqd = lrintf((count - available) / ratio); 960 size_t reqd = lrintf((count - available) / ratio);
934 #ifdef HAVE_RUBBERBAND
935 reqd = std::max(reqd, ts->getSamplesRequired()); 961 reqd = std::max(reqd, ts->getSamplesRequired());
936 #else
937 reqd = std::max(reqd, ts->getRequiredInputSamples());
938 #endif
939 if (reqd == 0) reqd = 1; 962 if (reqd == 0) reqd = 1;
940 963
941 float *ib[channels];
942
943 size_t got = reqd; 964 size_t got = reqd;
944 965
945 if (mix) { 966 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
946 for (size_t c = 0; c < channels; ++c) { 967 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 968 #endif
948 else ib[c] = 0; 969
949 RingBuffer<float> *rb = getReadRingBuffer(c); 970 for (size_t c = 0; c < channels; ++c) {
950 if (rb) { 971 if (c >= m_stretcherInputCount) continue;
951 size_t gotHere; 972 if (reqd > m_stretcherInputSizes[c]) {
952 if (c > 0) gotHere = rb->readAdding(ib[0], got); 973 if (c == 0) {
953 else gotHere = rb->read(ib[0], got); 974 std::cerr << "WARNING: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << std::endl;
954 if (gotHere < got) got = gotHere;
955 } 975 }
976 delete[] m_stretcherInputs[c];
977 m_stretcherInputSizes[c] = reqd * 2;
978 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]];
956 } 979 }
957 } else { 980 }
958 for (size_t c = 0; c < channels; ++c) { 981
959 ib[c] = new float[reqd]; //!!! fix -- this is a rt function 982 for (size_t c = 0; c < channels; ++c) {
960 RingBuffer<float> *rb = getReadRingBuffer(c); 983 if (c >= m_stretcherInputCount) continue;
961 if (rb) { 984 RingBuffer<float> *rb = getReadRingBuffer(c);
962 size_t gotHere = rb->read(ib[c], got); 985 if (rb) {
963 if (gotHere < got) got = gotHere; 986 size_t gotHere = rb->read(m_stretcherInputs[c], got);
987 if (gotHere < got) got = gotHere;
988
989 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
990 if (c == 0) {
991 std::cerr << "feeding stretcher: got " << gotHere
992 << ", " << rb->getReadSpace() << " remain" << std::endl;
964 } 993 }
994 #endif
995
996 } else {
997 std::cerr << "WARNING: No ring buffer available for channel " << c << " in stretcher input block" << std::endl;
965 } 998 }
966 } 999 }
967 1000
968 if (got < reqd) { 1001 if (got < reqd) {
969 std::cerr << "WARNING: Read underrun in playback (" 1002 std::cerr << "WARNING: Read underrun in playback ("
970 << got << " < " << reqd << ")" << std::endl; 1003 << got << " < " << reqd << ")" << std::endl;
971 } 1004 }
972 1005
973 #ifdef HAVE_RUBBERBAND 1006 ts->process(m_stretcherInputs, got, false);
974 ts->process(ib, got, false); 1007
975 #else 1008 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 1009
983 if (got == 0) break; 1010 if (got == 0) break;
984 1011
985 #ifdef HAVE_RUBBERBAND
986 if (ts->available() == available) { 1012 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; 1013 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; 1014 if (++warned == 5) break;
992 } 1015 }
993 } 1016 }
994 1017
995 #ifdef HAVE_RUBBERBAND
996 ts->retrieve(buffer, count); 1018 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 1019
1013 applyAuditioningEffect(count, buffer); 1020 applyAuditioningEffect(count, buffer);
1014 1021
1015 m_condition.wakeAll(); 1022 m_condition.wakeAll();
1016 1023
1182 data.src_ratio = ratio; 1189 data.src_ratio = ratio;
1183 data.end_of_input = 0; 1190 data.end_of_input = 0;
1184 1191
1185 int err = 0; 1192 int err = 0;
1186 1193
1187 #ifdef HAVE_RUBBERBAND
1188 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) { 1194 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 1195 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1193 std::cout << "Using crappy converter" << std::endl; 1196 std::cout << "Using crappy converter" << std::endl;
1194 #endif 1197 #endif
1195 err = src_process(m_crapConverter, &data); 1198 err = src_process(m_crapConverter, &data);
1196 } else { 1199 } else {
1225 1228
1226 } else { 1229 } else {
1227 1230
1228 // space must be a multiple of generatorBlockSize 1231 // space must be a multiple of generatorBlockSize
1229 space = (space / generatorBlockSize) * generatorBlockSize; 1232 space = (space / generatorBlockSize) * generatorBlockSize;
1230 if (space == 0) return false; 1233 if (space == 0) {
1234 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1235 std::cout << "requested fill is less than generator block size of "
1236 << generatorBlockSize << ", leaving it" << std::endl;
1237 #endif
1238 return false;
1239 }
1231 1240
1232 if (tmpSize < channels * space) { 1241 if (tmpSize < channels * space) {
1233 delete[] tmp; 1242 delete[] tmp;
1234 tmp = new float[channels * space]; 1243 tmp = new float[channels * space];
1235 tmpSize = channels * space; 1244 tmpSize = channels * space;
1511 while (!s.m_exiting) { 1520 while (!s.m_exiting) {
1512 1521
1513 s.unifyRingBuffers(); 1522 s.unifyRingBuffers();
1514 s.m_bufferScavenger.scavenge(); 1523 s.m_bufferScavenger.scavenge();
1515 s.m_pluginScavenger.scavenge(); 1524 s.m_pluginScavenger.scavenge();
1516 #ifndef HAVE_RUBBERBAND
1517 s.m_timeStretcherScavenger.scavenge();
1518 #endif
1519 1525
1520 if (work && s.m_playing && s.getSourceSampleRate()) { 1526 if (work && s.m_playing && s.getSourceSampleRate()) {
1521 1527
1522 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1528 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1523 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl; 1529 std::cout << "AudioCallbackPlaySourceFillThread: not waiting" << std::endl;