Mercurial > hg > svapp
comparison audio/AudioCallbackPlaySource.cpp @ 554:4be200469a9c 3.0-integration
Merge from branch bqresample
author | Chris Cannam |
---|---|
date | Fri, 09 Dec 2016 18:01:55 +0000 |
parents | 2a1e9e017484 |
children | 2683a8ca36ea |
comparison
equal
deleted
inserted
replaced
546:4de547a5905c | 554:4be200469a9c |
---|---|
26 #include "data/model/ReadOnlyWaveFileModel.h" | 26 #include "data/model/ReadOnlyWaveFileModel.h" |
27 #include "data/model/SparseOneDimensionalModel.h" | 27 #include "data/model/SparseOneDimensionalModel.h" |
28 #include "plugin/RealTimePluginInstance.h" | 28 #include "plugin/RealTimePluginInstance.h" |
29 | 29 |
30 #include "bqaudioio/SystemPlaybackTarget.h" | 30 #include "bqaudioio/SystemPlaybackTarget.h" |
31 #include "bqaudioio/ResamplerWrapper.h" | |
31 | 32 |
32 #include <rubberband/RubberBandStretcher.h> | 33 #include <rubberband/RubberBandStretcher.h> |
33 using namespace RubberBand; | 34 using namespace RubberBand; |
34 | 35 |
35 #include <iostream> | 36 #include <iostream> |
51 m_writeBufferFill(0), | 52 m_writeBufferFill(0), |
52 m_bufferScavenger(1), | 53 m_bufferScavenger(1), |
53 m_sourceChannelCount(0), | 54 m_sourceChannelCount(0), |
54 m_blockSize(1024), | 55 m_blockSize(1024), |
55 m_sourceSampleRate(0), | 56 m_sourceSampleRate(0), |
56 m_targetSampleRate(0), | 57 m_deviceSampleRate(0), |
57 m_playLatency(0), | 58 m_playLatency(0), |
58 m_target(0), | 59 m_target(0), |
59 m_lastRetrievalTimestamp(0.0), | 60 m_lastRetrievalTimestamp(0.0), |
60 m_lastRetrievedBlockSize(0), | 61 m_lastRetrievedBlockSize(0), |
61 m_trustworthyTimestamps(true), | 62 m_trustworthyTimestamps(true), |
75 m_stretchRatio(1.0), | 76 m_stretchRatio(1.0), |
76 m_stretchMono(false), | 77 m_stretchMono(false), |
77 m_stretcherInputCount(0), | 78 m_stretcherInputCount(0), |
78 m_stretcherInputs(0), | 79 m_stretcherInputs(0), |
79 m_stretcherInputSizes(0), | 80 m_stretcherInputSizes(0), |
80 m_fillThread(0) | 81 m_fillThread(0), |
82 m_resamplerWrapper(0) | |
81 { | 83 { |
82 m_viewManager->setAudioPlaySource(this); | 84 m_viewManager->setAudioPlaySource(this); |
83 | 85 |
84 connect(m_viewManager, SIGNAL(selectionChanged()), | 86 connect(m_viewManager, SIGNAL(selectionChanged()), |
85 this, SLOT(selectionChanged())); | 87 this, SLOT(selectionChanged())); |
226 buffersChanged = true; | 228 buffersChanged = true; |
227 } else { | 229 } else { |
228 if (willPlay) clearRingBuffers(true); | 230 if (willPlay) clearRingBuffers(true); |
229 } | 231 } |
230 | 232 |
231 if (buffersChanged || srChanged) { | 233 if (srChanged) { |
232 | 234 |
233 // There are more channels than there were before, or the | 235 SVCERR << "AudioCallbackPlaySource: Source rate changed" << endl; |
234 // source sample rate has changed | 236 |
235 | 237 if (m_resamplerWrapper) { |
236 //!!! | 238 SVCERR << "AudioCallbackPlaySource: Source sample rate changed to " |
237 | 239 << m_sourceSampleRate << ", updating resampler wrapper" << endl; |
240 m_resamplerWrapper->changeApplicationSampleRate | |
241 (int(round(m_sourceSampleRate))); | |
242 m_resamplerWrapper->reset(); | |
243 } | |
244 | |
245 delete m_timeStretcher; | |
246 delete m_monoStretcher; | |
247 m_timeStretcher = 0; | |
248 m_monoStretcher = 0; | |
249 | |
250 if (m_stretchRatio != 1.f) { | |
251 setTimeStretch(m_stretchRatio); | |
252 } | |
238 } | 253 } |
239 | 254 |
240 rebuildRangeLists(); | 255 rebuildRangeLists(); |
241 | 256 |
242 m_mutex.unlock(); | 257 m_mutex.unlock(); |
536 { | 551 { |
537 clearRingBuffers(); | 552 clearRingBuffers(); |
538 } | 553 } |
539 | 554 |
540 void | 555 void |
541 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n) | 556 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName ) |
542 { | 557 { |
543 } | 558 } |
544 | 559 |
545 void | 560 void |
546 AudioCallbackPlaySource::audioProcessingOverload() | 561 AudioCallbackPlaySource::audioProcessingOverload() |
571 { | 586 { |
572 m_target = target; | 587 m_target = target; |
573 } | 588 } |
574 | 589 |
575 void | 590 void |
591 AudioCallbackPlaySource::setResamplerWrapper(breakfastquay::ResamplerWrapper *w) | |
592 { | |
593 m_resamplerWrapper = w; | |
594 if (m_resamplerWrapper && m_sourceSampleRate != 0) { | |
595 m_resamplerWrapper->changeApplicationSampleRate | |
596 (int(round(m_sourceSampleRate))); | |
597 } | |
598 } | |
599 | |
600 void | |
576 AudioCallbackPlaySource::setSystemPlaybackBlockSize(int size) | 601 AudioCallbackPlaySource::setSystemPlaybackBlockSize(int size) |
577 { | 602 { |
578 cout << "AudioCallbackPlaySource::setTarget: Block size -> " << size << endl; | 603 cout << "AudioCallbackPlaySource::setTarget: Block size -> " << size << endl; |
579 if (size != 0) { | 604 if (size != 0) { |
580 m_blockSize = size; | 605 m_blockSize = size; |
616 AudioCallbackPlaySource::getCurrentPlayingFrame() | 641 AudioCallbackPlaySource::getCurrentPlayingFrame() |
617 { | 642 { |
618 // This method attempts to estimate which audio sample frame is | 643 // This method attempts to estimate which audio sample frame is |
619 // "currently coming through the speakers". | 644 // "currently coming through the speakers". |
620 | 645 |
621 sv_samplerate_t targetRate = getTargetSampleRate(); | 646 sv_samplerate_t deviceRate = getDeviceSampleRate(); |
622 sv_frame_t latency = m_playLatency; // at target rate | 647 sv_frame_t latency = m_playLatency; // at target rate |
623 RealTime latency_t = RealTime::zeroTime; | 648 RealTime latency_t = RealTime::zeroTime; |
624 | 649 |
625 if (targetRate != 0) { | 650 if (deviceRate != 0) { |
626 latency_t = RealTime::frame2RealTime(latency, targetRate); | 651 latency_t = RealTime::frame2RealTime(latency, deviceRate); |
627 } | 652 } |
628 | 653 |
629 return getCurrentFrame(latency_t); | 654 return getCurrentFrame(latency_t); |
630 } | 655 } |
631 | 656 |
636 } | 661 } |
637 | 662 |
638 sv_frame_t | 663 sv_frame_t |
639 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) | 664 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) |
640 { | 665 { |
641 // We resample when filling the ring buffer, and time-stretch when | 666 // The ring buffers contain data at the source sample rate and all |
642 // draining it. The buffer contains data at the "target rate" and | 667 // processing (including time stretching) happens at this |
643 // the latency provided by the target is also at the target rate. | 668 // rate. Resampling only happens after the audio data leaves this |
644 // Because of the multiple rates involved, we do the actual | 669 // class. |
645 // calculation using RealTime instead. | 670 |
646 | 671 // (But because historically more than one sample rate could have |
647 sv_samplerate_t sourceRate = getSourceSampleRate(); | 672 // been involved here, we do latency calculations using RealTime |
648 sv_samplerate_t targetRate = getTargetSampleRate(); | 673 // values instead of samples.) |
649 | 674 |
650 if (sourceRate == 0 || targetRate == 0) return 0; | 675 sv_samplerate_t rate = getSourceSampleRate(); |
676 | |
677 if (rate == 0) return 0; | |
651 | 678 |
652 int inbuffer = 0; // at target rate | 679 int inbuffer = 0; // at target rate |
653 | 680 |
654 for (int c = 0; c < getTargetChannelCount(); ++c) { | 681 for (int c = 0; c < getTargetChannelCount(); ++c) { |
655 RingBuffer<float> *rb = getReadRingBuffer(c); | 682 RingBuffer<float> *rb = getReadRingBuffer(c); |
665 double currentTime = 0.0; | 692 double currentTime = 0.0; |
666 if (m_target) currentTime = m_target->getCurrentTime(); | 693 if (m_target) currentTime = m_target->getCurrentTime(); |
667 | 694 |
668 bool looping = m_viewManager->getPlayLoopMode(); | 695 bool looping = m_viewManager->getPlayLoopMode(); |
669 | 696 |
670 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate); | 697 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, rate); |
671 | 698 |
672 sv_frame_t stretchlat = 0; | 699 sv_frame_t stretchlat = 0; |
673 double timeRatio = 1.0; | 700 double timeRatio = 1.0; |
674 | 701 |
675 if (m_timeStretcher) { | 702 if (m_timeStretcher) { |
676 stretchlat = m_timeStretcher->getLatency(); | 703 stretchlat = m_timeStretcher->getLatency(); |
677 timeRatio = m_timeStretcher->getTimeRatio(); | 704 timeRatio = m_timeStretcher->getTimeRatio(); |
678 } | 705 } |
679 | 706 |
680 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate); | 707 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, rate); |
681 | 708 |
682 // When the target has just requested a block from us, the last | 709 // When the target has just requested a block from us, the last |
683 // sample it obtained was our buffer fill frame count minus the | 710 // sample it obtained was our buffer fill frame count minus the |
684 // amount of read space (converted back to source sample rate) | 711 // amount of read space (converted back to source sample rate) |
685 // remaining now. That sample is not expected to be played until | 712 // remaining now. That sample is not expected to be played until |
693 | 720 |
694 if (m_target && | 721 if (m_target && |
695 m_trustworthyTimestamps && | 722 m_trustworthyTimestamps && |
696 lastRetrievalTimestamp != 0.0) { | 723 lastRetrievalTimestamp != 0.0) { |
697 | 724 |
698 lastretrieved_t = RealTime::frame2RealTime | 725 lastretrieved_t = RealTime::frame2RealTime(lastRetrievedBlockSize, rate); |
699 (lastRetrievedBlockSize, targetRate); | |
700 | 726 |
701 // calculate number of frames at target rate that have elapsed | 727 // calculate number of frames at target rate that have elapsed |
702 // since the end of the last call to getSourceSamples | 728 // since the end of the last call to getSourceSamples |
703 | 729 |
704 if (m_trustworthyTimestamps && !looping) { | 730 if (m_trustworthyTimestamps && !looping) { |
711 } | 737 } |
712 } | 738 } |
713 | 739 |
714 } else { | 740 } else { |
715 | 741 |
716 lastretrieved_t = RealTime::frame2RealTime | 742 lastretrieved_t = RealTime::frame2RealTime(getTargetBlockSize(), rate); |
717 (getTargetBlockSize(), targetRate); | 743 } |
718 } | 744 |
719 | 745 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, rate); |
720 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, sourceRate); | |
721 | 746 |
722 if (timeRatio != 1.0) { | 747 if (timeRatio != 1.0) { |
723 lastretrieved_t = lastretrieved_t / timeRatio; | 748 lastretrieved_t = lastretrieved_t / timeRatio; |
724 sincerequest_t = sincerequest_t / timeRatio; | 749 sincerequest_t = sincerequest_t / timeRatio; |
725 latency_t = latency_t / timeRatio; | 750 latency_t = latency_t / timeRatio; |
741 // this code is only used in case of error in rebuildRangeLists | 766 // this code is only used in case of error in rebuildRangeLists |
742 RealTime playing_t = bufferedto_t | 767 RealTime playing_t = bufferedto_t |
743 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t | 768 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t |
744 + sincerequest_t; | 769 + sincerequest_t; |
745 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; | 770 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; |
746 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate); | 771 sv_frame_t frame = RealTime::realTime2Frame(playing_t, rate); |
747 return m_viewManager->alignPlaybackFrameToReference(frame); | 772 return m_viewManager->alignPlaybackFrameToReference(frame); |
748 } | 773 } |
749 | 774 |
750 int inRange = 0; | 775 int inRange = 0; |
751 int index = 0; | 776 int index = 0; |
778 // the region boundary and end up being much smaller than the | 803 // the region boundary and end up being much smaller than the |
779 // theoretical play start frame, perhaps even for the entire | 804 // theoretical play start frame, perhaps even for the entire |
780 // duration of playback! | 805 // duration of playback! |
781 | 806 |
782 if (!m_playStartFramePassed) { | 807 if (!m_playStartFramePassed) { |
783 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame, | 808 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame, rate); |
784 sourceRate); | |
785 if (playing_t < playstart_t) { | 809 if (playing_t < playstart_t) { |
786 // cerr << "playing_t " << playing_t << " < playstart_t " | 810 // cerr << "playing_t " << playing_t << " < playstart_t " |
787 // << playstart_t << endl; | 811 // << playstart_t << endl; |
788 if (/*!!! sincerequest_t > RealTime::zeroTime && */ | 812 if (/*!!! sincerequest_t > RealTime::zeroTime && */ |
789 m_playStartedAt + latency_t + stretchlat_t < | 813 m_playStartedAt + latency_t + stretchlat_t < |
837 } | 861 } |
838 } | 862 } |
839 | 863 |
840 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; | 864 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; |
841 | 865 |
842 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate); | 866 sv_frame_t frame = RealTime::realTime2Frame(playing_t, rate); |
843 | 867 |
844 if (m_lastCurrentFrame > 0 && !looping) { | 868 if (m_lastCurrentFrame > 0 && !looping) { |
845 if (frame < m_lastCurrentFrame) { | 869 if (frame < m_lastCurrentFrame) { |
846 frame = m_lastCurrentFrame; | 870 frame = m_lastCurrentFrame; |
847 } | 871 } |
922 } | 946 } |
923 | 947 |
924 void | 948 void |
925 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) | 949 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) |
926 { | 950 { |
927 bool first = (m_targetSampleRate == 0); | 951 m_deviceSampleRate = sr; |
928 | 952 } |
929 m_targetSampleRate = sr; | 953 |
930 | 954 void |
931 if (first && (m_stretchRatio != 1.f)) { | 955 AudioCallbackPlaySource::setSystemPlaybackChannelCount(int) |
932 // couldn't create a stretcher before because we had no sample | |
933 // rate: make one now | |
934 setTimeStretch(m_stretchRatio); | |
935 } | |
936 } | |
937 | |
938 void | |
939 AudioCallbackPlaySource::setSystemPlaybackChannelCount(int c) | |
940 { | 956 { |
941 } | 957 } |
942 | 958 |
943 void | 959 void |
944 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a) | 960 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a) |
967 m_audioGenerator->clearSoloModelSet(); | 983 m_audioGenerator->clearSoloModelSet(); |
968 clearRingBuffers(); | 984 clearRingBuffers(); |
969 } | 985 } |
970 | 986 |
971 sv_samplerate_t | 987 sv_samplerate_t |
972 AudioCallbackPlaySource::getTargetSampleRate() const | 988 AudioCallbackPlaySource::getDeviceSampleRate() const |
973 { | 989 { |
974 if (m_targetSampleRate) return m_targetSampleRate; | 990 return m_deviceSampleRate; |
975 else return getSourceSampleRate(); | |
976 } | 991 } |
977 | 992 |
978 int | 993 int |
979 AudioCallbackPlaySource::getSourceChannelCount() const | 994 AudioCallbackPlaySource::getSourceChannelCount() const |
980 { | 995 { |
997 void | 1012 void |
998 AudioCallbackPlaySource::setTimeStretch(double factor) | 1013 AudioCallbackPlaySource::setTimeStretch(double factor) |
999 { | 1014 { |
1000 m_stretchRatio = factor; | 1015 m_stretchRatio = factor; |
1001 | 1016 |
1002 if (!getTargetSampleRate()) return; // have to make our stretcher later | 1017 int rate = int(getSourceSampleRate()); |
1018 if (!rate) return; // have to make our stretcher later | |
1003 | 1019 |
1004 if (m_timeStretcher || (factor == 1.0)) { | 1020 if (m_timeStretcher || (factor == 1.0)) { |
1005 // stretch ratio will be set in next process call if appropriate | 1021 // stretch ratio will be set in next process call if appropriate |
1006 } else { | 1022 } else { |
1007 m_stretcherInputCount = getTargetChannelCount(); | 1023 m_stretcherInputCount = getTargetChannelCount(); |
1008 RubberBandStretcher *stretcher = new RubberBandStretcher | 1024 RubberBandStretcher *stretcher = new RubberBandStretcher |
1009 (int(getTargetSampleRate()), | 1025 (rate, |
1010 m_stretcherInputCount, | 1026 m_stretcherInputCount, |
1011 RubberBandStretcher::OptionProcessRealTime, | 1027 RubberBandStretcher::OptionProcessRealTime, |
1012 factor); | 1028 factor); |
1013 RubberBandStretcher *monoStretcher = new RubberBandStretcher | 1029 RubberBandStretcher *monoStretcher = new RubberBandStretcher |
1014 (int(getTargetSampleRate()), | 1030 (rate, |
1015 1, | 1031 1, |
1016 RubberBandStretcher::OptionProcessRealTime, | 1032 RubberBandStretcher::OptionProcessRealTime, |
1017 factor); | 1033 factor); |
1018 m_stretcherInputs = new float *[m_stretcherInputCount]; | 1034 m_stretcherInputs = new float *[m_stretcherInputCount]; |
1019 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount]; | 1035 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount]; |
1306 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl; | 1322 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl; |
1307 #endif | 1323 #endif |
1308 return false; | 1324 return false; |
1309 } | 1325 } |
1310 | 1326 |
1327 // space is now the number of samples that can be written on each | |
1328 // channel's write ringbuffer | |
1329 | |
1311 sv_frame_t f = m_writeBufferFill; | 1330 sv_frame_t f = m_writeBufferFill; |
1312 | 1331 |
1313 bool readWriteEqual = (m_readBuffers == m_writeBuffers); | 1332 bool readWriteEqual = (m_readBuffers == m_writeBuffers); |
1314 | 1333 |
1315 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1334 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1322 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1341 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1323 cout << "buffered to " << f << " already" << endl; | 1342 cout << "buffered to " << f << " already" << endl; |
1324 #endif | 1343 #endif |
1325 | 1344 |
1326 int channels = getTargetChannelCount(); | 1345 int channels = getTargetChannelCount(); |
1327 | |
1328 sv_frame_t orig = space; | |
1329 | 1346 |
1330 static float **bufferPtrs = 0; | 1347 static float **bufferPtrs = 0; |
1331 static int bufferPtrCount = 0; | 1348 static int bufferPtrCount = 0; |
1332 | 1349 |
1333 if (bufferPtrCount < channels) { | 1350 if (bufferPtrCount < channels) { |