Mercurial > hg > svapp
comparison audio/AudioCallbackPlaySource.cpp @ 553:2a1e9e017484 bqresample
Fixes to sample rate and latency handling
author | Chris Cannam |
---|---|
date | Fri, 09 Dec 2016 14:40:49 +0000 |
parents | 8c11ca1ebc39 |
children | 2683a8ca36ea |
comparison
equal
deleted
inserted
replaced
552:8c11ca1ebc39 | 553:2a1e9e017484 |
---|---|
52 m_writeBufferFill(0), | 52 m_writeBufferFill(0), |
53 m_bufferScavenger(1), | 53 m_bufferScavenger(1), |
54 m_sourceChannelCount(0), | 54 m_sourceChannelCount(0), |
55 m_blockSize(1024), | 55 m_blockSize(1024), |
56 m_sourceSampleRate(0), | 56 m_sourceSampleRate(0), |
57 m_targetSampleRate(0), | 57 m_deviceSampleRate(0), |
58 m_playLatency(0), | 58 m_playLatency(0), |
59 m_target(0), | 59 m_target(0), |
60 m_lastRetrievalTimestamp(0.0), | 60 m_lastRetrievalTimestamp(0.0), |
61 m_lastRetrievedBlockSize(0), | 61 m_lastRetrievedBlockSize(0), |
62 m_trustworthyTimestamps(true), | 62 m_trustworthyTimestamps(true), |
229 } else { | 229 } else { |
230 if (willPlay) clearRingBuffers(true); | 230 if (willPlay) clearRingBuffers(true); |
231 } | 231 } |
232 | 232 |
233 if (srChanged) { | 233 if (srChanged) { |
234 | |
234 SVCERR << "AudioCallbackPlaySource: Source rate changed" << endl; | 235 SVCERR << "AudioCallbackPlaySource: Source rate changed" << endl; |
236 | |
235 if (m_resamplerWrapper) { | 237 if (m_resamplerWrapper) { |
236 SVCERR << "AudioCallbackPlaySource: Source sample rate changed to " | 238 SVCERR << "AudioCallbackPlaySource: Source sample rate changed to " |
237 << m_sourceSampleRate << ", updating resampler wrapper" << endl; | 239 << m_sourceSampleRate << ", updating resampler wrapper" << endl; |
238 m_resamplerWrapper->changeApplicationSampleRate | 240 m_resamplerWrapper->changeApplicationSampleRate |
239 (int(round(m_sourceSampleRate))); | 241 (int(round(m_sourceSampleRate))); |
240 m_resamplerWrapper->reset(); | 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); | |
241 } | 252 } |
242 } | 253 } |
243 | 254 |
244 rebuildRangeLists(); | 255 rebuildRangeLists(); |
245 | 256 |
630 AudioCallbackPlaySource::getCurrentPlayingFrame() | 641 AudioCallbackPlaySource::getCurrentPlayingFrame() |
631 { | 642 { |
632 // This method attempts to estimate which audio sample frame is | 643 // This method attempts to estimate which audio sample frame is |
633 // "currently coming through the speakers". | 644 // "currently coming through the speakers". |
634 | 645 |
635 sv_samplerate_t targetRate = getTargetSampleRate(); | 646 sv_samplerate_t deviceRate = getDeviceSampleRate(); |
636 sv_frame_t latency = m_playLatency; // at target rate | 647 sv_frame_t latency = m_playLatency; // at target rate |
637 RealTime latency_t = RealTime::zeroTime; | 648 RealTime latency_t = RealTime::zeroTime; |
638 | 649 |
639 if (targetRate != 0) { | 650 if (deviceRate != 0) { |
640 latency_t = RealTime::frame2RealTime(latency, targetRate); | 651 latency_t = RealTime::frame2RealTime(latency, deviceRate); |
641 } | 652 } |
642 | 653 |
643 return getCurrentFrame(latency_t); | 654 return getCurrentFrame(latency_t); |
644 } | 655 } |
645 | 656 |
650 } | 661 } |
651 | 662 |
652 sv_frame_t | 663 sv_frame_t |
653 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) | 664 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) |
654 { | 665 { |
655 // We resample when filling the ring buffer, and time-stretch when | 666 // The ring buffers contain data at the source sample rate and all |
656 // draining it. The buffer contains data at the "target rate" and | 667 // processing (including time stretching) happens at this |
657 // the latency provided by the target is also at the target rate. | 668 // rate. Resampling only happens after the audio data leaves this |
658 // Because of the multiple rates involved, we do the actual | 669 // class. |
659 // calculation using RealTime instead. | 670 |
660 | 671 // (But because historically more than one sample rate could have |
661 sv_samplerate_t sourceRate = getSourceSampleRate(); | 672 // been involved here, we do latency calculations using RealTime |
662 sv_samplerate_t targetRate = getTargetSampleRate(); | 673 // values instead of samples.) |
663 | 674 |
664 if (sourceRate == 0 || targetRate == 0) return 0; | 675 sv_samplerate_t rate = getSourceSampleRate(); |
676 | |
677 if (rate == 0) return 0; | |
665 | 678 |
666 int inbuffer = 0; // at target rate | 679 int inbuffer = 0; // at target rate |
667 | 680 |
668 for (int c = 0; c < getTargetChannelCount(); ++c) { | 681 for (int c = 0; c < getTargetChannelCount(); ++c) { |
669 RingBuffer<float> *rb = getReadRingBuffer(c); | 682 RingBuffer<float> *rb = getReadRingBuffer(c); |
679 double currentTime = 0.0; | 692 double currentTime = 0.0; |
680 if (m_target) currentTime = m_target->getCurrentTime(); | 693 if (m_target) currentTime = m_target->getCurrentTime(); |
681 | 694 |
682 bool looping = m_viewManager->getPlayLoopMode(); | 695 bool looping = m_viewManager->getPlayLoopMode(); |
683 | 696 |
684 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate); | 697 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, rate); |
685 | 698 |
686 sv_frame_t stretchlat = 0; | 699 sv_frame_t stretchlat = 0; |
687 double timeRatio = 1.0; | 700 double timeRatio = 1.0; |
688 | 701 |
689 if (m_timeStretcher) { | 702 if (m_timeStretcher) { |
690 stretchlat = m_timeStretcher->getLatency(); | 703 stretchlat = m_timeStretcher->getLatency(); |
691 timeRatio = m_timeStretcher->getTimeRatio(); | 704 timeRatio = m_timeStretcher->getTimeRatio(); |
692 } | 705 } |
693 | 706 |
694 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, targetRate); | 707 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, rate); |
695 | 708 |
696 // 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 |
697 // sample it obtained was our buffer fill frame count minus the | 710 // sample it obtained was our buffer fill frame count minus the |
698 // amount of read space (converted back to source sample rate) | 711 // amount of read space (converted back to source sample rate) |
699 // remaining now. That sample is not expected to be played until | 712 // remaining now. That sample is not expected to be played until |
707 | 720 |
708 if (m_target && | 721 if (m_target && |
709 m_trustworthyTimestamps && | 722 m_trustworthyTimestamps && |
710 lastRetrievalTimestamp != 0.0) { | 723 lastRetrievalTimestamp != 0.0) { |
711 | 724 |
712 lastretrieved_t = RealTime::frame2RealTime | 725 lastretrieved_t = RealTime::frame2RealTime(lastRetrievedBlockSize, rate); |
713 (lastRetrievedBlockSize, targetRate); | |
714 | 726 |
715 // calculate number of frames at target rate that have elapsed | 727 // calculate number of frames at target rate that have elapsed |
716 // since the end of the last call to getSourceSamples | 728 // since the end of the last call to getSourceSamples |
717 | 729 |
718 if (m_trustworthyTimestamps && !looping) { | 730 if (m_trustworthyTimestamps && !looping) { |
725 } | 737 } |
726 } | 738 } |
727 | 739 |
728 } else { | 740 } else { |
729 | 741 |
730 lastretrieved_t = RealTime::frame2RealTime | 742 lastretrieved_t = RealTime::frame2RealTime(getTargetBlockSize(), rate); |
731 (getTargetBlockSize(), targetRate); | 743 } |
732 } | 744 |
733 | 745 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, rate); |
734 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, sourceRate); | |
735 | 746 |
736 if (timeRatio != 1.0) { | 747 if (timeRatio != 1.0) { |
737 lastretrieved_t = lastretrieved_t / timeRatio; | 748 lastretrieved_t = lastretrieved_t / timeRatio; |
738 sincerequest_t = sincerequest_t / timeRatio; | 749 sincerequest_t = sincerequest_t / timeRatio; |
739 latency_t = latency_t / timeRatio; | 750 latency_t = latency_t / timeRatio; |
755 // this code is only used in case of error in rebuildRangeLists | 766 // this code is only used in case of error in rebuildRangeLists |
756 RealTime playing_t = bufferedto_t | 767 RealTime playing_t = bufferedto_t |
757 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t | 768 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t |
758 + sincerequest_t; | 769 + sincerequest_t; |
759 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; | 770 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; |
760 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate); | 771 sv_frame_t frame = RealTime::realTime2Frame(playing_t, rate); |
761 return m_viewManager->alignPlaybackFrameToReference(frame); | 772 return m_viewManager->alignPlaybackFrameToReference(frame); |
762 } | 773 } |
763 | 774 |
764 int inRange = 0; | 775 int inRange = 0; |
765 int index = 0; | 776 int index = 0; |
792 // the region boundary and end up being much smaller than the | 803 // the region boundary and end up being much smaller than the |
793 // theoretical play start frame, perhaps even for the entire | 804 // theoretical play start frame, perhaps even for the entire |
794 // duration of playback! | 805 // duration of playback! |
795 | 806 |
796 if (!m_playStartFramePassed) { | 807 if (!m_playStartFramePassed) { |
797 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame, | 808 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame, rate); |
798 sourceRate); | |
799 if (playing_t < playstart_t) { | 809 if (playing_t < playstart_t) { |
800 // cerr << "playing_t " << playing_t << " < playstart_t " | 810 // cerr << "playing_t " << playing_t << " < playstart_t " |
801 // << playstart_t << endl; | 811 // << playstart_t << endl; |
802 if (/*!!! sincerequest_t > RealTime::zeroTime && */ | 812 if (/*!!! sincerequest_t > RealTime::zeroTime && */ |
803 m_playStartedAt + latency_t + stretchlat_t < | 813 m_playStartedAt + latency_t + stretchlat_t < |
851 } | 861 } |
852 } | 862 } |
853 | 863 |
854 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; | 864 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; |
855 | 865 |
856 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate); | 866 sv_frame_t frame = RealTime::realTime2Frame(playing_t, rate); |
857 | 867 |
858 if (m_lastCurrentFrame > 0 && !looping) { | 868 if (m_lastCurrentFrame > 0 && !looping) { |
859 if (frame < m_lastCurrentFrame) { | 869 if (frame < m_lastCurrentFrame) { |
860 frame = m_lastCurrentFrame; | 870 frame = m_lastCurrentFrame; |
861 } | 871 } |
936 } | 946 } |
937 | 947 |
938 void | 948 void |
939 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) | 949 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) |
940 { | 950 { |
941 bool first = (m_targetSampleRate == 0); | 951 m_deviceSampleRate = sr; |
942 | |
943 m_targetSampleRate = sr; | |
944 | |
945 if (first && (m_stretchRatio != 1.f)) { | |
946 // couldn't create a stretcher before because we had no sample | |
947 // rate: make one now | |
948 setTimeStretch(m_stretchRatio); | |
949 } | |
950 } | 952 } |
951 | 953 |
952 void | 954 void |
953 AudioCallbackPlaySource::setSystemPlaybackChannelCount(int) | 955 AudioCallbackPlaySource::setSystemPlaybackChannelCount(int) |
954 { | 956 { |
981 m_audioGenerator->clearSoloModelSet(); | 983 m_audioGenerator->clearSoloModelSet(); |
982 clearRingBuffers(); | 984 clearRingBuffers(); |
983 } | 985 } |
984 | 986 |
985 sv_samplerate_t | 987 sv_samplerate_t |
986 AudioCallbackPlaySource::getTargetSampleRate() const | 988 AudioCallbackPlaySource::getDeviceSampleRate() const |
987 { | 989 { |
988 if (m_targetSampleRate) return m_targetSampleRate; | 990 return m_deviceSampleRate; |
989 else return getSourceSampleRate(); | |
990 } | 991 } |
991 | 992 |
992 int | 993 int |
993 AudioCallbackPlaySource::getSourceChannelCount() const | 994 AudioCallbackPlaySource::getSourceChannelCount() const |
994 { | 995 { |
1011 void | 1012 void |
1012 AudioCallbackPlaySource::setTimeStretch(double factor) | 1013 AudioCallbackPlaySource::setTimeStretch(double factor) |
1013 { | 1014 { |
1014 m_stretchRatio = factor; | 1015 m_stretchRatio = factor; |
1015 | 1016 |
1016 if (!getTargetSampleRate()) return; // have to make our stretcher later | 1017 int rate = int(getSourceSampleRate()); |
1018 if (!rate) return; // have to make our stretcher later | |
1017 | 1019 |
1018 if (m_timeStretcher || (factor == 1.0)) { | 1020 if (m_timeStretcher || (factor == 1.0)) { |
1019 // stretch ratio will be set in next process call if appropriate | 1021 // stretch ratio will be set in next process call if appropriate |
1020 } else { | 1022 } else { |
1021 m_stretcherInputCount = getTargetChannelCount(); | 1023 m_stretcherInputCount = getTargetChannelCount(); |
1022 RubberBandStretcher *stretcher = new RubberBandStretcher | 1024 RubberBandStretcher *stretcher = new RubberBandStretcher |
1023 (int(getTargetSampleRate()), | 1025 (rate, |
1024 m_stretcherInputCount, | 1026 m_stretcherInputCount, |
1025 RubberBandStretcher::OptionProcessRealTime, | 1027 RubberBandStretcher::OptionProcessRealTime, |
1026 factor); | 1028 factor); |
1027 RubberBandStretcher *monoStretcher = new RubberBandStretcher | 1029 RubberBandStretcher *monoStretcher = new RubberBandStretcher |
1028 (int(getTargetSampleRate()), | 1030 (rate, |
1029 1, | 1031 1, |
1030 RubberBandStretcher::OptionProcessRealTime, | 1032 RubberBandStretcher::OptionProcessRealTime, |
1031 factor); | 1033 factor); |
1032 m_stretcherInputs = new float *[m_stretcherInputCount]; | 1034 m_stretcherInputs = new float *[m_stretcherInputCount]; |
1033 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount]; | 1035 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount]; |