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 {