comparison audioio/AudioCallbackPlaySource.cpp @ 3:75c3ea1c3a32

* Add play-selection and looping modes. Looping seems to work OK, but the plain play-selection is miscalculating current frame number to feed back to the GUI. * Cache selection rectanges wherever possible in View::paintEvent.
author Chris Cannam
date Tue, 24 Jan 2006 16:20:58 +0000
parents 97c69acdcb82
children 5865094175ea
comparison
equal deleted inserted replaced
2:df5923e33d01 3:75c3ea1c3a32
45 // preallocate some slots, to avoid reallocation in an 45 // preallocate some slots, to avoid reallocation in an
46 // un-thread-safe manner later 46 // un-thread-safe manner later
47 while (m_buffers.size() < 20) m_buffers.push_back(0); 47 while (m_buffers.size() < 20) m_buffers.push_back(0);
48 48
49 m_viewManager->setAudioPlaySource(this); 49 m_viewManager->setAudioPlaySource(this);
50
51 connect(m_viewManager, SIGNAL(selectionChanged()),
52 this, SLOT(selectionChanged()));
53 connect(m_viewManager, SIGNAL(playLoopModeChanged()),
54 this, SLOT(playLoopModeChanged()));
55 connect(m_viewManager, SIGNAL(playSelectionModeChanged()),
56 this, SLOT(playSelectionModeChanged()));
50 } 57 }
51 58
52 AudioCallbackPlaySource::~AudioCallbackPlaySource() 59 AudioCallbackPlaySource::~AudioCallbackPlaySource()
53 { 60 {
54 m_exiting = true; 61 m_exiting = true;
212 m_playing = false; 219 m_playing = false;
213 m_condition.wakeAll(); 220 m_condition.wakeAll();
214 } 221 }
215 222
216 void 223 void
224 AudioCallbackPlaySource::selectionChanged()
225 {
226 if (m_viewManager->getPlaySelectionMode()) {
227 m_mutex.lock();
228 for (size_t c = 0; c < m_bufferCount; ++c) {
229 getRingBuffer(c).reset();
230 }
231 m_mutex.unlock();
232 }
233 }
234
235 void
236 AudioCallbackPlaySource::playLoopModeChanged()
237 {
238 m_mutex.lock();
239 for (size_t c = 0; c < m_bufferCount; ++c) {
240 getRingBuffer(c).reset();
241 }
242 m_mutex.unlock();
243 }
244
245 void
246 AudioCallbackPlaySource::playSelectionModeChanged()
247 {
248 if (!m_viewManager->getSelections().empty()) {
249 m_mutex.lock();
250 for (size_t c = 0; c < m_bufferCount; ++c) {
251 getRingBuffer(c).reset();
252 }
253 m_mutex.unlock();
254 }
255 }
256
257 void
217 AudioCallbackPlaySource::setTargetBlockSize(size_t size) 258 AudioCallbackPlaySource::setTargetBlockSize(size_t size)
218 { 259 {
219 std::cerr << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl; 260 std::cerr << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
220 m_blockSize = size; 261 m_blockSize = size;
221 for (size_t i = 0; i < m_bufferCount; ++i) { 262 for (size_t i = 0; i < m_bufferCount; ++i) {
260 } 301 }
261 302
262 if (resample) { 303 if (resample) {
263 readSpace = size_t(readSpace * ratio + 0.1); 304 readSpace = size_t(readSpace * ratio + 0.1);
264 } 305 }
265
266 size_t lastRequestedFrame = 0;
267 if (m_bufferedToFrame > readSpace) {
268 lastRequestedFrame = m_bufferedToFrame - readSpace;
269 }
270
271 size_t framePlaying = lastRequestedFrame;
272 306
273 size_t latency = m_playLatency; 307 size_t latency = m_playLatency;
274 if (resample) latency = size_t(m_playLatency * ratio + 0.1); 308 if (resample) latency = size_t(m_playLatency * ratio + 0.1);
275 309
276 TimeStretcherData *timeStretcher = m_timeStretcher; 310 TimeStretcherData *timeStretcher = m_timeStretcher;
277 if (timeStretcher) { 311 if (timeStretcher) {
278 latency += timeStretcher->getStretcher(0)->getProcessingLatency(); 312 latency += timeStretcher->getStretcher(0)->getProcessingLatency();
279 } 313 }
280 314
281 if (framePlaying > latency) { 315 latency += readSpace;
282 framePlaying = framePlaying - latency; 316 size_t bufferedFrame = m_bufferedToFrame;
283 } else { 317
284 framePlaying = 0; 318 size_t framePlaying = bufferedFrame;
285 } 319 if (framePlaying > latency) framePlaying -= latency;
286 320 else framePlaying = 0;
287 #ifdef DEBUG_AUDIO_PLAY_SOURCE 321
288 std::cout << "getCurrentPlayingFrame: readSpace " << readSpace << ", lastRequestedFrame " << lastRequestedFrame << ", framePlaying " << framePlaying << ", latency " << latency << std::endl; 322 if (!m_viewManager->getPlaySelectionMode()) {
289 #endif 323 return framePlaying;
324 }
325
326 ViewManager::SelectionList selections = m_viewManager->getSelections();
327 if (selections.empty()) {
328 return framePlaying;
329 }
330
331 ViewManager::SelectionList::const_iterator i;
332
333 for (i = selections.begin(); i != selections.end(); ++i) {
334 if (i->contains(bufferedFrame)) break;
335 }
336
337 size_t f = bufferedFrame;
338
339 std::cerr << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << std::endl;
340
341 if (i == selections.end()) {
342 --i;
343 if (i->getEndFrame() + latency < f) {
344 return framePlaying;
345 } else {
346 std::cerr << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl;
347 latency -= (f - i->getEndFrame());
348 f = i->getEndFrame();
349 }
350 }
351
352 std::cerr << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl;
353
354 while (latency > 0) {
355 size_t offset = f - i->getStartFrame();
356 if (offset >= latency) {
357 if (f > latency) {
358 framePlaying = f - latency;
359 } else {
360 framePlaying = 0;
361 }
362 break;
363 } else {
364 if (i == selections.begin()) {
365 if (m_viewManager->getPlayLoopMode()) {
366 i = selections.end();
367 }
368 }
369 latency -= offset;
370 --i;
371 f = i->getEndFrame();
372 }
373 }
290 374
291 return framePlaying; 375 return framePlaying;
292 } 376 }
293 377
294 void 378 void
608 for (size_t i = 0; i < orig; ++i) { 692 for (size_t i = 0; i < orig; ++i) {
609 nonintlv[channels * i + c] = 0.0f; 693 nonintlv[channels * i + c] = 0.0f;
610 } 694 }
611 } 695 }
612 696
613 for (std::set<Model *>::iterator mi = m_models.begin(); 697 for (size_t c = 0; c < channels; ++c) {
614 mi != m_models.end(); ++mi) { 698 bufferPtrs[c] = nonintlv + c * orig;
615 699 }
616 for (size_t c = 0; c < channels; ++c) { 700
617 bufferPtrs[c] = nonintlv + c * orig; 701 bool ended = !mixModels(f, orig, bufferPtrs);
618 } 702 got = orig;
619
620 size_t gotHere = m_audioGenerator->mixModel
621 (*mi, f, orig, bufferPtrs);
622
623 got = std::max(got, gotHere);
624 }
625 703
626 // and interleave into first half 704 // and interleave into first half
627 for (size_t c = 0; c < channels; ++c) { 705 for (size_t c = 0; c < channels; ++c) {
628 for (size_t i = 0; i < orig; ++i) { 706 for (size_t i = 0; i < orig; ++i) {
629 float sample = 0; 707 float sample = 0;
662 for (size_t i = 0; i < toCopy; ++i) { 740 for (size_t i = 0; i < toCopy; ++i) {
663 tmp[i] = srcout[channels * i + c]; 741 tmp[i] = srcout[channels * i + c];
664 } 742 }
665 getRingBuffer(c).write(tmp, toCopy); 743 getRingBuffer(c).write(tmp, toCopy);
666 } 744 }
745
746 m_bufferedToFrame = f;
667 747
668 } else { 748 } else {
669 749
670 // space must be a multiple of generatorBlockSize 750 // space must be a multiple of generatorBlockSize
671 space = (space / generatorBlockSize) * generatorBlockSize; 751 space = (space / generatorBlockSize) * generatorBlockSize;
678 } 758 }
679 759
680 for (size_t c = 0; c < channels; ++c) { 760 for (size_t c = 0; c < channels; ++c) {
681 761
682 bufferPtrs[c] = tmp + c * space; 762 bufferPtrs[c] = tmp + c * space;
683 763
684 for (size_t i = 0; i < space; ++i) { 764 for (size_t i = 0; i < space; ++i) {
685 tmp[c * space + i] = 0.0f; 765 tmp[c * space + i] = 0.0f;
686 } 766 }
687 } 767 }
688 768
689 for (std::set<Model *>::iterator mi = m_models.begin(); 769 bool ended = !mixModels(f, space, bufferPtrs);
690 mi != m_models.end(); ++mi) {
691
692 got = m_audioGenerator->mixModel
693 (*mi, f, space, bufferPtrs);
694 }
695 770
696 for (size_t c = 0; c < channels; ++c) { 771 for (size_t c = 0; c < channels; ++c) {
697 772
698 got = getRingBuffer(c).write(bufferPtrs[c], space); 773 getRingBuffer(c).write(bufferPtrs[c], space);
699 774
700 #ifdef DEBUG_AUDIO_PLAY_SOURCE 775 #ifdef DEBUG_AUDIO_PLAY_SOURCE
701 std::cerr << "Wrote " << got << " frames for ch " << c << ", now " 776 std::cerr << "Wrote " << got << " frames for ch " << c << ", now "
702 << getRingBuffer(c).getReadSpace() << " to read" 777 << getRingBuffer(c).getReadSpace() << " to read"
703 << std::endl; 778 << std::endl;
704 #endif 779 #endif
705 } 780 }
706 } 781
782 m_bufferedToFrame = f;
783 //!!! 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
784 }
785 }
786
787 bool
788 AudioCallbackPlaySource::mixModels(size_t &frame, size_t count, float **buffers)
789 {
790 size_t processed = 0;
791 size_t chunkStart = frame;
792 size_t chunkSize = count;
793 size_t nextChunkStart = chunkStart + chunkSize;
707 794
708 m_bufferedToFrame = f + got; 795 bool useSelection = (m_viewManager->getPlaySelectionMode() &&
709 } 796 !m_viewManager->getSelections().empty());
797
798 static float **chunkBufferPtrs = 0;
799 static size_t chunkBufferPtrCount = 0;
800 size_t channels = getSourceChannelCount();
801
802 #ifdef DEBUG_AUDIO_PLAY_SOURCE
803 std::cerr << "Selection playback: start " << frame << ", size " << count <<", channels " << channels << std::endl;
804 #endif
805
806 if (chunkBufferPtrCount < channels) {
807 if (chunkBufferPtrs) delete[] chunkBufferPtrs;
808 chunkBufferPtrs = new float *[channels];
809 chunkBufferPtrCount = channels;
810 }
811
812 for (size_t c = 0; c < channels; ++c) {
813 chunkBufferPtrs[c] = buffers[c];
814 }
815
816 while (processed < count) {
817
818 chunkSize = count - processed;
819 nextChunkStart = chunkStart + chunkSize;
820
821 if (useSelection) {
822
823 Selection selection =
824 m_viewManager->getContainingSelection(chunkStart, true);
825
826 if (selection.isEmpty()) {
827 if (m_viewManager->getPlayLoopMode()) {
828 selection = *m_viewManager->getSelections().begin();
829 chunkStart = selection.getStartFrame();
830 }
831 }
832
833 if (selection.isEmpty()) {
834
835 chunkSize = 0;
836 nextChunkStart = chunkStart;
837
838 } else {
839
840 if (chunkStart < selection.getStartFrame()) {
841 chunkStart = selection.getStartFrame();
842 }
843
844 nextChunkStart = std::min(chunkStart + chunkSize,
845 selection.getEndFrame());
846
847 chunkSize = nextChunkStart - chunkStart;
848 }
849 }
850
851 if (!chunkSize) {
852 #ifdef DEBUG_AUDIO_PLAY_SOURCE
853 std::cerr << "Ending selection playback at " << nextChunkStart << std::endl;
854 #endif
855 // We need to maintain full buffers so that the other
856 // thread can tell where it's got to in the playback -- so
857 // return the full amount here
858 frame = frame + count;
859 return false;
860 }
861
862 #ifdef DEBUG_AUDIO_PLAY_SOURCE
863 std::cerr << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl;
864 #endif
865
866 size_t got = 0;
867
868 for (std::set<Model *>::iterator mi = m_models.begin();
869 mi != m_models.end(); ++mi) {
870
871 got = m_audioGenerator->mixModel(*mi, chunkStart,
872 chunkSize, chunkBufferPtrs);
873 }
874
875 for (size_t c = 0; c < channels; ++c) {
876 chunkBufferPtrs[c] += chunkSize;
877 }
878
879 processed += chunkSize;
880 chunkStart = nextChunkStart;
881 }
882
883 #ifdef DEBUG_AUDIO_PLAY_SOURCE
884 std::cerr << "Returning selection playback at " << nextChunkStart << std::endl;
885 #endif
886
887 frame = nextChunkStart;
888 return true;
889 }
710 890
711 void 891 void
712 AudioCallbackPlaySource::AudioCallbackPlaySourceFillThread::run() 892 AudioCallbackPlaySource::AudioCallbackPlaySourceFillThread::run()
713 { 893 {
714 AudioCallbackPlaySource &s(m_source); 894 AudioCallbackPlaySource &s(m_source);