Mercurial > hg > svapp
comparison audioio/AudioCallbackPlaySource.cpp @ 450:d9d132c0e240 alignment_view
Merge from default branch
author | Chris Cannam |
---|---|
date | Mon, 20 Apr 2015 09:21:32 +0100 |
parents | c48bc6ddfe17 |
children | 3e2a2ca24d90 |
comparison
equal
deleted
inserted
replaced
430:adfb2948fabf | 450:d9d132c0e240 |
---|---|
147 void | 147 void |
148 AudioCallbackPlaySource::addModel(Model *model) | 148 AudioCallbackPlaySource::addModel(Model *model) |
149 { | 149 { |
150 if (m_models.find(model) != m_models.end()) return; | 150 if (m_models.find(model) != m_models.end()) return; |
151 | 151 |
152 bool canPlay = m_audioGenerator->addModel(model); | 152 bool willPlay = m_audioGenerator->addModel(model); |
153 | 153 |
154 m_mutex.lock(); | 154 m_mutex.lock(); |
155 | 155 |
156 m_models.insert(model); | 156 m_models.insert(model); |
157 if (model->getEndFrame() > m_lastModelEndFrame) { | 157 if (model->getEndFrame() > m_lastModelEndFrame) { |
223 | 223 |
224 if (!m_writeBuffers || (int)m_writeBuffers->size() < getTargetChannelCount()) { | 224 if (!m_writeBuffers || (int)m_writeBuffers->size() < getTargetChannelCount()) { |
225 clearRingBuffers(true, getTargetChannelCount()); | 225 clearRingBuffers(true, getTargetChannelCount()); |
226 buffersChanged = true; | 226 buffersChanged = true; |
227 } else { | 227 } else { |
228 if (canPlay) clearRingBuffers(true); | 228 if (willPlay) clearRingBuffers(true); |
229 } | 229 } |
230 | 230 |
231 if (buffersChanged || srChanged) { | 231 if (buffersChanged || srChanged) { |
232 if (m_converter) { | 232 if (m_converter) { |
233 src_delete(m_converter); | 233 src_delete(m_converter); |
254 | 254 |
255 if (buffersChanged || srChanged) { | 255 if (buffersChanged || srChanged) { |
256 emit modelReplaced(); | 256 emit modelReplaced(); |
257 } | 257 } |
258 | 258 |
259 connect(model, SIGNAL(modelChangedWithin(int, int)), | 259 connect(model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)), |
260 this, SLOT(modelChangedWithin(int, int))); | 260 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); |
261 | 261 |
262 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 262 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
263 cout << "AudioCallbackPlaySource::addModel: awakening thread" << endl; | 263 cout << "AudioCallbackPlaySource::addModel: awakening thread" << endl; |
264 #endif | 264 #endif |
265 | 265 |
266 m_condition.wakeAll(); | 266 m_condition.wakeAll(); |
267 } | 267 } |
268 | 268 |
269 void | 269 void |
270 AudioCallbackPlaySource::modelChangedWithin(int | 270 AudioCallbackPlaySource::modelChangedWithin(sv_frame_t |
271 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 271 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
272 startFrame | 272 startFrame |
273 #endif | 273 #endif |
274 , int endFrame) | 274 , sv_frame_t endFrame) |
275 { | 275 { |
276 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 276 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
277 SVDEBUG << "AudioCallbackPlaySource::modelChangedWithin(" << startFrame << "," << endFrame << ")" << endl; | 277 SVDEBUG << "AudioCallbackPlaySource::modelChangedWithin(" << startFrame << "," << endFrame << ")" << endl; |
278 #endif | 278 #endif |
279 if (endFrame > m_lastModelEndFrame) { | 279 if (endFrame > m_lastModelEndFrame) { |
289 | 289 |
290 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 290 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
291 cout << "AudioCallbackPlaySource::removeModel(" << model << ")" << endl; | 291 cout << "AudioCallbackPlaySource::removeModel(" << model << ")" << endl; |
292 #endif | 292 #endif |
293 | 293 |
294 disconnect(model, SIGNAL(modelChangedWithin(int, int)), | 294 disconnect(model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)), |
295 this, SLOT(modelChangedWithin(int, int))); | 295 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); |
296 | 296 |
297 m_models.erase(model); | 297 m_models.erase(model); |
298 | 298 |
299 if (m_models.empty()) { | 299 if (m_models.empty()) { |
300 if (m_converter) { | 300 if (m_converter) { |
304 m_crapConverter = 0; | 304 m_crapConverter = 0; |
305 } | 305 } |
306 m_sourceSampleRate = 0; | 306 m_sourceSampleRate = 0; |
307 } | 307 } |
308 | 308 |
309 int lastEnd = 0; | 309 sv_frame_t lastEnd = 0; |
310 for (std::set<Model *>::const_iterator i = m_models.begin(); | 310 for (std::set<Model *>::const_iterator i = m_models.begin(); |
311 i != m_models.end(); ++i) { | 311 i != m_models.end(); ++i) { |
312 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 312 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
313 cout << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << endl; | 313 cout << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << endl; |
314 #endif | 314 #endif |
360 void | 360 void |
361 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, int count) | 361 AudioCallbackPlaySource::clearRingBuffers(bool haveLock, int count) |
362 { | 362 { |
363 if (!haveLock) m_mutex.lock(); | 363 if (!haveLock) m_mutex.lock(); |
364 | 364 |
365 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
365 cerr << "clearRingBuffers" << endl; | 366 cerr << "clearRingBuffers" << endl; |
367 #endif | |
366 | 368 |
367 rebuildRangeLists(); | 369 rebuildRangeLists(); |
368 | 370 |
369 if (count == 0) { | 371 if (count == 0) { |
370 if (m_writeBuffers) count = m_writeBuffers->size(); | 372 if (m_writeBuffers) count = int(m_writeBuffers->size()); |
371 } | 373 } |
372 | 374 |
375 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
373 cerr << "current playing frame = " << getCurrentPlayingFrame() << endl; | 376 cerr << "current playing frame = " << getCurrentPlayingFrame() << endl; |
374 | 377 |
375 cerr << "write buffer fill (before) = " << m_writeBufferFill << endl; | 378 cerr << "write buffer fill (before) = " << m_writeBufferFill << endl; |
376 | 379 #endif |
380 | |
377 m_writeBufferFill = getCurrentBufferedFrame(); | 381 m_writeBufferFill = getCurrentBufferedFrame(); |
378 | 382 |
383 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
379 cerr << "current buffered frame = " << m_writeBufferFill << endl; | 384 cerr << "current buffered frame = " << m_writeBufferFill << endl; |
385 #endif | |
380 | 386 |
381 if (m_readBuffers != m_writeBuffers) { | 387 if (m_readBuffers != m_writeBuffers) { |
382 delete m_writeBuffers; | 388 delete m_writeBuffers; |
383 } | 389 } |
384 | 390 |
386 | 392 |
387 for (int i = 0; i < count; ++i) { | 393 for (int i = 0; i < count; ++i) { |
388 m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize)); | 394 m_writeBuffers->push_back(new RingBuffer<float>(m_ringBufferSize)); |
389 } | 395 } |
390 | 396 |
397 m_audioGenerator->reset(); | |
398 | |
391 // cout << "AudioCallbackPlaySource::clearRingBuffers: Created " | 399 // cout << "AudioCallbackPlaySource::clearRingBuffers: Created " |
392 // << count << " write buffers" << endl; | 400 // << count << " write buffers" << endl; |
393 | 401 |
394 if (!haveLock) { | 402 if (!haveLock) { |
395 m_mutex.unlock(); | 403 m_mutex.unlock(); |
396 } | 404 } |
397 } | 405 } |
398 | 406 |
399 void | 407 void |
400 AudioCallbackPlaySource::play(int startFrame) | 408 AudioCallbackPlaySource::play(sv_frame_t startFrame) |
401 { | 409 { |
402 if (!m_sourceSampleRate) { | 410 if (!m_sourceSampleRate) { |
403 cerr << "AudioCallbackPlaySource::play: No source sample rate available, not playing" << endl; | 411 cerr << "AudioCallbackPlaySource::play: No source sample rate available, not playing" << endl; |
404 return; | 412 return; |
405 } | 413 } |
591 | 599 |
592 int | 600 int |
593 AudioCallbackPlaySource::getTargetBlockSize() const | 601 AudioCallbackPlaySource::getTargetBlockSize() const |
594 { | 602 { |
595 // cout << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << endl; | 603 // cout << "AudioCallbackPlaySource::getTargetBlockSize() -> " << m_blockSize << endl; |
596 return m_blockSize; | 604 return int(m_blockSize); |
597 } | 605 } |
598 | 606 |
599 void | 607 void |
600 AudioCallbackPlaySource::setTargetPlayLatency(int latency) | 608 AudioCallbackPlaySource::setTargetPlayLatency(sv_frame_t latency) |
601 { | 609 { |
602 m_playLatency = latency; | 610 m_playLatency = latency; |
603 } | 611 } |
604 | 612 |
605 int | 613 sv_frame_t |
606 AudioCallbackPlaySource::getTargetPlayLatency() const | 614 AudioCallbackPlaySource::getTargetPlayLatency() const |
607 { | 615 { |
608 return m_playLatency; | 616 return m_playLatency; |
609 } | 617 } |
610 | 618 |
611 int | 619 sv_frame_t |
612 AudioCallbackPlaySource::getCurrentPlayingFrame() | 620 AudioCallbackPlaySource::getCurrentPlayingFrame() |
613 { | 621 { |
614 // This method attempts to estimate which audio sample frame is | 622 // This method attempts to estimate which audio sample frame is |
615 // "currently coming through the speakers". | 623 // "currently coming through the speakers". |
616 | 624 |
617 int targetRate = getTargetSampleRate(); | 625 sv_samplerate_t targetRate = getTargetSampleRate(); |
618 int latency = m_playLatency; // at target rate | 626 sv_frame_t latency = m_playLatency; // at target rate |
619 RealTime latency_t = RealTime::zeroTime; | 627 RealTime latency_t = RealTime::zeroTime; |
620 | 628 |
621 if (targetRate != 0) { | 629 if (targetRate != 0) { |
622 latency_t = RealTime::frame2RealTime(latency, targetRate); | 630 latency_t = RealTime::frame2RealTime(latency, targetRate); |
623 } | 631 } |
624 | 632 |
625 return getCurrentFrame(latency_t); | 633 return getCurrentFrame(latency_t); |
626 } | 634 } |
627 | 635 |
628 int | 636 sv_frame_t |
629 AudioCallbackPlaySource::getCurrentBufferedFrame() | 637 AudioCallbackPlaySource::getCurrentBufferedFrame() |
630 { | 638 { |
631 return getCurrentFrame(RealTime::zeroTime); | 639 return getCurrentFrame(RealTime::zeroTime); |
632 } | 640 } |
633 | 641 |
634 int | 642 sv_frame_t |
635 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) | 643 AudioCallbackPlaySource::getCurrentFrame(RealTime latency_t) |
636 { | 644 { |
637 // We resample when filling the ring buffer, and time-stretch when | 645 // We resample when filling the ring buffer, and time-stretch when |
638 // draining it. The buffer contains data at the "target rate" and | 646 // draining it. The buffer contains data at the "target rate" and |
639 // the latency provided by the target is also at the target rate. | 647 // the latency provided by the target is also at the target rate. |
640 // Because of the multiple rates involved, we do the actual | 648 // Because of the multiple rates involved, we do the actual |
641 // calculation using RealTime instead. | 649 // calculation using RealTime instead. |
642 | 650 |
643 int sourceRate = getSourceSampleRate(); | 651 sv_samplerate_t sourceRate = getSourceSampleRate(); |
644 int targetRate = getTargetSampleRate(); | 652 sv_samplerate_t targetRate = getTargetSampleRate(); |
645 | 653 |
646 if (sourceRate == 0 || targetRate == 0) return 0; | 654 if (sourceRate == 0 || targetRate == 0) return 0; |
647 | 655 |
648 int inbuffer = 0; // at target rate | 656 int inbuffer = 0; // at target rate |
649 | 657 |
653 int here = rb->getReadSpace(); | 661 int here = rb->getReadSpace(); |
654 if (c == 0 || here < inbuffer) inbuffer = here; | 662 if (c == 0 || here < inbuffer) inbuffer = here; |
655 } | 663 } |
656 } | 664 } |
657 | 665 |
658 int readBufferFill = m_readBufferFill; | 666 sv_frame_t readBufferFill = m_readBufferFill; |
659 int lastRetrievedBlockSize = m_lastRetrievedBlockSize; | 667 sv_frame_t lastRetrievedBlockSize = m_lastRetrievedBlockSize; |
660 double lastRetrievalTimestamp = m_lastRetrievalTimestamp; | 668 double lastRetrievalTimestamp = m_lastRetrievalTimestamp; |
661 double currentTime = 0.0; | 669 double currentTime = 0.0; |
662 if (m_target) currentTime = m_target->getCurrentTime(); | 670 if (m_target) currentTime = m_target->getCurrentTime(); |
663 | 671 |
664 bool looping = m_viewManager->getPlayLoopMode(); | 672 bool looping = m_viewManager->getPlayLoopMode(); |
665 | 673 |
666 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate); | 674 RealTime inbuffer_t = RealTime::frame2RealTime(inbuffer, targetRate); |
667 | 675 |
668 int stretchlat = 0; | 676 sv_frame_t stretchlat = 0; |
669 double timeRatio = 1.0; | 677 double timeRatio = 1.0; |
670 | 678 |
671 if (m_timeStretcher) { | 679 if (m_timeStretcher) { |
672 stretchlat = m_timeStretcher->getLatency(); | 680 stretchlat = m_timeStretcher->getLatency(); |
673 timeRatio = m_timeStretcher->getTimeRatio(); | 681 timeRatio = m_timeStretcher->getTimeRatio(); |
737 // this code is only used in case of error in rebuildRangeLists | 745 // this code is only used in case of error in rebuildRangeLists |
738 RealTime playing_t = bufferedto_t | 746 RealTime playing_t = bufferedto_t |
739 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t | 747 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t |
740 + sincerequest_t; | 748 + sincerequest_t; |
741 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; | 749 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; |
742 int frame = RealTime::realTime2Frame(playing_t, sourceRate); | 750 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate); |
743 return m_viewManager->alignPlaybackFrameToReference(frame); | 751 return m_viewManager->alignPlaybackFrameToReference(frame); |
744 } | 752 } |
745 | 753 |
746 int inRange = 0; | 754 int inRange = 0; |
747 int index = 0; | 755 int index = 0; |
753 break; | 761 break; |
754 } | 762 } |
755 ++index; | 763 ++index; |
756 } | 764 } |
757 | 765 |
758 if (inRange >= (int)m_rangeStarts.size()) inRange = m_rangeStarts.size()-1; | 766 if (inRange >= int(m_rangeStarts.size())) { |
767 inRange = int(m_rangeStarts.size())-1; | |
768 } | |
759 | 769 |
760 RealTime playing_t = bufferedto_t; | 770 RealTime playing_t = bufferedto_t; |
761 | 771 |
762 playing_t = playing_t | 772 playing_t = playing_t |
763 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t | 773 - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t |
804 | 814 |
805 while (playing_t < RealTime::zeroTime) { | 815 while (playing_t < RealTime::zeroTime) { |
806 | 816 |
807 if (inRange == 0) { | 817 if (inRange == 0) { |
808 if (looping) { | 818 if (looping) { |
809 inRange = m_rangeStarts.size() - 1; | 819 inRange = int(m_rangeStarts.size()) - 1; |
810 } else { | 820 } else { |
811 break; | 821 break; |
812 } | 822 } |
813 } else { | 823 } else { |
814 --inRange; | 824 --inRange; |
831 } | 841 } |
832 } | 842 } |
833 | 843 |
834 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; | 844 if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime; |
835 | 845 |
836 int frame = RealTime::realTime2Frame(playing_t, sourceRate); | 846 sv_frame_t frame = RealTime::realTime2Frame(playing_t, sourceRate); |
837 | 847 |
838 if (m_lastCurrentFrame > 0 && !looping) { | 848 if (m_lastCurrentFrame > 0 && !looping) { |
839 if (frame < m_lastCurrentFrame) { | 849 if (frame < m_lastCurrentFrame) { |
840 frame = m_lastCurrentFrame; | 850 frame = m_lastCurrentFrame; |
841 } | 851 } |
852 bool constrained = (m_viewManager->getPlaySelectionMode()); | 862 bool constrained = (m_viewManager->getPlaySelectionMode()); |
853 | 863 |
854 m_rangeStarts.clear(); | 864 m_rangeStarts.clear(); |
855 m_rangeDurations.clear(); | 865 m_rangeDurations.clear(); |
856 | 866 |
857 int sourceRate = getSourceSampleRate(); | 867 sv_samplerate_t sourceRate = getSourceSampleRate(); |
858 if (sourceRate == 0) return; | 868 if (sourceRate == 0) return; |
859 | 869 |
860 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate); | 870 RealTime end = RealTime::frame2RealTime(m_lastModelEndFrame, sourceRate); |
861 if (end == RealTime::zeroTime) return; | 871 if (end == RealTime::zeroTime) return; |
862 | 872 |
914 right = m_outputRight; | 924 right = m_outputRight; |
915 return true; | 925 return true; |
916 } | 926 } |
917 | 927 |
918 void | 928 void |
919 AudioCallbackPlaySource::setTargetSampleRate(int sr) | 929 AudioCallbackPlaySource::setTargetSampleRate(sv_samplerate_t sr) |
920 { | 930 { |
921 bool first = (m_targetSampleRate == 0); | 931 bool first = (m_targetSampleRate == 0); |
922 | 932 |
923 m_targetSampleRate = sr; | 933 m_targetSampleRate = sr; |
924 initialiseConverter(); | 934 initialiseConverter(); |
1031 { | 1041 { |
1032 m_audioGenerator->clearSoloModelSet(); | 1042 m_audioGenerator->clearSoloModelSet(); |
1033 clearRingBuffers(); | 1043 clearRingBuffers(); |
1034 } | 1044 } |
1035 | 1045 |
1036 int | 1046 sv_samplerate_t |
1037 AudioCallbackPlaySource::getTargetSampleRate() const | 1047 AudioCallbackPlaySource::getTargetSampleRate() const |
1038 { | 1048 { |
1039 if (m_targetSampleRate) return m_targetSampleRate; | 1049 if (m_targetSampleRate) return m_targetSampleRate; |
1040 else return getSourceSampleRate(); | 1050 else return getSourceSampleRate(); |
1041 } | 1051 } |
1051 { | 1061 { |
1052 if (m_sourceChannelCount < 2) return 2; | 1062 if (m_sourceChannelCount < 2) return 2; |
1053 return m_sourceChannelCount; | 1063 return m_sourceChannelCount; |
1054 } | 1064 } |
1055 | 1065 |
1056 int | 1066 sv_samplerate_t |
1057 AudioCallbackPlaySource::getSourceSampleRate() const | 1067 AudioCallbackPlaySource::getSourceSampleRate() const |
1058 { | 1068 { |
1059 return m_sourceSampleRate; | 1069 return m_sourceSampleRate; |
1060 } | 1070 } |
1061 | 1071 |
1062 void | 1072 void |
1063 AudioCallbackPlaySource::setTimeStretch(float factor) | 1073 AudioCallbackPlaySource::setTimeStretch(double factor) |
1064 { | 1074 { |
1065 m_stretchRatio = factor; | 1075 m_stretchRatio = factor; |
1066 | 1076 |
1067 if (!getTargetSampleRate()) return; // have to make our stretcher later | 1077 if (!getTargetSampleRate()) return; // have to make our stretcher later |
1068 | 1078 |
1069 if (m_timeStretcher || (factor == 1.f)) { | 1079 if (m_timeStretcher || (factor == 1.0)) { |
1070 // stretch ratio will be set in next process call if appropriate | 1080 // stretch ratio will be set in next process call if appropriate |
1071 } else { | 1081 } else { |
1072 m_stretcherInputCount = getTargetChannelCount(); | 1082 m_stretcherInputCount = getTargetChannelCount(); |
1073 RubberBandStretcher *stretcher = new RubberBandStretcher | 1083 RubberBandStretcher *stretcher = new RubberBandStretcher |
1074 (getTargetSampleRate(), | 1084 (int(getTargetSampleRate()), |
1075 m_stretcherInputCount, | 1085 m_stretcherInputCount, |
1076 RubberBandStretcher::OptionProcessRealTime, | 1086 RubberBandStretcher::OptionProcessRealTime, |
1077 factor); | 1087 factor); |
1078 RubberBandStretcher *monoStretcher = new RubberBandStretcher | 1088 RubberBandStretcher *monoStretcher = new RubberBandStretcher |
1079 (getTargetSampleRate(), | 1089 (int(getTargetSampleRate()), |
1080 1, | 1090 1, |
1081 RubberBandStretcher::OptionProcessRealTime, | 1091 RubberBandStretcher::OptionProcessRealTime, |
1082 factor); | 1092 factor); |
1083 m_stretcherInputs = new float *[m_stretcherInputCount]; | 1093 m_stretcherInputs = new float *[m_stretcherInputCount]; |
1084 m_stretcherInputSizes = new int[m_stretcherInputCount]; | 1094 m_stretcherInputSizes = new sv_frame_t[m_stretcherInputCount]; |
1085 for (int c = 0; c < m_stretcherInputCount; ++c) { | 1095 for (int c = 0; c < m_stretcherInputCount; ++c) { |
1086 m_stretcherInputSizes[c] = 16384; | 1096 m_stretcherInputSizes[c] = 16384; |
1087 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]]; | 1097 m_stretcherInputs[c] = new float[m_stretcherInputSizes[c]]; |
1088 } | 1098 } |
1089 m_monoStretcher = monoStretcher; | 1099 m_monoStretcher = monoStretcher; |
1091 } | 1101 } |
1092 | 1102 |
1093 emit activity(tr("Change time-stretch factor to %1").arg(factor)); | 1103 emit activity(tr("Change time-stretch factor to %1").arg(factor)); |
1094 } | 1104 } |
1095 | 1105 |
1096 int | 1106 sv_frame_t |
1097 AudioCallbackPlaySource::getSourceSamples(int ucount, float **buffer) | 1107 AudioCallbackPlaySource::getSourceSamples(sv_frame_t count, float **buffer) |
1098 { | 1108 { |
1099 int count = ucount; | |
1100 | |
1101 if (!m_playing) { | 1109 if (!m_playing) { |
1102 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1110 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1103 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Not playing" << endl; | 1111 SVDEBUG << "AudioCallbackPlaySource::getSourceSamples: Not playing" << endl; |
1104 #endif | 1112 #endif |
1105 for (int ch = 0; ch < getTargetChannelCount(); ++ch) { | 1113 for (int ch = 0; ch < getTargetChannelCount(); ++ch) { |
1146 if (count == 0) return 0; | 1154 if (count == 0) return 0; |
1147 | 1155 |
1148 RubberBandStretcher *ts = m_timeStretcher; | 1156 RubberBandStretcher *ts = m_timeStretcher; |
1149 RubberBandStretcher *ms = m_monoStretcher; | 1157 RubberBandStretcher *ms = m_monoStretcher; |
1150 | 1158 |
1151 float ratio = ts ? ts->getTimeRatio() : 1.f; | 1159 double ratio = ts ? ts->getTimeRatio() : 1.0; |
1152 | 1160 |
1153 if (ratio != m_stretchRatio) { | 1161 if (ratio != m_stretchRatio) { |
1154 if (!ts) { | 1162 if (!ts) { |
1155 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << endl; | 1163 cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: Time ratio change to " << m_stretchRatio << " is pending, but no stretcher is set" << endl; |
1156 m_stretchRatio = 1.f; | 1164 m_stretchRatio = 1.0; |
1157 } else { | 1165 } else { |
1158 ts->setTimeRatio(m_stretchRatio); | 1166 ts->setTimeRatio(m_stretchRatio); |
1159 if (ms) ms->setTimeRatio(m_stretchRatio); | 1167 if (ms) ms->setTimeRatio(m_stretchRatio); |
1160 if (m_stretchRatio >= 1.0) m_stretchMono = false; | 1168 if (m_stretchRatio >= 1.0) m_stretchMono = false; |
1161 } | 1169 } |
1186 | 1194 |
1187 if (rb) { | 1195 if (rb) { |
1188 | 1196 |
1189 // this is marginally more likely to leave our channels in | 1197 // this is marginally more likely to leave our channels in |
1190 // sync after a processing failure than just passing "count": | 1198 // sync after a processing failure than just passing "count": |
1191 int request = count; | 1199 sv_frame_t request = count; |
1192 if (ch > 0) request = got; | 1200 if (ch > 0) request = got; |
1193 | 1201 |
1194 got = rb->read(buffer[ch], request); | 1202 got = rb->read(buffer[ch], int(request)); |
1195 | 1203 |
1196 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1204 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1197 cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << endl; | 1205 cout << "AudioCallbackPlaySource::getSamples: got " << got << " (of " << count << ") samples on channel " << ch << ", signalling for more (possibly)" << endl; |
1198 #endif | 1206 #endif |
1199 } | 1207 } |
1215 | 1223 |
1216 return got; | 1224 return got; |
1217 } | 1225 } |
1218 | 1226 |
1219 int channels = getTargetChannelCount(); | 1227 int channels = getTargetChannelCount(); |
1220 int available; | 1228 sv_frame_t available; |
1229 sv_frame_t fedToStretcher = 0; | |
1221 int warned = 0; | 1230 int warned = 0; |
1222 int fedToStretcher = 0; | |
1223 | 1231 |
1224 // The input block for a given output is approx output / ratio, | 1232 // The input block for a given output is approx output / ratio, |
1225 // but we can't predict it exactly, for an adaptive timestretcher. | 1233 // but we can't predict it exactly, for an adaptive timestretcher. |
1226 | 1234 |
1227 while ((available = ts->available()) < count) { | 1235 while ((available = ts->available()) < count) { |
1228 | 1236 |
1229 int reqd = lrintf((count - available) / ratio); | 1237 sv_frame_t reqd = lrint(double(count - available) / ratio); |
1230 reqd = std::max(reqd, (int)ts->getSamplesRequired()); | 1238 reqd = std::max(reqd, sv_frame_t(ts->getSamplesRequired())); |
1231 if (reqd == 0) reqd = 1; | 1239 if (reqd == 0) reqd = 1; |
1232 | 1240 |
1233 int got = reqd; | 1241 sv_frame_t got = reqd; |
1234 | 1242 |
1235 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1243 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1236 cerr << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << endl; | 1244 cerr << "reqd = " <<reqd << ", channels = " << channels << ", ic = " << m_stretcherInputCount << endl; |
1237 #endif | 1245 #endif |
1238 | 1246 |
1250 | 1258 |
1251 for (int c = 0; c < channels; ++c) { | 1259 for (int c = 0; c < channels; ++c) { |
1252 if (c >= m_stretcherInputCount) continue; | 1260 if (c >= m_stretcherInputCount) continue; |
1253 RingBuffer<float> *rb = getReadRingBuffer(c); | 1261 RingBuffer<float> *rb = getReadRingBuffer(c); |
1254 if (rb) { | 1262 if (rb) { |
1255 int gotHere; | 1263 sv_frame_t gotHere; |
1256 if (stretchChannels == 1 && c > 0) { | 1264 if (stretchChannels == 1 && c > 0) { |
1257 gotHere = rb->readAdding(m_stretcherInputs[0], got); | 1265 gotHere = rb->readAdding(m_stretcherInputs[0], int(got)); |
1258 } else { | 1266 } else { |
1259 gotHere = rb->read(m_stretcherInputs[c], got); | 1267 gotHere = rb->read(m_stretcherInputs[c], int(got)); |
1260 } | 1268 } |
1261 if (gotHere < got) got = gotHere; | 1269 if (gotHere < got) got = gotHere; |
1262 | 1270 |
1263 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1271 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1264 if (c == 0) { | 1272 if (c == 0) { |
1307 | 1315 |
1308 return count; | 1316 return count; |
1309 } | 1317 } |
1310 | 1318 |
1311 void | 1319 void |
1312 AudioCallbackPlaySource::applyAuditioningEffect(int count, float **buffers) | 1320 AudioCallbackPlaySource::applyAuditioningEffect(sv_frame_t count, float **buffers) |
1313 { | 1321 { |
1314 if (m_auditioningPluginBypassed) return; | 1322 if (m_auditioningPluginBypassed) return; |
1315 RealTimePluginInstance *plugin = m_auditioningPlugin; | 1323 RealTimePluginInstance *plugin = m_auditioningPlugin; |
1316 if (!plugin) return; | 1324 if (!plugin) return; |
1317 | 1325 |
1341 for (int i = 0; i < count; ++i) { | 1349 for (int i = 0; i < count; ++i) { |
1342 ib[c][i] = buffers[c][i]; | 1350 ib[c][i] = buffers[c][i]; |
1343 } | 1351 } |
1344 } | 1352 } |
1345 | 1353 |
1346 plugin->run(Vamp::RealTime::zeroTime, count); | 1354 plugin->run(Vamp::RealTime::zeroTime, int(count)); |
1347 | 1355 |
1348 for (int c = 0; c < getTargetChannelCount(); ++c) { | 1356 for (int c = 0; c < getTargetChannelCount(); ++c) { |
1349 for (int i = 0; i < count; ++i) { | 1357 for (int i = 0; i < count; ++i) { |
1350 buffers[c][i] = ob[c][i]; | 1358 buffers[c][i] = ob[c][i]; |
1351 } | 1359 } |
1355 // Called from fill thread, m_playing true, mutex held | 1363 // Called from fill thread, m_playing true, mutex held |
1356 bool | 1364 bool |
1357 AudioCallbackPlaySource::fillBuffers() | 1365 AudioCallbackPlaySource::fillBuffers() |
1358 { | 1366 { |
1359 static float *tmp = 0; | 1367 static float *tmp = 0; |
1360 static int tmpSize = 0; | 1368 static sv_frame_t tmpSize = 0; |
1361 | 1369 |
1362 int space = 0; | 1370 sv_frame_t space = 0; |
1363 for (int c = 0; c < getTargetChannelCount(); ++c) { | 1371 for (int c = 0; c < getTargetChannelCount(); ++c) { |
1364 RingBuffer<float> *wb = getWriteRingBuffer(c); | 1372 RingBuffer<float> *wb = getWriteRingBuffer(c); |
1365 if (wb) { | 1373 if (wb) { |
1366 int spaceHere = wb->getWriteSpace(); | 1374 sv_frame_t spaceHere = wb->getWriteSpace(); |
1367 if (c == 0 || spaceHere < space) space = spaceHere; | 1375 if (c == 0 || spaceHere < space) space = spaceHere; |
1368 } | 1376 } |
1369 } | 1377 } |
1370 | 1378 |
1371 if (space == 0) { | 1379 if (space == 0) { |
1373 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl; | 1381 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl; |
1374 #endif | 1382 #endif |
1375 return false; | 1383 return false; |
1376 } | 1384 } |
1377 | 1385 |
1378 int f = m_writeBufferFill; | 1386 sv_frame_t f = m_writeBufferFill; |
1379 | 1387 |
1380 bool readWriteEqual = (m_readBuffers == m_writeBuffers); | 1388 bool readWriteEqual = (m_readBuffers == m_writeBuffers); |
1381 | 1389 |
1382 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1390 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1383 if (!readWriteEqual) { | 1391 if (!readWriteEqual) { |
1396 cout << (resample ? "" : "not ") << "resampling (source " << getSourceSampleRate() << ", target " << getTargetSampleRate() << ")" << endl; | 1404 cout << (resample ? "" : "not ") << "resampling (source " << getSourceSampleRate() << ", target " << getTargetSampleRate() << ")" << endl; |
1397 #endif | 1405 #endif |
1398 | 1406 |
1399 int channels = getTargetChannelCount(); | 1407 int channels = getTargetChannelCount(); |
1400 | 1408 |
1401 int orig = space; | 1409 sv_frame_t orig = space; |
1402 int got = 0; | 1410 sv_frame_t got = 0; |
1403 | 1411 |
1404 static float **bufferPtrs = 0; | 1412 static float **bufferPtrs = 0; |
1405 static int bufferPtrCount = 0; | 1413 static int bufferPtrCount = 0; |
1406 | 1414 |
1407 if (bufferPtrCount < channels) { | 1415 if (bufferPtrCount < channels) { |
1408 if (bufferPtrs) delete[] bufferPtrs; | 1416 if (bufferPtrs) delete[] bufferPtrs; |
1409 bufferPtrs = new float *[channels]; | 1417 bufferPtrs = new float *[channels]; |
1410 bufferPtrCount = channels; | 1418 bufferPtrCount = channels; |
1411 } | 1419 } |
1412 | 1420 |
1413 int generatorBlockSize = m_audioGenerator->getBlockSize(); | 1421 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize(); |
1414 | 1422 |
1415 if (resample && !m_converter) { | 1423 if (resample && !m_converter) { |
1416 static bool warned = false; | 1424 static bool warned = false; |
1417 if (!warned) { | 1425 if (!warned) { |
1418 cerr << "WARNING: sample rates differ, but no converter available!" << endl; | 1426 cerr << "WARNING: sample rates differ, but no converter available!" << endl; |
1422 | 1430 |
1423 if (resample && m_converter) { | 1431 if (resample && m_converter) { |
1424 | 1432 |
1425 double ratio = | 1433 double ratio = |
1426 double(getTargetSampleRate()) / double(getSourceSampleRate()); | 1434 double(getTargetSampleRate()) / double(getSourceSampleRate()); |
1427 orig = int(orig / ratio + 0.1); | 1435 orig = sv_frame_t(double(orig) / ratio + 0.1); |
1428 | 1436 |
1429 // orig must be a multiple of generatorBlockSize | 1437 // orig must be a multiple of generatorBlockSize |
1430 orig = (orig / generatorBlockSize) * generatorBlockSize; | 1438 orig = (orig / generatorBlockSize) * generatorBlockSize; |
1431 if (orig == 0) return false; | 1439 if (orig == 0) return false; |
1432 | 1440 |
1433 int work = std::max(orig, space); | 1441 sv_frame_t work = std::max(orig, space); |
1434 | 1442 |
1435 // We only allocate one buffer, but we use it in two halves. | 1443 // We only allocate one buffer, but we use it in two halves. |
1436 // We place the non-interleaved values in the second half of | 1444 // We place the non-interleaved values in the second half of |
1437 // the buffer (orig samples for channel 0, orig samples for | 1445 // the buffer (orig samples for channel 0, orig samples for |
1438 // channel 1 etc), and then interleave them into the first | 1446 // channel 1 etc), and then interleave them into the first |
1490 err = src_process(m_crapConverter, &data); | 1498 err = src_process(m_crapConverter, &data); |
1491 } else { | 1499 } else { |
1492 err = src_process(m_converter, &data); | 1500 err = src_process(m_converter, &data); |
1493 } | 1501 } |
1494 | 1502 |
1495 int toCopy = int(got * ratio + 0.1); | 1503 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1); |
1496 | 1504 |
1497 if (err) { | 1505 if (err) { |
1498 cerr | 1506 cerr |
1499 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: " | 1507 << "AudioCallbackPlaySourceFillThread: ERROR in samplerate conversion: " |
1500 << src_strerror(err) << endl; | 1508 << src_strerror(err) << endl; |
1510 for (int c = 0; c < channels; ++c) { | 1518 for (int c = 0; c < channels; ++c) { |
1511 for (int i = 0; i < toCopy; ++i) { | 1519 for (int i = 0; i < toCopy; ++i) { |
1512 tmp[i] = srcout[channels * i + c]; | 1520 tmp[i] = srcout[channels * i + c]; |
1513 } | 1521 } |
1514 RingBuffer<float> *wb = getWriteRingBuffer(c); | 1522 RingBuffer<float> *wb = getWriteRingBuffer(c); |
1515 if (wb) wb->write(tmp, toCopy); | 1523 if (wb) wb->write(tmp, int(toCopy)); |
1516 } | 1524 } |
1517 | 1525 |
1518 m_writeBufferFill = f; | 1526 m_writeBufferFill = f; |
1519 if (readWriteEqual) m_readBufferFill = f; | 1527 if (readWriteEqual) m_readBufferFill = f; |
1520 | 1528 |
1521 } else { | 1529 } else { |
1522 | 1530 |
1523 // space must be a multiple of generatorBlockSize | 1531 // space must be a multiple of generatorBlockSize |
1524 int reqSpace = space; | 1532 sv_frame_t reqSpace = space; |
1525 space = (reqSpace / generatorBlockSize) * generatorBlockSize; | 1533 space = (reqSpace / generatorBlockSize) * generatorBlockSize; |
1526 if (space == 0) { | 1534 if (space == 0) { |
1527 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1535 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1528 cout << "requested fill of " << reqSpace | 1536 cout << "requested fill of " << reqSpace |
1529 << " is less than generator block size of " | 1537 << " is less than generator block size of " |
1545 for (int i = 0; i < space; ++i) { | 1553 for (int i = 0; i < space; ++i) { |
1546 tmp[c * space + i] = 0.0f; | 1554 tmp[c * space + i] = 0.0f; |
1547 } | 1555 } |
1548 } | 1556 } |
1549 | 1557 |
1550 int got = mixModels(f, space, bufferPtrs); // also modifies f | 1558 sv_frame_t got = mixModels(f, space, bufferPtrs); // also modifies f |
1551 | 1559 |
1552 for (int c = 0; c < channels; ++c) { | 1560 for (int c = 0; c < channels; ++c) { |
1553 | 1561 |
1554 RingBuffer<float> *wb = getWriteRingBuffer(c); | 1562 RingBuffer<float> *wb = getWriteRingBuffer(c); |
1555 if (wb) { | 1563 if (wb) { |
1556 int actual = wb->write(bufferPtrs[c], got); | 1564 int actual = wb->write(bufferPtrs[c], int(got)); |
1557 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1565 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1558 cout << "Wrote " << actual << " samples for ch " << c << ", now " | 1566 cout << "Wrote " << actual << " samples for ch " << c << ", now " |
1559 << wb->getReadSpace() << " to read" | 1567 << wb->getReadSpace() << " to read" |
1560 << endl; | 1568 << endl; |
1561 #endif | 1569 #endif |
1578 } | 1586 } |
1579 | 1587 |
1580 return true; | 1588 return true; |
1581 } | 1589 } |
1582 | 1590 |
1583 int | 1591 sv_frame_t |
1584 AudioCallbackPlaySource::mixModels(int &frame, int count, float **buffers) | 1592 AudioCallbackPlaySource::mixModels(sv_frame_t &frame, sv_frame_t count, float **buffers) |
1585 { | 1593 { |
1586 int processed = 0; | 1594 sv_frame_t processed = 0; |
1587 int chunkStart = frame; | 1595 sv_frame_t chunkStart = frame; |
1588 int chunkSize = count; | 1596 sv_frame_t chunkSize = count; |
1589 int selectionSize = 0; | 1597 sv_frame_t selectionSize = 0; |
1590 int nextChunkStart = chunkStart + chunkSize; | 1598 sv_frame_t nextChunkStart = chunkStart + chunkSize; |
1591 | 1599 |
1592 bool looping = m_viewManager->getPlayLoopMode(); | 1600 bool looping = m_viewManager->getPlayLoopMode(); |
1593 bool constrained = (m_viewManager->getPlaySelectionMode() && | 1601 bool constrained = (m_viewManager->getPlaySelectionMode() && |
1594 !m_viewManager->getSelections().empty()); | 1602 !m_viewManager->getSelections().empty()); |
1595 | 1603 |
1615 | 1623 |
1616 chunkSize = count - processed; | 1624 chunkSize = count - processed; |
1617 nextChunkStart = chunkStart + chunkSize; | 1625 nextChunkStart = chunkStart + chunkSize; |
1618 selectionSize = 0; | 1626 selectionSize = 0; |
1619 | 1627 |
1620 int fadeIn = 0, fadeOut = 0; | 1628 sv_frame_t fadeIn = 0, fadeOut = 0; |
1621 | 1629 |
1622 if (constrained) { | 1630 if (constrained) { |
1623 | 1631 |
1624 int rChunkStart = | 1632 sv_frame_t rChunkStart = |
1625 m_viewManager->alignPlaybackFrameToReference(chunkStart); | 1633 m_viewManager->alignPlaybackFrameToReference(chunkStart); |
1626 | 1634 |
1627 Selection selection = | 1635 Selection selection = |
1628 m_viewManager->getContainingSelection(rChunkStart, true); | 1636 m_viewManager->getContainingSelection(rChunkStart, true); |
1629 | 1637 |
1641 chunkSize = 0; | 1649 chunkSize = 0; |
1642 nextChunkStart = chunkStart; | 1650 nextChunkStart = chunkStart; |
1643 | 1651 |
1644 } else { | 1652 } else { |
1645 | 1653 |
1646 int sf = m_viewManager->alignReferenceToPlaybackFrame | 1654 sv_frame_t sf = m_viewManager->alignReferenceToPlaybackFrame |
1647 (selection.getStartFrame()); | 1655 (selection.getStartFrame()); |
1648 int ef = m_viewManager->alignReferenceToPlaybackFrame | 1656 sv_frame_t ef = m_viewManager->alignReferenceToPlaybackFrame |
1649 (selection.getEndFrame()); | 1657 (selection.getEndFrame()); |
1650 | 1658 |
1651 selectionSize = ef - sf; | 1659 selectionSize = ef - sf; |
1652 | 1660 |
1653 if (chunkStart < sf) { | 1661 if (chunkStart < sf) { |
1759 } | 1767 } |
1760 break; | 1768 break; |
1761 } | 1769 } |
1762 } | 1770 } |
1763 | 1771 |
1764 int rf = m_readBufferFill; | 1772 sv_frame_t rf = m_readBufferFill; |
1765 RingBuffer<float> *rb = getReadRingBuffer(0); | 1773 RingBuffer<float> *rb = getReadRingBuffer(0); |
1766 if (rb) { | 1774 if (rb) { |
1767 int rs = rb->getReadSpace(); | 1775 int rs = rb->getReadSpace(); |
1768 //!!! incorrect when in non-contiguous selection, see comments elsewhere | 1776 //!!! incorrect when in non-contiguous selection, see comments elsewhere |
1769 // cout << "rs = " << rs << endl; | 1777 // cout << "rs = " << rs << endl; |
1773 | 1781 |
1774 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING | 1782 #ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING |
1775 SVDEBUG << "AudioCallbackPlaySource::unifyRingBuffers: m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << endl; | 1783 SVDEBUG << "AudioCallbackPlaySource::unifyRingBuffers: m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << endl; |
1776 #endif | 1784 #endif |
1777 | 1785 |
1778 int wf = m_writeBufferFill; | 1786 sv_frame_t wf = m_writeBufferFill; |
1779 int skip = 0; | 1787 sv_frame_t skip = 0; |
1780 for (int c = 0; c < getTargetChannelCount(); ++c) { | 1788 for (int c = 0; c < getTargetChannelCount(); ++c) { |
1781 RingBuffer<float> *wb = getWriteRingBuffer(c); | 1789 RingBuffer<float> *wb = getWriteRingBuffer(c); |
1782 if (wb) { | 1790 if (wb) { |
1783 if (c == 0) { | 1791 if (c == 0) { |
1784 | 1792 |
1792 if (wf < rf) skip = rf - wf; | 1800 if (wf < rf) skip = rf - wf; |
1793 if (skip == 0) break; | 1801 if (skip == 0) break; |
1794 } | 1802 } |
1795 | 1803 |
1796 // cout << "skipping " << skip << endl; | 1804 // cout << "skipping " << skip << endl; |
1797 wb->skip(skip); | 1805 wb->skip(int(skip)); |
1798 } | 1806 } |
1799 } | 1807 } |
1800 | 1808 |
1801 m_bufferScavenger.claim(m_readBuffers); | 1809 m_bufferScavenger.claim(m_readBuffers); |
1802 m_readBuffers = m_writeBuffers; | 1810 m_readBuffers = m_writeBuffers; |
1835 s.m_mutex.unlock(); | 1843 s.m_mutex.unlock(); |
1836 s.m_mutex.lock(); | 1844 s.m_mutex.lock(); |
1837 | 1845 |
1838 } else { | 1846 } else { |
1839 | 1847 |
1840 float ms = 100; | 1848 double ms = 100; |
1841 if (s.getSourceSampleRate() > 0) { | 1849 if (s.getSourceSampleRate() > 0) { |
1842 ms = float(s.m_ringBufferSize) / | 1850 ms = double(s.m_ringBufferSize) / s.getSourceSampleRate() * 1000.0; |
1843 float(s.getSourceSampleRate()) * 1000.0; | |
1844 } | 1851 } |
1845 | 1852 |
1846 if (s.m_playing) ms /= 10; | 1853 if (s.m_playing) ms /= 10; |
1847 | 1854 |
1848 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1855 #ifdef DEBUG_AUDIO_PLAY_SOURCE |