comparison audioio/AudioCallbackPlaySource.cpp @ 4:5865094175ea

* Fix update and play limits for play-selection mode when not looping * Fix playback in loop mode when no selection -- but the GUI update for this is still wrong on the flyback * Various fixes and improvements to making selections, particularly during playback * Draw selection under non-opaque non-scrollable layers, so as to improve cacheing * Show selection limits as text when drawing selection * Allow user to find missing audio files when loading session * Cross-fade selections when in play-selection mode -- mostly. We don't cross-fade on a processing block boundary, and unfortunately with short selections the selection boundary is quite likely to coincide with a block boundary.
author Chris Cannam
date Wed, 25 Jan 2006 17:46:28 +0000
parents 75c3ea1c3a32
children 2edc0757ca75
comparison
equal deleted inserted replaced
3:75c3ea1c3a32 4:5865094175ea
33 m_targetSampleRate(0), 33 m_targetSampleRate(0),
34 m_playLatency(0), 34 m_playLatency(0),
35 m_playing(false), 35 m_playing(false),
36 m_exiting(false), 36 m_exiting(false),
37 m_bufferedToFrame(0), 37 m_bufferedToFrame(0),
38 m_lastModelEndFrame(0),
38 m_outputLeft(0.0), 39 m_outputLeft(0.0),
39 m_outputRight(0.0), 40 m_outputRight(0.0),
40 m_slowdownCounter(0), 41 m_slowdownCounter(0),
41 m_timeStretcher(0), 42 m_timeStretcher(0),
42 m_fillThread(0), 43 m_fillThread(0),
73 AudioCallbackPlaySource::addModel(Model *model) 74 AudioCallbackPlaySource::addModel(Model *model)
74 { 75 {
75 m_mutex.lock(); 76 m_mutex.lock();
76 77
77 m_models.insert(model); 78 m_models.insert(model);
79 if (model->getEndFrame() > m_lastModelEndFrame) {
80 m_lastModelEndFrame = model->getEndFrame();
81 }
78 82
79 bool buffersChanged = false, srChanged = false; 83 bool buffersChanged = false, srChanged = false;
80 84
81 if (m_sourceSampleRate == 0) { 85 if (m_sourceSampleRate == 0) {
82 86
162 m_converter = 0; 166 m_converter = 0;
163 } 167 }
164 m_sourceSampleRate = 0; 168 m_sourceSampleRate = 0;
165 } 169 }
166 170
171 size_t lastEnd = 0;
172 for (std::set<Model *>::const_iterator i = m_models.begin();
173 i != m_models.end(); ++i) {
174 if ((*i)->getEndFrame() > lastEnd) lastEnd = (*i)->getEndFrame();
175 }
176 m_lastModelEndFrame = lastEnd;
177
167 m_audioGenerator->removeModel(model); 178 m_audioGenerator->removeModel(model);
168 179
169 m_mutex.unlock(); 180 m_mutex.unlock();
170 } 181 }
171 182
179 if (m_converter) { 190 if (m_converter) {
180 src_delete(m_converter); 191 src_delete(m_converter);
181 m_converter = 0; 192 m_converter = 0;
182 } 193 }
183 194
195 m_lastModelEndFrame = 0;
196
184 m_audioGenerator->clearModels(); 197 m_audioGenerator->clearModels();
185 198
186 m_sourceSampleRate = 0; 199 m_sourceSampleRate = 0;
187 200
188 m_mutex.unlock(); 201 m_mutex.unlock();
189 } 202 }
190 203
191 void 204 void
192 AudioCallbackPlaySource::play(size_t startFrame) 205 AudioCallbackPlaySource::play(size_t startFrame)
193 { 206 {
207 if (m_viewManager->getPlaySelectionMode()) {
208 ViewManager::SelectionList selections = m_viewManager->getSelections();
209 ViewManager::SelectionList::iterator i = selections.begin();
210 if (i != selections.end()) {
211 if (startFrame < i->getStartFrame()) {
212 startFrame = i->getStartFrame();
213 } else {
214 ViewManager::SelectionList::iterator j = selections.end();
215 --j;
216 if (startFrame >= j->getEndFrame()) {
217 startFrame = i->getStartFrame();
218 }
219 }
220 }
221 }
222
194 // The fill thread will automatically empty its buffers before 223 // The fill thread will automatically empty its buffers before
195 // starting again if we have not so far been playing, but not if 224 // starting again if we have not so far been playing, but not if
196 // we're just re-seeking. 225 // we're just re-seeking.
197 226
198 if (m_playing) { 227 if (m_playing) {
209 238
210 m_audioGenerator->reset(); 239 m_audioGenerator->reset();
211 240
212 m_playing = true; 241 m_playing = true;
213 m_condition.wakeAll(); 242 m_condition.wakeAll();
243 emit playStatusChanged(m_playing);
214 } 244 }
215 245
216 void 246 void
217 AudioCallbackPlaySource::stop() 247 AudioCallbackPlaySource::stop()
218 { 248 {
219 m_playing = false; 249 m_playing = false;
220 m_condition.wakeAll(); 250 m_condition.wakeAll();
251 emit playStatusChanged(m_playing);
221 } 252 }
222 253
223 void 254 void
224 AudioCallbackPlaySource::selectionChanged() 255 AudioCallbackPlaySource::selectionChanged()
225 { 256 {
227 m_mutex.lock(); 258 m_mutex.lock();
228 for (size_t c = 0; c < m_bufferCount; ++c) { 259 for (size_t c = 0; c < m_bufferCount; ++c) {
229 getRingBuffer(c).reset(); 260 getRingBuffer(c).reset();
230 } 261 }
231 m_mutex.unlock(); 262 m_mutex.unlock();
263 m_condition.wakeAll();
232 } 264 }
233 } 265 }
234 266
235 void 267 void
236 AudioCallbackPlaySource::playLoopModeChanged() 268 AudioCallbackPlaySource::playLoopModeChanged()
237 { 269 {
238 m_mutex.lock();
239 for (size_t c = 0; c < m_bufferCount; ++c) {
240 getRingBuffer(c).reset();
241 }
242 m_mutex.unlock();
243 } 270 }
244 271
245 void 272 void
246 AudioCallbackPlaySource::playSelectionModeChanged() 273 AudioCallbackPlaySource::playSelectionModeChanged()
247 { 274 {
249 m_mutex.lock(); 276 m_mutex.lock();
250 for (size_t c = 0; c < m_bufferCount; ++c) { 277 for (size_t c = 0; c < m_bufferCount; ++c) {
251 getRingBuffer(c).reset(); 278 getRingBuffer(c).reset();
252 } 279 }
253 m_mutex.unlock(); 280 m_mutex.unlock();
281 m_condition.wakeAll();
254 } 282 }
255 } 283 }
256 284
257 void 285 void
258 AudioCallbackPlaySource::setTargetBlockSize(size_t size) 286 AudioCallbackPlaySource::setTargetBlockSize(size_t size)
315 latency += readSpace; 343 latency += readSpace;
316 size_t bufferedFrame = m_bufferedToFrame; 344 size_t bufferedFrame = m_bufferedToFrame;
317 345
318 size_t framePlaying = bufferedFrame; 346 size_t framePlaying = bufferedFrame;
319 if (framePlaying > latency) framePlaying -= latency; 347 if (framePlaying > latency) framePlaying -= latency;
320 else framePlaying = 0; 348 else {
349 //!!! Not right
350 if (m_viewManager->getPlayLoopMode() &&
351 !m_viewManager->getPlaySelectionMode()) {
352 framePlaying += m_lastModelEndFrame;
353 if (framePlaying > latency) framePlaying -= latency;
354 else framePlaying = 0;
355 }
356 }
321 357
322 if (!m_viewManager->getPlaySelectionMode()) { 358 if (!m_viewManager->getPlaySelectionMode()) {
323 return framePlaying; 359 return framePlaying;
324 } 360 }
325 361
328 return framePlaying; 364 return framePlaying;
329 } 365 }
330 366
331 ViewManager::SelectionList::const_iterator i; 367 ViewManager::SelectionList::const_iterator i;
332 368
369 i = selections.begin();
370 size_t rangeStart = i->getStartFrame();
371
372 i = selections.end();
373 --i;
374 size_t rangeEnd = i->getEndFrame();
375
333 for (i = selections.begin(); i != selections.end(); ++i) { 376 for (i = selections.begin(); i != selections.end(); ++i) {
334 if (i->contains(bufferedFrame)) break; 377 if (i->contains(bufferedFrame)) break;
335 } 378 }
336 379
337 size_t f = bufferedFrame; 380 size_t f = bufferedFrame;
338 381
339 std::cerr << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << std::endl; 382 // std::cerr << "getCurrentPlayingFrame: f=" << f << ", latency=" << latency << ", rangeEnd=" << rangeEnd << std::endl;
340 383
341 if (i == selections.end()) { 384 if (i == selections.end()) {
342 --i; 385 --i;
343 if (i->getEndFrame() + latency < f) { 386 if (i->getEndFrame() + latency < f) {
344 return framePlaying; 387 // std::cerr << "framePlaying = " << framePlaying << ", rangeEnd = " << rangeEnd << std::endl;
388
389 if (!m_viewManager->getPlayLoopMode() && (framePlaying > rangeEnd)) {
390 // std::cerr << "STOPPING" << std::endl;
391 stop();
392 return rangeEnd;
393 } else {
394 return framePlaying;
395 }
345 } else { 396 } else {
346 std::cerr << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl; 397 // std::cerr << "latency <- " << latency << "-(" << f << "-" << i->getEndFrame() << ")" << std::endl;
347 latency -= (f - i->getEndFrame()); 398 latency -= (f - i->getEndFrame());
348 f = i->getEndFrame(); 399 f = i->getEndFrame();
349 } 400 }
350 } 401 }
351 402
352 std::cerr << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl; 403 // std::cerr << "i=(" << i->getStartFrame() << "," << i->getEndFrame() << ") f=" << f << ", latency=" << latency << std::endl;
353 404
354 while (latency > 0) { 405 while (latency > 0) {
355 size_t offset = f - i->getStartFrame(); 406 size_t offset = f - i->getStartFrame();
356 if (offset >= latency) { 407 if (offset >= latency) {
357 if (f > latency) { 408 if (f > latency) {
613 size_t spaceHere = getRingBuffer(c).getWriteSpace(); 664 size_t spaceHere = getRingBuffer(c).getWriteSpace();
614 if (c == 0 || spaceHere < space) space = spaceHere; 665 if (c == 0 || spaceHere < space) space = spaceHere;
615 } 666 }
616 667
617 if (space == 0) return; 668 if (space == 0) return;
618 669
619 #ifdef DEBUG_AUDIO_PLAY_SOURCE 670 #ifdef DEBUG_AUDIO_PLAY_SOURCE
620 std::cout << "AudioCallbackPlaySourceFillThread: filling " << space << " frames" << std::endl; 671 std::cout << "AudioCallbackPlaySourceFillThread: filling " << space << " frames" << std::endl;
621 #endif 672 #endif
622 673
623 size_t f = m_bufferedToFrame; 674 size_t f = m_bufferedToFrame;
816 while (processed < count) { 867 while (processed < count) {
817 868
818 chunkSize = count - processed; 869 chunkSize = count - processed;
819 nextChunkStart = chunkStart + chunkSize; 870 nextChunkStart = chunkStart + chunkSize;
820 871
872 size_t fadeIn = 0, fadeOut = 0;
873
821 if (useSelection) { 874 if (useSelection) {
822 875
823 Selection selection = 876 Selection selection =
824 m_viewManager->getContainingSelection(chunkStart, true); 877 m_viewManager->getContainingSelection(chunkStart, true);
825 878
826 if (selection.isEmpty()) { 879 if (selection.isEmpty()) {
827 if (m_viewManager->getPlayLoopMode()) { 880 if (m_viewManager->getPlayLoopMode()) {
828 selection = *m_viewManager->getSelections().begin(); 881 selection = *m_viewManager->getSelections().begin();
829 chunkStart = selection.getStartFrame(); 882 chunkStart = selection.getStartFrame();
883 fadeIn = 50;
830 } 884 }
831 } 885 }
832 886
833 if (selection.isEmpty()) { 887 if (selection.isEmpty()) {
834 888
837 891
838 } else { 892 } else {
839 893
840 if (chunkStart < selection.getStartFrame()) { 894 if (chunkStart < selection.getStartFrame()) {
841 chunkStart = selection.getStartFrame(); 895 chunkStart = selection.getStartFrame();
896 fadeIn = 50;
842 } 897 }
843 898
844 nextChunkStart = std::min(chunkStart + chunkSize, 899 nextChunkStart = chunkStart + chunkSize;
845 selection.getEndFrame()); 900
901 if (nextChunkStart > selection.getEndFrame()) {
902 nextChunkStart = selection.getEndFrame();
903 fadeOut = 50;
904 }
846 905
847 chunkSize = nextChunkStart - chunkStart; 906 chunkSize = nextChunkStart - chunkStart;
848 } 907 }
908
909 } else if (m_viewManager->getPlayLoopMode() &&
910 m_lastModelEndFrame > 0) {
911
912 if (chunkStart >= m_lastModelEndFrame) {
913 chunkStart = 0;
914 }
915 if (chunkSize > m_lastModelEndFrame - chunkStart) {
916 chunkSize = m_lastModelEndFrame - chunkStart;
917 }
918 nextChunkStart = chunkStart + chunkSize;
849 } 919 }
850 920
851 if (!chunkSize) { 921 if (!chunkSize) {
852 #ifdef DEBUG_AUDIO_PLAY_SOURCE 922 #ifdef DEBUG_AUDIO_PLAY_SOURCE
853 std::cerr << "Ending selection playback at " << nextChunkStart << std::endl; 923 std::cerr << "Ending selection playback at " << nextChunkStart << std::endl;
863 std::cerr << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl; 933 std::cerr << "Selection playback: chunk at " << chunkStart << " -> " << nextChunkStart << " (size " << chunkSize << ")" << std::endl;
864 #endif 934 #endif
865 935
866 size_t got = 0; 936 size_t got = 0;
867 937
938 if (chunkSize < 100) {
939 fadeIn = 0;
940 fadeOut = 0;
941 } else if (chunkSize < 300) {
942 if (fadeIn > 0) fadeIn = 10;
943 if (fadeOut > 0) fadeOut = 10;
944 }
945
946 if (fadeIn > 0) {
947 if (processed * 2 < fadeIn) {
948 fadeIn = processed * 2;
949 }
950 }
951
952 if (fadeOut > 0) {
953 if ((count - processed) * 2 < fadeOut) {
954 fadeOut = (count - processed) * 2;
955 }
956 }
957
868 for (std::set<Model *>::iterator mi = m_models.begin(); 958 for (std::set<Model *>::iterator mi = m_models.begin();
869 mi != m_models.end(); ++mi) { 959 mi != m_models.end(); ++mi) {
870 960
871 got = m_audioGenerator->mixModel(*mi, chunkStart, 961 got = m_audioGenerator->mixModel(*mi, chunkStart,
872 chunkSize, chunkBufferPtrs); 962 chunkSize, chunkBufferPtrs,
963 fadeIn, fadeOut);
873 } 964 }
874 965
875 for (size_t c = 0; c < channels; ++c) { 966 for (size_t c = 0; c < channels; ++c) {
876 chunkBufferPtrs[c] += chunkSize; 967 chunkBufferPtrs[c] += chunkSize;
877 } 968 }
909 if (s.getSourceSampleRate() > 0) { 1000 if (s.getSourceSampleRate() > 0) {
910 ms = float(m_ringBufferSize) / float(s.getSourceSampleRate()) * 1000.0; 1001 ms = float(m_ringBufferSize) / float(s.getSourceSampleRate()) * 1000.0;
911 } 1002 }
912 1003
913 if (!s.m_playing) ms *= 10; 1004 if (!s.m_playing) ms *= 10;
914 1005 ms = ms / 8;
915 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1006
916 std::cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms/4 << "ms..." << std::endl; 1007 #ifdef DEBUG_AUDIO_PLAY_SOURCE
917 #endif 1008 std::cout << "AudioCallbackPlaySourceFillThread: waiting for " << ms << "ms..." << std::endl;
918 1009 #endif
919 s.m_condition.wait(&s.m_mutex, size_t(ms / 4)); 1010
1011 s.m_condition.wait(&s.m_mutex, size_t(ms));
920 1012
921 #ifdef DEBUG_AUDIO_PLAY_SOURCE 1013 #ifdef DEBUG_AUDIO_PLAY_SOURCE
922 std::cout << "AudioCallbackPlaySourceFillThread: awoken" << std::endl; 1014 std::cout << "AudioCallbackPlaySourceFillThread: awoken" << std::endl;
923 #endif 1015 #endif
924 1016