comparison audioio/AudioCallbackPlaySource.cpp @ 6:f3d777b693f7

* Introduce potentially-separate read and write ring buffers, so we can swap in a new set when something changes -- thus allowing us to respond quickly when something changes during playback, without losing the long buffers * Some fixes for display & editing
author Chris Cannam
date Fri, 27 Jan 2006 18:04:07 +0000
parents 2edc0757ca75
children 3a41ba527b4a
comparison
equal deleted inserted replaced
5:2edc0757ca75 6:f3d777b693f7
16 #include "model/DenseTimeValueModel.h" 16 #include "model/DenseTimeValueModel.h"
17 #include "model/SparseOneDimensionalModel.h" 17 #include "model/SparseOneDimensionalModel.h"
18 #include "dsp/timestretching/IntegerTimeStretcher.h" 18 #include "dsp/timestretching/IntegerTimeStretcher.h"
19 19
20 #include <iostream> 20 #include <iostream>
21 #include <cassert>
21 22
22 //#define DEBUG_AUDIO_PLAY_SOURCE 1 23 //#define DEBUG_AUDIO_PLAY_SOURCE 1
23 24
24 //const size_t AudioCallbackPlaySource::m_ringBufferSize = 102400; 25 //const size_t AudioCallbackPlaySource::m_ringBufferSize = 102400;
25 const size_t AudioCallbackPlaySource::m_ringBufferSize = 131071; 26 const size_t AudioCallbackPlaySource::m_ringBufferSize = 131071;
26 27
27 AudioCallbackPlaySource::AudioCallbackPlaySource(ViewManager *manager) : 28 AudioCallbackPlaySource::AudioCallbackPlaySource(ViewManager *manager) :
28 m_viewManager(manager), 29 m_viewManager(manager),
29 m_audioGenerator(new AudioGenerator(manager)), 30 m_audioGenerator(new AudioGenerator(manager)),
30 m_bufferCount(0), 31 m_readBuffers(0),
32 m_writeBuffers(0),
33 m_sourceChannelCount(0),
31 m_blockSize(1024), 34 m_blockSize(1024),
32 m_sourceSampleRate(0), 35 m_sourceSampleRate(0),
33 m_targetSampleRate(0), 36 m_targetSampleRate(0),
34 m_playLatency(0), 37 m_playLatency(0),
35 m_playing(false), 38 m_playing(false),
41 m_slowdownCounter(0), 44 m_slowdownCounter(0),
42 m_timeStretcher(0), 45 m_timeStretcher(0),
43 m_fillThread(0), 46 m_fillThread(0),
44 m_converter(0) 47 m_converter(0)
45 { 48 {
46 // preallocate some slots, to avoid reallocation in an
47 // un-thread-safe manner later
48 while (m_buffers.size() < 20) m_buffers.push_back(0);
49
50 m_viewManager->setAudioPlaySource(this); 49 m_viewManager->setAudioPlaySource(this);
51 50
52 connect(m_viewManager, SIGNAL(selectionChanged()), 51 connect(m_viewManager, SIGNAL(selectionChanged()),
53 this, SLOT(selectionChanged())); 52 this, SLOT(selectionChanged()));
54 connect(m_viewManager, SIGNAL(playLoopModeChanged()), 53 connect(m_viewManager, SIGNAL(playLoopModeChanged()),
66 m_fillThread->wait(); 65 m_fillThread->wait();
67 delete m_fillThread; 66 delete m_fillThread;
68 } 67 }
69 68
70 clearModels(); 69 clearModels();
70
71 if (m_readBuffers != m_writeBuffers) {
72 delete m_readBuffers;
73 }
74
75 delete m_writeBuffers;
76
77 m_bufferScavenger.scavenge(true);
71 } 78 }
72 79
73 void 80 void
74 AudioCallbackPlaySource::addModel(Model *model) 81 AudioCallbackPlaySource::addModel(Model *model)
75 { 82 {
94 << " vs " << m_sourceSampleRate 101 << " vs " << m_sourceSampleRate
95 << "), playback will be wrong" 102 << "), playback will be wrong"
96 << std::endl; 103 << std::endl;
97 } 104 }
98 105
99 size_t sz = m_ringBufferSize;
100 if (m_bufferCount > 0) {
101 sz = m_buffers[0]->getSize();
102 }
103
104 size_t modelChannels = 1; 106 size_t modelChannels = 1;
105 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model); 107 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model);
106 if (dtvm) modelChannels = dtvm->getChannelCount(); 108 if (dtvm) modelChannels = dtvm->getChannelCount();
107 109 if (modelChannels > m_sourceChannelCount) {
108 while (m_bufferCount < modelChannels) { 110 m_sourceChannelCount = modelChannels;
109 111 }
110 if (m_buffers.size() < modelChannels) { 112
111 // This is a hideously chancy operation -- the RT thread 113 std::cerr << "Adding model with " << modelChannels << " channels " << std::endl;
112 // could be using this vector. We allocated several slots 114
113 // in the ctor to avoid exactly this, but if we ever end 115 if (!m_writeBuffers || m_writeBuffers->size() < modelChannels) {
114 // up with more channels than that (!) then we're just 116 m_audioGenerator->setTargetChannelCount(modelChannels);
115 // going to have to risk it 117 }
116 m_buffers.push_back(new RingBuffer<float>(sz)); 118
117 119 m_audioGenerator->addModel(model);
118 } else { 120
119 // The usual case 121 if (!m_writeBuffers || (m_writeBuffers->size() < modelChannels)) {
120 m_buffers[m_bufferCount] = new RingBuffer<float>(sz); 122 clearRingBuffers(true, modelChannels);
121 }
122
123 ++m_bufferCount;
124 buffersChanged = true; 123 buffersChanged = true;
125 } 124 } else {
126 125 clearRingBuffers(true);
127 if (buffersChanged) {
128 m_audioGenerator->setTargetChannelCount(m_bufferCount);
129 } 126 }
130 127
131 if (buffersChanged || srChanged) { 128 if (buffersChanged || srChanged) {
132 if (m_converter) { 129 if (m_converter) {
133 src_delete(m_converter); 130 src_delete(m_converter);
134 m_converter = 0; 131 m_converter = 0;
135 } 132 }
136 } 133 }
137 134
138 m_audioGenerator->addModel(model);
139
140 m_mutex.unlock(); 135 m_mutex.unlock();
141 136
142 if (!m_fillThread) { 137 if (!m_fillThread) {
143 m_fillThread = new AudioCallbackPlaySourceFillThread(*this); 138 m_fillThread = new AudioCallbackPlaySourceFillThread(*this);
144 m_fillThread->start(); 139 m_fillThread->start();
149 #endif 144 #endif
150 145
151 if (buffersChanged || srChanged) { 146 if (buffersChanged || srChanged) {
152 emit modelReplaced(); 147 emit modelReplaced();
153 } 148 }
149
150 m_condition.wakeAll();
154 } 151 }
155 152
156 void 153 void
157 AudioCallbackPlaySource::removeModel(Model *model) 154 AudioCallbackPlaySource::removeModel(Model *model)
158 { 155 {
176 m_lastModelEndFrame = lastEnd; 173 m_lastModelEndFrame = lastEnd;
177 174
178 m_audioGenerator->removeModel(model); 175 m_audioGenerator->removeModel(model);
179 176
180 m_mutex.unlock(); 177 m_mutex.unlock();
178
179 clearRingBuffers();
181 } 180 }
182 181
183 void 182 void
184 AudioCallbackPlaySource::clearModels() 183 AudioCallbackPlaySource::clearModels()
185 { 184 {
198 197
199 m_sourceSampleRate = 0; 198 m_sourceSampleRate = 0;
200 199
201 m_mutex.unlock(); 200 m_mutex.unlock();
202 } 201 }
202
203 void
204 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, size_t count)
205 {
206 if (!haveLock) m_mutex.lock();
207
208 if (count == 0) {
209 if (m_writeBuffers) count = m_writeBuffers->size();
210 }
211
212 if (m_readBuffers != m_writeBuffers) {
213 delete m_writeBuffers;
214 }
215
216 m_writeBuffers = new RingBufferVector;
217
218 for (size_t i = 0; i < count; ++i) {
219 m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize));
220 }
221
222 std::cerr << "AudioCallbackPlaySource::clearRingBuffers: Created "
223 << count << " write buffers" << std::endl;
224
225 if (!haveLock) {
226 m_mutex.unlock();
227 m_condition.wakeAll();
228 }
229 }
203 230
204 void 231 void
205 AudioCallbackPlaySource::play(size_t startFrame) 232 AudioCallbackPlaySource::play(size_t startFrame)
206 { 233 {
207 if (m_viewManager->getPlaySelectionMode() && 234 if (m_viewManager->getPlaySelectionMode() &&
227 254
228 // The fill thread will automatically empty its buffers before 255 // The fill thread will automatically empty its buffers before
229 // starting again if we have not so far been playing, but not if 256 // starting again if we have not so far been playing, but not if
230 // we're just re-seeking. 257 // we're just re-seeking.
231 258
259 m_mutex.lock();
232 if (m_playing) { 260 if (m_playing) {
233 m_mutex.lock();
234 m_bufferedToFrame = startFrame; 261 m_bufferedToFrame = startFrame;
235 for (size_t c = 0; c < m_bufferCount; ++c) { 262 if (m_readBuffers) {
236 getRingBuffer(c).reset(); 263 for (size_t c = 0; c < getSourceChannelCount(); ++c) {
237 if (m_converter) src_reset(m_converter); 264 RingBuffer<float> *rb = getReadRingBuffer(c);
238 } 265 if (rb) rb->reset();
239 m_mutex.unlock(); 266 }
267 }
268 if (m_converter) src_reset(m_converter);
240 } else { 269 } else {
270 if (m_converter) src_reset(m_converter);
241 m_bufferedToFrame = startFrame; 271 m_bufferedToFrame = startFrame;
242 } 272 }
273 m_mutex.unlock();
243 274
244 m_audioGenerator->reset(); 275 m_audioGenerator->reset();
245 276
246 m_playing = true; 277 m_playing = true;
247 m_condition.wakeAll(); 278 m_condition.wakeAll();
258 289
259 void 290 void
260 AudioCallbackPlaySource::selectionChanged() 291 AudioCallbackPlaySource::selectionChanged()
261 { 292 {
262 if (m_viewManager->getPlaySelectionMode()) { 293 if (m_viewManager->getPlaySelectionMode()) {
263 m_mutex.lock(); 294 clearRingBuffers();
264 for (size_t c = 0; c < m_bufferCount; ++c) {
265 getRingBuffer(c).reset();
266 }
267 m_mutex.unlock();
268 m_condition.wakeAll();
269 } 295 }
270 } 296 }
271 297
272 void 298 void
273 AudioCallbackPlaySource::playLoopModeChanged() 299 AudioCallbackPlaySource::playLoopModeChanged()
274 { 300 {
301 clearRingBuffers();
275 } 302 }
276 303
277 void 304 void
278 AudioCallbackPlaySource::playSelectionModeChanged() 305 AudioCallbackPlaySource::playSelectionModeChanged()
279 { 306 {
280 if (!m_viewManager->getSelections().empty()) { 307 if (!m_viewManager->getSelections().empty()) {
281 m_mutex.lock(); 308 clearRingBuffers();
282 for (size_t c = 0; c < m_bufferCount; ++c) {
283 getRingBuffer(c).reset();
284 }
285 m_mutex.unlock();
286 m_condition.wakeAll();
287 } 309 }
288 } 310 }
289 311
290 void 312 void
291 AudioCallbackPlaySource::setTargetBlockSize(size_t size) 313 AudioCallbackPlaySource::setTargetBlockSize(size_t size)
292 { 314 {
293 std::cerr << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; 315 std::cerr << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
316 assert(size < m_ringBufferSize);
294 m_blockSize = size; 317 m_blockSize = size;
295 for (size_t i = 0; i < m_bufferCount; ++i) {
296 getRingBuffer(i).resize(m_ringBufferSize);
297 }
298 } 318 }
299 319
300 size_t 320 size_t
301 AudioCallbackPlaySource::getTargetBlockSize() const 321 AudioCallbackPlaySource::getTargetBlockSize() const
302 { 322 {
327 ratio = double(getSourceSampleRate()) / double(getTargetSampleRate()); 347 ratio = double(getSourceSampleRate()) / double(getTargetSampleRate());
328 } 348 }
329 349
330 size_t readSpace = 0; 350 size_t readSpace = 0;
331 for (size_t c = 0; c < getSourceChannelCount(); ++c) { 351 for (size_t c = 0; c < getSourceChannelCount(); ++c) {
332 size_t spaceHere = getRingBuffer(c).getReadSpace(); 352 RingBuffer<float> *rb = getReadRingBuffer(c);
333 if (c == 0 || spaceHere < readSpace) readSpace = spaceHere; 353 if (rb) {
354 size_t spaceHere = rb->getReadSpace();
355 if (c == 0 || spaceHere < readSpace) readSpace = spaceHere;
356 }
334 } 357 }
335 358
336 if (resample) { 359 if (resample) {
337 readSpace = size_t(readSpace * ratio + 0.1); 360 readSpace = size_t(readSpace * ratio + 0.1);
338 } 361 }
453 m_targetSampleRate = sr; 476 m_targetSampleRate = sr;
454 477
455 if (getSourceSampleRate() != getTargetSampleRate()) { 478 if (getSourceSampleRate() != getTargetSampleRate()) {
456 479
457 int err = 0; 480 int err = 0;
458 m_converter = src_new(SRC_SINC_BEST_QUALITY, m_bufferCount, &err); 481 m_converter = src_new(SRC_SINC_BEST_QUALITY, m_sourceChannelCount, &err);
459 if (!m_converter) { 482 if (!m_converter) {
460 std::cerr 483 std::cerr
461 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " 484 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: "
462 << src_strerror(err) << std::endl; 485 << src_strerror(err) << std::endl;
463 } 486 }
474 } 497 }
475 498
476 size_t 499 size_t
477 AudioCallbackPlaySource::getSourceChannelCount() const 500 AudioCallbackPlaySource::getSourceChannelCount() const
478 { 501 {
479 return m_bufferCount; 502 return m_sourceChannelCount;
480 } 503 }
481 504
482 size_t 505 size_t
483 AudioCallbackPlaySource::getSourceSampleRate() const 506 AudioCallbackPlaySource::getSourceSampleRate() const
484 { 507 {
586 609
587 size_t got = 0; 610 size_t got = 0;
588 611
589 for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { 612 for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) {
590 613
591 RingBuffer<float> &rb = *m_buffers[ch]; 614 RingBuffer<float> *rb = getReadRingBuffer(ch);
592 615
593 // this is marginally more likely to leave our channels in 616 if (rb) {
594 // sync after a processing failure than just passing "count": 617
595 size_t request = count; 618 // this is marginally more likely to leave our channels in
596 if (ch > 0) request = got; 619 // sync after a processing failure than just passing "count":
597 620 size_t request = count;
598 got = rb.read(buffer[ch], request); 621 if (ch > 0) request = got;
622
623 got = rb->read(buffer[ch], request);
599 624
600 #ifdef DEBUG_AUDIO_PLAY_SOURCE 625 #ifdef DEBUG_AUDIO_PLAY_SOURCE
601 std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << ", signalling for more (possibly)" << std::endl; 626 std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << ", signalling for more (possibly)" << std::endl;
602 #endif 627 #endif
603 } 628 }
604 629
605 for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { 630 for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) {
606 for (size_t i = got; i < count; ++i) { 631 for (size_t i = got; i < count; ++i) {
607 buffer[ch][i] = 0.0; 632 buffer[ch][i] = 0.0;
633 }
608 } 634 }
609 } 635 }
610 636
611 m_condition.wakeAll(); 637 m_condition.wakeAll();
612 return got; 638 return got;
617 size_t got = 0; 643 size_t got = 0;
618 double *ib = timeStretcher->getInputBuffer(); 644 double *ib = timeStretcher->getInputBuffer();
619 645
620 for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) { 646 for (size_t ch = 0; ch < getSourceChannelCount(); ++ch) {
621 647
622 RingBuffer<float> &rb = *m_buffers[ch]; 648 RingBuffer<float> *rb = getReadRingBuffer(ch);
623 size_t request = count; 649
624 if (ch > 0) request = got; // see above 650 if (rb) {
625 got = rb.read(buffer[ch], request); 651
626 652 size_t request = count;
627 #ifdef DEBUG_AUDIO_PLAY_SOURCE 653 if (ch > 0) request = got; // see above
628 std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << ", running time stretcher" << std::endl; 654 got = rb->read(buffer[ch], request);
629 #endif 655
630 656 #ifdef DEBUG_AUDIO_PLAY_SOURCE
631 for (size_t i = 0; i < count; ++i) { 657 std::cout << "AudioCallbackPlaySource::getSamples: got " << got << " samples on channel " << ch << ", running time stretcher" << std::endl;
632 ib[i] = buffer[ch][i]; 658 #endif
633 } 659
660 for (size_t i = 0; i < count; ++i) {
661 ib[i] = buffer[ch][i];
662 }
634 663
635 timeStretcher->run(ch); 664 timeStretcher->run(ch);
665 }
636 } 666 }
637 667
638 } else if (m_slowdownCounter >= timeStretcher->getFactor()) { 668 } else if (m_slowdownCounter >= timeStretcher->getFactor()) {
639 // reset this in case the factor has changed leaving the 669 // reset this in case the factor has changed leaving the
640 // counter out of range 670 // counter out of range
657 if (m_slowdownCounter == 0) m_condition.wakeAll(); 687 if (m_slowdownCounter == 0) m_condition.wakeAll();
658 m_slowdownCounter = (m_slowdownCounter + 1) % timeStretcher->getFactor(); 688 m_slowdownCounter = (m_slowdownCounter + 1) % timeStretcher->getFactor();
659 return count; 689 return count;
660 } 690 }
661 691
692 // Called from fill thread, m_playing true, mutex held
662 void 693 void
663 AudioCallbackPlaySource::fillBuffers() 694 AudioCallbackPlaySource::fillBuffers()
664 { 695 {
665 static float *tmp = 0; 696 static float *tmp = 0;
666 static size_t tmpSize = 0; 697 static size_t tmpSize = 0;
667 698
668 size_t space = 0; 699 size_t space = 0;
669 for (size_t c = 0; c < m_bufferCount; ++c) { 700 for (size_t c = 0; c < getSourceChannelCount(); ++c) {
670 size_t spaceHere = getRingBuffer(c).getWriteSpace(); 701 RingBuffer<float> *wb = getWriteRingBuffer(c);
671 if (c == 0 || spaceHere < space) space = spaceHere; 702 if (wb) {
703 size_t spaceHere = wb->getWriteSpace();
704 if (c == 0 || spaceHere < space) space = spaceHere;
705 }
672 } 706 }
673 707
674 if (space == 0) return; 708 if (space == 0) return;
675 709
676 #ifdef DEBUG_AUDIO_PLAY_SOURCE 710 #ifdef DEBUG_AUDIO_PLAY_SOURCE
753 787
754 for (size_t c = 0; c < channels; ++c) { 788 for (size_t c = 0; c < channels; ++c) {
755 bufferPtrs[c] = nonintlv + c * orig; 789 bufferPtrs[c] = nonintlv + c * orig;
756 } 790 }
757 791
758 bool ended = !mixModels(f, orig, bufferPtrs); 792 got = mixModels(f, orig, bufferPtrs);
759 got = orig;
760 793
761 // and interleave into first half 794 // and interleave into first half
762 for (size_t c = 0; c < channels; ++c) { 795 for (size_t c = 0; c < channels; ++c) {
763 for (size_t i = 0; i < orig; ++i) { 796 for (size_t i = 0; i < got; ++i) {
764 float sample = 0; 797 float sample = nonintlv[c * got + i];
765 if (i < got) {
766 sample = nonintlv[c * orig + i];
767 }
768 intlv[channels * i + c] = sample; 798 intlv[channels * i + c] = sample;
769 } 799 }
770 } 800 }
771 801
772 SRC_DATA data; 802 SRC_DATA data;
773 data.data_in = intlv; 803 data.data_in = intlv;
774 data.data_out = srcout; 804 data.data_out = srcout;
775 data.input_frames = orig; 805 data.input_frames = got;
776 data.output_frames = work; 806 data.output_frames = work;
777 data.src_ratio = ratio; 807 data.src_ratio = ratio;
778 data.end_of_input = 0; 808 data.end_of_input = 0;
779 809
780 int err = src_process(m_converter, &data); 810 int err = src_process(m_converter, &data);
781 size_t toCopy = size_t(work * ratio + 0.1); 811 // size_t toCopy = size_t(work * ratio + 0.1);
782 812 size_t toCopy = size_t(got * ratio + 0.1);
813
783 if (err) { 814 if (err) {
784 std::cerr 815 std::cerr
785 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: " 816 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: "
786 << src_strerror(err) << std::endl; 817 << src_strerror(err) << std::endl;
787 //!!! Then what? 818 //!!! Then what?
795 826
796 for (size_t c = 0; c < channels; ++c) { 827 for (size_t c = 0; c < channels; ++c) {
797 for (size_t i = 0; i < toCopy; ++i) { 828 for (size_t i = 0; i < toCopy; ++i) {
798 tmp[i] = srcout[channels * i + c]; 829 tmp[i] = srcout[channels * i + c];
799 } 830 }
800 getRingBuffer(c).write(tmp, toCopy); 831 RingBuffer<float> *wb = getWriteRingBuffer(c);
832 if (wb) wb->write(tmp, toCopy);
801 } 833 }
802 834
803 m_bufferedToFrame = f; 835 m_bufferedToFrame = f;
804 836
805 } else { 837 } else {
821 for (size_t i = 0; i < space; ++i) { 853 for (size_t i = 0; i < space; ++i) {
822 tmp[c * space + i] = 0.0f; 854 tmp[c * space + i] = 0.0f;
823 } 855 }
824 } 856 }
825 857
826 bool ended = !mixModels(f, space, bufferPtrs); 858 size_t got = mixModels(f, space, bufferPtrs);
827 859
828 for (size_t c = 0; c < channels; ++c) { 860 for (size_t c = 0; c < channels; ++c) {
829 861
830 getRingBuffer(c).write(bufferPtrs[c], space); 862 RingBuffer<float> *wb = getWriteRingBuffer(c);
831 863 if (wb) wb->write(bufferPtrs[c], got);
832 #ifdef DEBUG_AUDIO_PLAY_SOURCE 864
833 std::cerr << "Wrote " << got << " frames for ch " << c << ", now " 865 #ifdef DEBUG_AUDIO_PLAY_SOURCE
834 << getRingBuffer(c).getReadSpace() << " to read" 866 if (wb)
835 << std::endl; 867 std::cerr << "Wrote " << got << " frames for ch " << c << ", now "
868 << wb->getReadSpace() << " to read"
869 << std::endl;
836 #endif 870 #endif
837 } 871 }
838 872
839 m_bufferedToFrame = f; 873 m_bufferedToFrame = f;
840 //!!! how do we know when ended? need to mark up a fully-buffered flag and check this if we find the buffers empty in getSourceSamples 874 //!!! how do we know when ended? need to mark up a fully-buffered flag and check this if we find the buffers empty in getSourceSamples
841 } 875 }
842 } 876 }
843 877
844 bool 878 size_t
845 AudioCallbackPlaySource::mixModels(size_t &frame, size_t count, float **buffers) 879 AudioCallbackPlaySource::mixModels(size_t &frame, size_t count, float **buffers)
846 { 880 {
847 size_t processed = 0; 881 size_t processed = 0;
848 size_t chunkStart = frame; 882 size_t chunkStart = frame;
849 size_t chunkSize = count; 883 size_t chunkSize = count;
884 size_t selectionSize = 0;
850 size_t nextChunkStart = chunkStart + chunkSize; 885 size_t nextChunkStart = chunkStart + chunkSize;
851 886
852 bool looping = m_viewManager->getPlayLoopMode(); 887 bool looping = m_viewManager->getPlayLoopMode();
853 bool constrained = (m_viewManager->getPlaySelectionMode() && 888 bool constrained = (m_viewManager->getPlaySelectionMode() &&
854 !m_viewManager->getSelections().empty()); 889 !m_viewManager->getSelections().empty());
873 908
874 while (processed < count) { 909 while (processed < count) {
875 910
876 chunkSize = count - processed; 911 chunkSize = count - processed;
877 nextChunkStart = chunkStart + chunkSize; 912 nextChunkStart = chunkStart + chunkSize;
913 selectionSize = 0;
878 914
879 size_t fadeIn = 0, fadeOut = 0; 915 size_t fadeIn = 0, fadeOut = 0;
880 916
881 if (constrained) { 917 if (constrained) {
882 918
896 chunkSize = 0; 932 chunkSize = 0;
897 nextChunkStart = chunkStart; 933 nextChunkStart = chunkStart;
898 934
899 } else { 935 } else {
900 936
937 selectionSize =
938 selection.getEndFrame() -
939 selection.getStartFrame();
940
901 if (chunkStart < selection.getStartFrame()) { 941 if (chunkStart < selection.getStartFrame()) {
902 chunkStart = selection.getStartFrame(); 942 chunkStart = selection.getStartFrame();
903 fadeIn = 50; 943 fadeIn = 50;
904 } 944 }
905 945
906 nextChunkStart = chunkStart + chunkSize; 946 nextChunkStart = chunkStart + chunkSize;
907 947
908 if (nextChunkStart > selection.getEndFrame()) { 948 if (nextChunkStart >= selection.getEndFrame()) {
909 nextChunkStart = selection.getEndFrame(); 949 nextChunkStart = selection.getEndFrame();
910 fadeOut = 50; 950 fadeOut = 50;
911 } 951 }
912 952
913 chunkSize = nextChunkStart - chunkStart; 953 chunkSize = nextChunkStart - chunkStart;
922 chunkSize = m_lastModelEndFrame - chunkStart; 962 chunkSize = m_lastModelEndFrame - chunkStart;
923 } 963 }
924 nextChunkStart = chunkStart + chunkSize; 964 nextChunkStart = chunkStart + chunkSize;
925 } 965 }
926 966
967 // std::cerr << "chunkStart " << chunkStart << ", chunkSize " << chunkSize << ", nextChunkStart " << nextChunkStart << ", frame " << frame << ", count " << count << ", processed " << processed << std::endl;
968
927 if (!chunkSize) { 969 if (!chunkSize) {
928 #ifdef DEBUG_AUDIO_PLAY_SOURCE 970 #ifdef DEBUG_AUDIO_PLAY_SOURCE
929 std::cerr << "Ending selection playback at " << nextChunkStart << std::endl; 971 std::cerr << "Ending selection playback at " << nextChunkStart << std::endl;
930 #endif 972 #endif
931 // We need to maintain full buffers so that the other 973 // We need to maintain full buffers so that the other
932 // thread can tell where it's got to in the playback -- so 974 // thread can tell where it's got to in the playback -- so
933 // return the full amount here 975 // return the full amount here
934 frame = frame + count; 976 frame = frame + count;
935 return false; 977 return count;
936 } 978 }
937 979
938 #ifdef DEBUG_AUDIO_PLAY_SOURCE 980 #ifdef DEBUG_AUDIO_PLAY_SOURCE
939 std::cerr << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl; 981 std::cerr << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl;
940 #endif 982 #endif
941 983
942 size_t got = 0; 984 size_t got = 0;
943 985
944 if (chunkSize < 100) { 986 if (selectionSize < 100) {
945 fadeIn = 0; 987 fadeIn = 0;
946 fadeOut = 0; 988 fadeOut = 0;
947 } else if (chunkSize < 300) { 989 } else if (selectionSize < 300) {
948 if (fadeIn > 0) fadeIn = 10; 990 if (fadeIn > 0) fadeIn = 10;
949 if (fadeOut > 0) fadeOut = 10; 991 if (fadeOut > 0) fadeOut = 10;
950 } 992 }
951 993
952 if (fadeIn > 0) { 994 if (fadeIn > 0) {
954 fadeIn = processed * 2; 996 fadeIn = processed * 2;
955 } 997 }
956 } 998 }
957 999
958 if (fadeOut > 0) { 1000 if (fadeOut > 0) {
959 if ((count - processed) * 2 < fadeOut) { 1001 if ((count - processed - chunkSize) * 2 < fadeOut) {
960 fadeOut = (count - processed) * 2; 1002 fadeOut = (count - processed - chunkSize) * 2;
961 } 1003 }
962 } 1004 }
963 1005
964 for (std::set<Model *>::iterator mi = m_models.begin(); 1006 for (std::set<Model *>::iterator mi = m_models.begin();
965 mi != m_models.end(); ++mi) { 1007 mi != m_models.end(); ++mi) {
980 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1022 #ifdef DEBUG_AUDIO_PLAY_SOURCE
981 std::cerr << "Returning selection playback at " << nextChunkStart << std::endl; 1023 std::cerr << "Returning selection playback at " << nextChunkStart << std::endl;
982 #endif 1024 #endif
983 1025
984 frame = nextChunkStart; 1026 frame = nextChunkStart;
985 return true; 1027 return processed;
986 } 1028 }
987 1029
988 void 1030 void
989 AudioCallbackPlaySource::AudioCallbackPlaySourceFillThread::run() 1031 AudioCallbackPlaySource::AudioCallbackPlaySourceFillThread::run()
990 { 1032 {
997 s.m_mutex.lock(); 1039 s.m_mutex.lock();
998 1040
999 bool previouslyPlaying = s.m_playing; 1041 bool previouslyPlaying = s.m_playing;
1000 1042
1001 while (!s.m_exiting) { 1043 while (!s.m_exiting) {
1044
1045 if (s.m_readBuffers != s.m_writeBuffers) {
1046 s.m_bufferScavenger.claim(s.m_readBuffers);
1047 s.m_readBuffers = s.m_writeBuffers;
1048 std::cerr << "unified" << std::endl;
1049 }
1050
1051 s.m_bufferScavenger.scavenge();
1002 1052
1003 s.m_timeStretcherScavenger.scavenge(); 1053 s.m_timeStretcherScavenger.scavenge();
1004 1054
1005 float ms = 100; 1055 float ms = 100;
1006 if (s.getSourceSampleRate() > 0) { 1056 if (s.getSourceSampleRate() > 0) {
1027 if (playing && !previouslyPlaying) { 1077 if (playing && !previouslyPlaying) {
1028 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1078 #ifdef DEBUG_AUDIO_PLAY_SOURCE
1029 std::cout << "AudioCallbackPlaySourceFillThread: playback state changed, resetting" << std::endl; 1079 std::cout << "AudioCallbackPlaySourceFillThread: playback state changed, resetting" << std::endl;
1030 #endif 1080 #endif
1031 for (size_t c = 0; c < s.getSourceChannelCount(); ++c) { 1081 for (size_t c = 0; c < s.getSourceChannelCount(); ++c) {
1032 s.getRingBuffer(c).reset(); 1082 RingBuffer<float> *rb = s.getReadRingBuffer(c);
1083 if (rb) rb->reset();
1033 } 1084 }
1034 } 1085 }
1035 previouslyPlaying = playing; 1086 previouslyPlaying = playing;
1036
1037 if (!playing) continue;
1038 1087
1039 s.fillBuffers(); 1088 s.fillBuffers();
1040 } 1089 }
1041 1090
1042 s.m_mutex.unlock(); 1091 s.m_mutex.unlock();