Mercurial > hg > svapp
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(); |