Mercurial > hg > svapp
comparison audio/AudioCallbackPlaySource.cpp @ 746:771ec060c1d2
Merge from branch audio-source-refactor. Pull out auditioning effect wrapper and time stretch wrapper from play source; corresponding changes to plugin memory management etc.
author | Chris Cannam |
---|---|
date | Fri, 03 Apr 2020 12:14:05 +0100 |
parents | 75390b1ebd2c 1c6c10cc5f73 |
children | e7c77c366360 |
comparison
equal
deleted
inserted
replaced
743:7b1d30af4b38 | 746:771ec060c1d2 |
---|---|
14 */ | 14 */ |
15 | 15 |
16 #include "AudioCallbackPlaySource.h" | 16 #include "AudioCallbackPlaySource.h" |
17 | 17 |
18 #include "AudioGenerator.h" | 18 #include "AudioGenerator.h" |
19 #include "TimeStretchWrapper.h" | |
20 #include "EffectWrapper.h" | |
19 | 21 |
20 #include "data/model/Model.h" | 22 #include "data/model/Model.h" |
21 #include "base/ViewManagerBase.h" | 23 #include "base/ViewManagerBase.h" |
22 #include "base/PlayParameterRepository.h" | 24 #include "base/PlayParameterRepository.h" |
23 #include "base/Preferences.h" | 25 #include "base/Preferences.h" |
29 | 31 |
30 #include "bqaudioio/SystemPlaybackTarget.h" | 32 #include "bqaudioio/SystemPlaybackTarget.h" |
31 #include "bqaudioio/ResamplerWrapper.h" | 33 #include "bqaudioio/ResamplerWrapper.h" |
32 | 34 |
33 #include "bqvec/VectorOps.h" | 35 #include "bqvec/VectorOps.h" |
34 | |
35 #include <rubberband/RubberBandStretcher.h> | |
36 using namespace RubberBand; | |
37 | 36 |
38 using breakfastquay::v_zero_channels; | 37 using breakfastquay::v_zero_channels; |
39 | 38 |
40 #include <iostream> | 39 #include <iostream> |
41 #include <cassert> | 40 #include <cassert> |
71 m_lastModelEndFrame(0), | 70 m_lastModelEndFrame(0), |
72 m_ringBufferSize(DEFAULT_RING_BUFFER_SIZE), | 71 m_ringBufferSize(DEFAULT_RING_BUFFER_SIZE), |
73 m_outputLeft(0.0), | 72 m_outputLeft(0.0), |
74 m_outputRight(0.0), | 73 m_outputRight(0.0), |
75 m_levelsSet(false), | 74 m_levelsSet(false), |
76 m_auditioningPlugin(nullptr), | |
77 m_auditioningPluginBypassed(false), | |
78 m_auditioningPluginFailed(false), | |
79 m_playStartFrame(0), | 75 m_playStartFrame(0), |
80 m_playStartFramePassed(false), | 76 m_playStartFramePassed(false), |
81 m_timeStretcher(nullptr), | |
82 m_monoStretcher(nullptr), | |
83 m_stretchRatio(1.0), | |
84 m_stretchMono(false), | |
85 m_stretcherInputCount(0), | |
86 m_stretcherInputs(nullptr), | |
87 m_stretcherInputSizes(nullptr), | |
88 m_fillThread(nullptr), | 77 m_fillThread(nullptr), |
89 m_resamplerWrapper(nullptr) | 78 m_resamplerWrapper(nullptr), |
79 m_timeStretchWrapper(nullptr), | |
80 m_auditioningEffectWrapper(nullptr) | |
90 { | 81 { |
91 m_viewManager->setAudioPlaySource(this); | 82 m_viewManager->setAudioPlaySource(this); |
92 | 83 |
93 connect(m_viewManager, SIGNAL(selectionChanged()), | 84 connect(m_viewManager, SIGNAL(selectionChanged()), |
94 this, SLOT(selectionChanged())); | 85 this, SLOT(selectionChanged())); |
133 | 124 |
134 delete m_writeBuffers; | 125 delete m_writeBuffers; |
135 | 126 |
136 delete m_audioGenerator; | 127 delete m_audioGenerator; |
137 | 128 |
138 for (int i = 0; i < m_stretcherInputCount; ++i) { | 129 delete m_timeStretchWrapper; |
139 delete[] m_stretcherInputs[i]; | 130 delete m_auditioningEffectWrapper; |
140 } | 131 delete m_resamplerWrapper; |
141 delete[] m_stretcherInputSizes; | |
142 delete[] m_stretcherInputs; | |
143 | |
144 delete m_timeStretcher; | |
145 delete m_monoStretcher; | |
146 | 132 |
147 m_bufferScavenger.scavenge(true); | 133 m_bufferScavenger.scavenge(true); |
148 m_pluginScavenger.scavenge(true); | 134 m_pluginScavenger.scavenge(true); |
149 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 135 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
150 SVDEBUG << "AudioCallbackPlaySource::~AudioCallbackPlaySource finishing" << endl; | 136 SVDEBUG << "AudioCallbackPlaySource::~AudioCallbackPlaySource finishing" << endl; |
151 #endif | 137 #endif |
138 } | |
139 | |
140 breakfastquay::ApplicationPlaybackSource * | |
141 AudioCallbackPlaySource::getApplicationPlaybackSource() | |
142 { | |
143 QMutexLocker locker(&m_mutex); | |
144 | |
145 if (m_timeStretchWrapper) { | |
146 return m_timeStretchWrapper; | |
147 } | |
148 | |
149 checkWrappers(); | |
150 return m_timeStretchWrapper; | |
151 } | |
152 | |
153 void | |
154 AudioCallbackPlaySource::checkWrappers() | |
155 { | |
156 // to be called only with m_mutex held | |
157 | |
158 if (!m_resamplerWrapper) { | |
159 m_resamplerWrapper = new breakfastquay::ResamplerWrapper(this); | |
160 } | |
161 if (!m_auditioningEffectWrapper) { | |
162 m_auditioningEffectWrapper = new EffectWrapper(m_resamplerWrapper); | |
163 } | |
164 if (!m_timeStretchWrapper) { | |
165 m_timeStretchWrapper = new TimeStretchWrapper(m_auditioningEffectWrapper); | |
166 } | |
152 } | 167 } |
153 | 168 |
154 void | 169 void |
155 AudioCallbackPlaySource::addModel(ModelId modelId) | 170 AudioCallbackPlaySource::addModel(ModelId modelId) |
156 { | 171 { |
248 if (willPlay) clearRingBuffers(true); | 263 if (willPlay) clearRingBuffers(true); |
249 } | 264 } |
250 | 265 |
251 if (srChanged) { | 266 if (srChanged) { |
252 | 267 |
253 SVCERR << "AudioCallbackPlaySource: Source rate changed" << endl; | 268 checkWrappers(); |
254 | 269 |
255 if (m_resamplerWrapper) { | 270 SVCERR << "AudioCallbackPlaySource: Source sample rate changed to " |
256 SVCERR << "AudioCallbackPlaySource: Source sample rate changed to " | 271 << m_sourceSampleRate << ", updating resampler wrapper" |
257 << m_sourceSampleRate << ", updating resampler wrapper" << endl; | 272 << endl; |
258 m_resamplerWrapper->changeApplicationSampleRate | 273 m_resamplerWrapper->changeApplicationSampleRate |
259 (int(round(m_sourceSampleRate))); | 274 (int(round(m_sourceSampleRate))); |
260 m_resamplerWrapper->reset(); | 275 m_resamplerWrapper->reset(); |
261 } | |
262 | |
263 delete m_timeStretcher; | |
264 delete m_monoStretcher; | |
265 m_timeStretcher = nullptr; | |
266 m_monoStretcher = nullptr; | |
267 | |
268 if (m_stretchRatio != 1.f) { | |
269 setTimeStretch(m_stretchRatio); | |
270 } | |
271 } | 276 } |
272 | 277 |
273 rebuildRangeLists(); | 278 rebuildRangeLists(); |
274 | 279 |
275 m_mutex.unlock(); | 280 m_mutex.unlock(); |
481 // we're just re-seeking. | 486 // we're just re-seeking. |
482 // NO -- we can end up playing some first -- always reset here | 487 // NO -- we can end up playing some first -- always reset here |
483 | 488 |
484 m_mutex.lock(); | 489 m_mutex.lock(); |
485 | 490 |
486 if (m_timeStretcher) { | 491 if (m_timeStretchWrapper) { |
487 m_timeStretcher->reset(); | 492 m_timeStretchWrapper->reset(); |
488 } | |
489 if (m_monoStretcher) { | |
490 m_monoStretcher->reset(); | |
491 } | 493 } |
492 | 494 |
493 m_readBufferFill = m_writeBufferFill = startFrame; | 495 m_readBufferFill = m_writeBufferFill = startFrame; |
494 if (m_readBuffers) { | 496 if (m_readBuffers) { |
495 for (int c = 0; c < getTargetChannelCount(); ++c) { | 497 for (int c = 0; c < getTargetChannelCount(); ++c) { |
597 { | 599 { |
598 SVCERR << "Audio processing overload!" << endl; | 600 SVCERR << "Audio processing overload!" << endl; |
599 | 601 |
600 if (!m_playing) return; | 602 if (!m_playing) return; |
601 | 603 |
602 RealTimePluginInstance *ap = m_auditioningPlugin; | 604 if (m_auditioningEffectWrapper && |
603 if (ap && !m_auditioningPluginBypassed) { | 605 !m_auditioningEffectWrapper->isBypassed()) { |
604 m_auditioningPluginBypassed = true; | 606 m_auditioningEffectWrapper->setBypassed(true); |
605 emit audioOverloadPluginDisabled(); | 607 emit audioOverloadPluginDisabled(); |
606 return; | |
607 } | |
608 | |
609 if (m_timeStretcher && | |
610 m_timeStretcher->getTimeRatio() < 1.0 && | |
611 m_stretcherInputCount > 1 && | |
612 m_monoStretcher && !m_stretchMono) { | |
613 m_stretchMono = true; | |
614 emit audioTimeStretchMultiChannelDisabled(); | |
615 return; | 608 return; |
616 } | 609 } |
617 } | 610 } |
618 | 611 |
619 void | 612 void |
626 } | 619 } |
627 m_target = target; | 620 m_target = target; |
628 } | 621 } |
629 | 622 |
630 void | 623 void |
631 AudioCallbackPlaySource::setResamplerWrapper(breakfastquay::ResamplerWrapper *w) | |
632 { | |
633 m_resamplerWrapper = w; | |
634 if (m_resamplerWrapper && m_sourceSampleRate != 0) { | |
635 m_resamplerWrapper->changeApplicationSampleRate | |
636 (int(round(m_sourceSampleRate))); | |
637 } | |
638 } | |
639 | |
640 void | |
641 AudioCallbackPlaySource::setSystemPlaybackBlockSize(int size) | 624 AudioCallbackPlaySource::setSystemPlaybackBlockSize(int size) |
642 { | 625 { |
643 cout << "AudioCallbackPlaySource::setTarget: Block size -> " << size << endl; | 626 SVDEBUG << "AudioCallbackPlaySource::setTarget: Block size -> " << size << endl; |
644 if (size != 0) { | 627 if (size != 0) { |
645 m_blockSize = size; | 628 m_blockSize = size; |
646 } | 629 } |
647 if (size * 4 > m_ringBufferSize) { | 630 if (size * 4 > m_ringBufferSize) { |
648 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 631 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
649 cout << "AudioCallbackPlaySource::setTarget: Buffer size " | 632 SVCERR << "AudioCallbackPlaySource::setTarget: Buffer size " |
650 << size << " > a quarter of ring buffer size " | 633 << size << " > a quarter of ring buffer size " |
651 << m_ringBufferSize << ", calling for more ring buffer" | 634 << m_ringBufferSize << ", calling for more ring buffer" |
652 << endl; | 635 << endl; |
653 #endif | 636 #endif |
654 m_ringBufferSize = size * 4; | 637 m_ringBufferSize = size * 4; |
655 if (m_writeBuffers && !m_writeBuffers->empty()) { | 638 if (m_writeBuffers && !m_writeBuffers->empty()) { |
656 clearRingBuffers(); | 639 clearRingBuffers(); |
657 } | 640 } |
702 | 685 |
703 sv_frame_t | 686 sv_frame_t |
704 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) | 687 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) |
705 { | 688 { |
706 // The ring buffers contain data at the source sample rate and all | 689 // The ring buffers contain data at the source sample rate and all |
707 // processing (including time stretching) happens at this | 690 // processing here happens at this rate. Resampling only happens |
708 // rate. Resampling only happens after the audio data leaves this | 691 // after the audio data leaves this class. |
709 // class. | |
710 | 692 |
711 // (But because historically more than one sample rate could have | 693 // (But because historically more than one sample rate could have |
712 // been involved here, we do latency calculations using RealTime | 694 // been involved here, we do latency calculations using RealTime |
713 // values instead of samples.) | 695 // values instead of samples.) |
714 | 696 |
733 if (m_target) currentTime = m_target->getCurrentTime(); | 715 if (m_target) currentTime = m_target->getCurrentTime(); |
734 | 716 |
735 bool looping = m_viewManager->getPlayLoopMode(); | 717 bool looping = m_viewManager->getPlayLoopMode(); |
736 | 718 |
737 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, rate); | 719 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, rate); |
738 | |
739 sv_frame_t stretchlat = 0; | |
740 double timeRatio = 1.0; | |
741 | |
742 if (m_timeStretcher) { | |
743 stretchlat = m_timeStretcher->getLatency(); | |
744 timeRatio = m_timeStretcher->getTimeRatio(); | |
745 } | |
746 | |
747 RealTime stretchlat_t = RealTime::frame2RealTime(stretchlat, rate); | |
748 | 720 |
749 // When the target has just requested a block from us, the last | 721 // When the target has just requested a block from us, the last |
750 // sample it obtained was our buffer fill frame count minus the | 722 // sample it obtained was our buffer fill frame count minus the |
751 // amount of read space (converted back to source sample rate) | 723 // amount of read space (converted back to source sample rate) |
752 // remaining now. That sample is not expected to be played until | 724 // remaining now. That sample is not expected to be played until |
782 lastretrieved_t = RealTime::frame2RealTime(getTargetBlockSize(), rate); | 754 lastretrieved_t = RealTime::frame2RealTime(getTargetBlockSize(), rate); |
783 } | 755 } |
784 | 756 |
785 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, rate); | 757 RealTime bufferedto_t = RealTime::frame2RealTime(readBufferFill, rate); |
786 | 758 |
787 if (timeRatio != 1.0) { | |
788 lastretrieved_t = lastretrieved_t / timeRatio; | |
789 sincerequest_t = sincerequest_t / timeRatio; | |
790 latency_t = latency_t / timeRatio; | |
791 } | |
792 | |
793 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 759 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
794 cout << "\nbuffered to: " << bufferedto_t << ", in buffer: " << inbuffer_t << ", device latency: " << latency_t << "\n since request: " << sincerequest_t << ", last retrieved quantity: " << lastretrieved_t << endl; | 760 cout << "\nbuffered to: " << bufferedto_t << ", in buffer: " << inbuffer_t << ", device latency: " << latency_t << "\n since request: " << sincerequest_t << ", last retrieved quantity: " << lastretrieved_t << endl; |
795 #endif | 761 #endif |
796 | 762 |
797 // Normally the range lists should contain at least one item each | 763 // Normally the range lists should contain at least one item each |
803 } | 769 } |
804 | 770 |
805 if (m_rangeStarts.empty()) { | 771 if (m_rangeStarts.empty()) { |
806 // this code is only used in case of error in rebuildRangeLists | 772 // this code is only used in case of error in rebuildRangeLists |
807 RealTime playing_t = bufferedto_t | 773 RealTime playing_t = bufferedto_t |
808 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t | 774 - latency_t - lastretrieved_t - inbuffer_t |
809 + sincerequest_t; | 775 + sincerequest_t; |
810 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; | 776 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; |
811 sv_frame_t frame = RealTime::realTime2Frame(playing_t, rate); | 777 sv_frame_t frame = RealTime::realTime2Frame(playing_t, rate); |
812 return m_viewManager->alignPlaybackFrameToReference(frame); | 778 return m_viewManager->alignPlaybackFrameToReference(frame); |
813 } | 779 } |
829 } | 795 } |
830 | 796 |
831 RealTime playing_t = bufferedto_t; | 797 RealTime playing_t = bufferedto_t; |
832 | 798 |
833 playing_t = playing_t | 799 playing_t = playing_t |
834 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t | 800 - latency_t - lastretrieved_t - inbuffer_t |
835 + sincerequest_t; | 801 + sincerequest_t; |
836 | 802 |
837 // This rather gross little hack is used to ensure that latency | 803 // This rather gross little hack is used to ensure that latency |
838 // compensation doesn't result in the playback pointer appearing | 804 // compensation doesn't result in the playback pointer appearing |
839 // to start earlier than the actual playback does. It doesn't | 805 // to start earlier than the actual playback does. It doesn't |
847 if (!m_playStartFramePassed) { | 813 if (!m_playStartFramePassed) { |
848 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame, rate); | 814 RealTime playstart_t = RealTime::frame2RealTime(m_playStartFrame, rate); |
849 if (playing_t < playstart_t) { | 815 if (playing_t < playstart_t) { |
850 // cout << "playing_t " << playing_t << " < playstart_t " | 816 // cout << "playing_t " << playing_t << " < playstart_t " |
851 // << playstart_t << endl; | 817 // << playstart_t << endl; |
852 if (/*!!! sincerequest_t > RealTime::zeroTime && */ | 818 if (m_playStartedAt + latency_t < |
853 m_playStartedAt + latency_t + stretchlat_t < | |
854 RealTime::fromSeconds(currentTime)) { | 819 RealTime::fromSeconds(currentTime)) { |
855 // cout << "but we've been playing for long enough that I think we should disregard it (it probably results from loop wrapping)" << endl; | 820 // cout << "but we've been playing for long enough that I think we should disregard it (it probably results from loop wrapping)" << endl; |
856 m_playStartFramePassed = true; | 821 m_playStartFramePassed = true; |
857 } else { | 822 } else { |
858 playing_t = playstart_t; | 823 playing_t = playstart_t; |
1001 { | 966 { |
1002 m_deviceChannelCount = count; | 967 m_deviceChannelCount = count; |
1003 } | 968 } |
1004 | 969 |
1005 void | 970 void |
1006 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a) | 971 AudioCallbackPlaySource::setAuditioningEffect(std::shared_ptr<Auditionable> a) |
1007 { | 972 { |
1008 RealTimePluginInstance *plugin = dynamic_cast<RealTimePluginInstance *>(a); | 973 SVDEBUG << "AudioCallbackPlaySource::setAuditioningEffect(" << a << ")" |
974 << endl; | |
975 | |
976 auto plugin = std::dynamic_pointer_cast<RealTimePluginInstance>(a); | |
1009 if (a && !plugin) { | 977 if (a && !plugin) { |
1010 SVCERR << "WARNING: AudioCallbackPlaySource::setAuditioningEffect: auditionable object " << a << " is not a real-time plugin instance" << endl; | 978 SVCERR << "WARNING: AudioCallbackPlaySource::setAuditioningEffect: auditionable object " << a << " is not a real-time plugin instance" << endl; |
1011 } | 979 } |
1012 | 980 |
1013 m_mutex.lock(); | 981 m_mutex.lock(); |
1014 m_auditioningPlugin = plugin; | 982 m_auditioningEffectWrapper->setEffect(plugin); |
1015 m_auditioningPluginBypassed = false; | 983 m_auditioningEffectWrapper->setBypassed(false); |
1016 m_auditioningPluginFailed = false; | |
1017 m_mutex.unlock(); | 984 m_mutex.unlock(); |
1018 | 985 |
1019 SVDEBUG << "AudioCallbackPlaySource::setAuditioningEffect: set plugin to " | 986 SVDEBUG << "AudioCallbackPlaySource::setAuditioningEffect: set plugin to " |
1020 << plugin << " and bypassed to " << m_auditioningPluginBypassed | 987 << plugin << endl; |
1021 << endl; | |
1022 } | 988 } |
1023 | 989 |
1024 void | 990 void |
1025 AudioCallbackPlaySource::setSoloModelSet(std::set<ModelId> s) | 991 AudioCallbackPlaySource::setSoloModelSet(std::set<ModelId> s) |
1026 { | 992 { |
1067 } | 1033 } |
1068 | 1034 |
1069 void | 1035 void |
1070 AudioCallbackPlaySource::setTimeStretch(double factor) | 1036 AudioCallbackPlaySource::setTimeStretch(double factor) |
1071 { | 1037 { |
1072 m_stretchRatio = factor; | 1038 checkWrappers(); |
1073 | 1039 |
1074 int rate = int(getSourceSampleRate()); | 1040 m_timeStretchWrapper->setTimeStretchRatio(factor); |
1075 if (!rate) return; // have to make our stretcher later | 1041 |
1076 | |
1077 if (m_timeStretcher || (factor == 1.0)) { | |
1078 // stretch ratio will be set in next process call if appropriate | |
1079 } else { | |
1080 m_stretcherInputCount = getTargetChannelCount(); | |
1081 RubberBandStretcher *stretcher = new RubberBandStretcher | |
1082 (rate, | |
1083 m_stretcherInputCount, | |
1084 RubberBandStretcher::OptionProcessRealTime, | |
1085 factor); | |
1086 RubberBandStretcher *monoStretcher = new RubberBandStretcher | |
1087 (rate, | |
1088 1, | |
1089 RubberBandStretcher::OptionProcessRealTime, | |
1090 factor); | |
1091 m_stretcherInputs = new float *[m_stretcherInputCount]; | |
1092 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount]; | |
1093 for (int c = 0; c < m_stretcherInputCount; ++c) { | |
1094 m_stretcherInputSizes[c] = 16384; | |
1095 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]]; | |
1096 } | |
1097 m_monoStretcher = monoStretcher; | |
1098 m_timeStretcher = stretcher; | |
1099 } | |
1100 | |
1101 emit activity(tr("Change time-stretch factor to %1").arg(factor)); | 1042 emit activity(tr("Change time-stretch factor to %1").arg(factor)); |
1102 } | 1043 } |
1103 | 1044 |
1104 int | 1045 int |
1105 AudioCallbackPlaySource::getSourceSamples(float *const *buffer, | 1046 AudioCallbackPlaySource::getSourceSamples(float *const *buffer, |
1200 } | 1141 } |
1201 } | 1142 } |
1202 | 1143 |
1203 if (count == 0) return 0; | 1144 if (count == 0) return 0; |
1204 | 1145 |
1205 RubberBandStretcher *ts = m_timeStretcher; | |
1206 RubberBandStretcher *ms = m_monoStretcher; | |
1207 | |
1208 double ratio = ts ? ts->getTimeRatio() : 1.0; | |
1209 | |
1210 if (ratio != m_stretchRatio) { | |
1211 if (!ts) { | |
1212 SVCERR << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << endl; | |
1213 m_stretchRatio = 1.0; | |
1214 } else { | |
1215 ts->setTimeRatio(m_stretchRatio); | |
1216 if (ms) ms->setTimeRatio(m_stretchRatio); | |
1217 if (m_stretchRatio >= 1.0) m_stretchMono = false; | |
1218 } | |
1219 } | |
1220 | |
1221 int stretchChannels = m_stretcherInputCount; | |
1222 if (m_stretchMono) { | |
1223 if (ms) { | |
1224 ts = ms; | |
1225 stretchChannels = 1; | |
1226 } else { | |
1227 m_stretchMono = false; | |
1228 } | |
1229 } | |
1230 | |
1231 if (m_target) { | 1146 if (m_target) { |
1232 m_lastRetrievedBlockSize = count; | 1147 m_lastRetrievedBlockSize = count; |
1233 m_lastRetrievalTimestamp = m_target->getCurrentTime(); | 1148 m_lastRetrievalTimestamp = m_target->getCurrentTime(); |
1234 } | 1149 } |
1235 | 1150 |
1236 if (!ts || ratio == 1.f) { | 1151 int got = 0; |
1237 | |
1238 int got = 0; | |
1239 | 1152 |
1240 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1153 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1241 cout << "channels == " << channels << endl; | 1154 cout << "channels == " << channels << endl; |
1242 #endif | 1155 #endif |
1243 | 1156 |
1244 for (int ch = 0; ch < channels; ++ch) { | 1157 for (int ch = 0; ch < channels; ++ch) { |
1245 | 1158 |
1246 RingBuffer<float> *rb = getReadRingBuffer(ch); | 1159 RingBuffer<float> *rb = getReadRingBuffer(ch); |
1247 | 1160 |
1248 if (rb) { | 1161 if (rb) { |
1249 | 1162 |
1250 // this is marginally more likely to leave our channels in | 1163 // this is marginally more likely to leave our channels in |
1251 // sync after a processing failure than just passing "count": | 1164 // sync after a processing failure than just passing "count": |
1252 sv_frame_t request = count; | 1165 sv_frame_t request = count; |
1253 if (ch > 0) request = got; | 1166 if (ch > 0) request = got; |
1254 | 1167 |
1255 got = rb->read(buffer[ch], int(request)); | 1168 got = rb->read(buffer[ch], int(request)); |
1256 | 1169 |
1257 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1170 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1258 cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << endl; | 1171 cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << endl; |
1259 #endif | 1172 #endif |
1260 } | 1173 } |
1261 | 1174 |
1262 for (int ch = 0; ch < channels; ++ch) { | 1175 for (int ch = 0; ch < channels; ++ch) { |
1263 for (int i = got; i < count; ++i) { | 1176 for (int i = got; i < count; ++i) { |
1264 buffer[ch][i] = 0.0; | 1177 buffer[ch][i] = 0.0; |
1265 } | 1178 } |
1266 } | 1179 } |
1267 } | 1180 } |
1268 | |
1269 applyAuditioningEffect(count, buffer); | |
1270 | 1181 |
1271 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1182 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1272 cout << "AudioCallbackPlaySource::getSamples: awakening thread" << endl; | 1183 cout << "AudioCallbackPlaySource::getSamples: awakening thread" << endl; |
1273 #endif | 1184 #endif |
1274 | 1185 |
1275 m_condition.wakeAll(); | |
1276 | |
1277 return got; | |
1278 } | |
1279 | |
1280 sv_frame_t available; | |
1281 sv_frame_t fedToStretcher = 0; | |
1282 int warned = 0; | |
1283 | |
1284 // The input block for a given output is approx output / ratio, | |
1285 // but we can't predict it exactly, for an adaptive timestretcher. | |
1286 | |
1287 while ((available = ts->available()) < count) { | |
1288 | |
1289 sv_frame_t reqd = lrint(double(count - available) / ratio); | |
1290 reqd = std::max(reqd, sv_frame_t(ts->getSamplesRequired())); | |
1291 if (reqd == 0) reqd = 1; | |
1292 | |
1293 sv_frame_t got = reqd; | |
1294 | |
1295 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | |
1296 cout << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << endl; | |
1297 #endif | |
1298 | |
1299 for (int c = 0; c < channels; ++c) { | |
1300 if (c >= m_stretcherInputCount) continue; | |
1301 if (reqd > m_stretcherInputSizes[c]) { | |
1302 if (c == 0) { | |
1303 SVDEBUG << "NOTE: resizing stretcher input buffer from " << m_stretcherInputSizes[c] << " to " << (reqd * 2) << endl; | |
1304 } | |
1305 delete[] m_stretcherInputs[c]; | |
1306 m_stretcherInputSizes[c] = reqd * 2; | |
1307 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]]; | |
1308 } | |
1309 } | |
1310 | |
1311 for (int c = 0; c < channels; ++c) { | |
1312 if (c >= m_stretcherInputCount) continue; | |
1313 RingBuffer<float> *rb = getReadRingBuffer(c); | |
1314 if (rb) { | |
1315 sv_frame_t gotHere; | |
1316 if (stretchChannels == 1 && c > 0) { | |
1317 gotHere = rb->readAdding(m_stretcherInputs[0], int(got)); | |
1318 } else { | |
1319 gotHere = rb->read(m_stretcherInputs[c], int(got)); | |
1320 } | |
1321 if (gotHere < got) got = gotHere; | |
1322 | |
1323 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | |
1324 if (c == 0) { | |
1325 cout << "feeding stretcher: got " << gotHere | |
1326 << ", " << rb->getReadSpace() << " remain" << endl; | |
1327 } | |
1328 #endif | |
1329 | |
1330 } else { | |
1331 SVCERR << "WARNING: No ring buffer available for channel " << c << " in stretcher input block" << endl; | |
1332 } | |
1333 } | |
1334 | |
1335 if (got < reqd) { | |
1336 SVCERR << "WARNING: Read underrun in playback (" | |
1337 << got << " < " << reqd << ")" << endl; | |
1338 } | |
1339 | |
1340 ts->process(m_stretcherInputs, size_t(got), false); | |
1341 | |
1342 fedToStretcher += got; | |
1343 | |
1344 if (got == 0) break; | |
1345 | |
1346 if (ts->available() == available) { | |
1347 SVCERR << "WARNING: AudioCallbackPlaySource::getSamples: Added " << got << " samples to time stretcher, created no new available output samples (warned = " << warned << ")" << endl; | |
1348 if (++warned == 5) break; | |
1349 } | |
1350 } | |
1351 | |
1352 ts->retrieve(buffer, size_t(count)); | |
1353 | |
1354 v_zero_channels(buffer + stretchChannels, channels - stretchChannels, count); | |
1355 | |
1356 applyAuditioningEffect(count, buffer); | |
1357 | |
1358 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
1359 cout << "AudioCallbackPlaySource::getSamples [stretched]: awakening thread" << endl; | |
1360 #endif | |
1361 | |
1362 m_condition.wakeAll(); | 1186 m_condition.wakeAll(); |
1363 | 1187 |
1364 return count; | 1188 return got; |
1365 } | 1189 } |
1366 | |
1367 void | |
1368 AudioCallbackPlaySource::applyAuditioningEffect(sv_frame_t count, float *const *buffers) | |
1369 { | |
1370 if (m_auditioningPluginBypassed) return; | |
1371 RealTimePluginInstance *plugin = m_auditioningPlugin; | |
1372 if (!plugin) return; | |
1373 | |
1374 if ((int)plugin->getAudioInputCount() != getTargetChannelCount()) { | |
1375 if (!m_auditioningPluginFailed) { | |
1376 SVCERR << "AudioCallbackPlaySource::applyAuditioningEffect: " | |
1377 << "Can't run plugin: plugin input count " | |
1378 << plugin->getAudioInputCount() | |
1379 << " != our channel count " << getTargetChannelCount() | |
1380 << " (future errors for this plugin will be suppressed)" | |
1381 << endl; | |
1382 m_auditioningPluginFailed = true; | |
1383 } | |
1384 return; | |
1385 } | |
1386 if ((int)plugin->getAudioOutputCount() != getTargetChannelCount()) { | |
1387 if (!m_auditioningPluginFailed) { | |
1388 SVCERR << "AudioCallbackPlaySource::applyAuditioningEffect: " | |
1389 << "Can't run plugin: plugin output count " | |
1390 << plugin->getAudioOutputCount() | |
1391 << " != our channel count " << getTargetChannelCount() | |
1392 << " (future errors for this plugin will be suppressed)" | |
1393 << endl; | |
1394 m_auditioningPluginFailed = true; | |
1395 } | |
1396 return; | |
1397 } | |
1398 if ((int)plugin->getBufferSize() < count) { | |
1399 if (!m_auditioningPluginFailed) { | |
1400 SVCERR << "AudioCallbackPlaySource::applyAuditioningEffect: " | |
1401 << "Can't run plugin: plugin buffer size " | |
1402 << plugin->getBufferSize() | |
1403 << " < our block size " << count | |
1404 << " (future errors for this plugin will be suppressed)" | |
1405 << endl; | |
1406 m_auditioningPluginFailed = true; | |
1407 } | |
1408 return; | |
1409 } | |
1410 | |
1411 float **ib = plugin->getAudioInputBuffers(); | |
1412 float **ob = plugin->getAudioOutputBuffers(); | |
1413 | |
1414 for (int c = 0; c < getTargetChannelCount(); ++c) { | |
1415 for (int i = 0; i < count; ++i) { | |
1416 ib[c][i] = buffers[c][i]; | |
1417 } | |
1418 } | |
1419 | |
1420 plugin->run(Vamp::RealTime::zeroTime, int(count)); | |
1421 | |
1422 for (int c = 0; c < getTargetChannelCount(); ++c) { | |
1423 for (int i = 0; i < count; ++i) { | |
1424 buffers[c][i] = ob[c][i]; | |
1425 } | |
1426 } | |
1427 } | |
1428 | 1190 |
1429 // Called from fill thread, m_playing true, mutex held | 1191 // Called from fill thread, m_playing true, mutex held |
1430 bool | 1192 bool |
1431 AudioCallbackPlaySource::fillBuffers() | 1193 AudioCallbackPlaySource::fillBuffers() |
1432 { | 1194 { |