Mercurial > hg > svapp
comparison audio/AudioCallbackPlaySource.cpp @ 548:baa11365ebdd bqaudioio
Merge from branch bqresample
author | Chris Cannam |
---|---|
date | Wed, 07 Dec 2016 11:51:42 +0000 |
parents | c4391f6c7484 |
children | c732251237b1 |
comparison
equal
deleted
inserted
replaced
547:82d7e5cf7517 | 548:baa11365ebdd |
---|---|
21 #include "base/ViewManagerBase.h" | 21 #include "base/ViewManagerBase.h" |
22 #include "base/PlayParameterRepository.h" | 22 #include "base/PlayParameterRepository.h" |
23 #include "base/Preferences.h" | 23 #include "base/Preferences.h" |
24 #include "data/model/DenseTimeValueModel.h" | 24 #include "data/model/DenseTimeValueModel.h" |
25 #include "data/model/WaveFileModel.h" | 25 #include "data/model/WaveFileModel.h" |
26 #include "data/model/ReadOnlyWaveFileModel.h" | |
26 #include "data/model/SparseOneDimensionalModel.h" | 27 #include "data/model/SparseOneDimensionalModel.h" |
27 #include "plugin/RealTimePluginInstance.h" | 28 #include "plugin/RealTimePluginInstance.h" |
28 | 29 |
29 #include "bqaudioio/SystemPlaybackTarget.h" | 30 #include "bqaudioio/SystemPlaybackTarget.h" |
30 | 31 |
75 m_stretchMono(false), | 76 m_stretchMono(false), |
76 m_stretcherInputCount(0), | 77 m_stretcherInputCount(0), |
77 m_stretcherInputs(0), | 78 m_stretcherInputs(0), |
78 m_stretcherInputSizes(0), | 79 m_stretcherInputSizes(0), |
79 m_fillThread(0), | 80 m_fillThread(0), |
80 m_converter(0), | 81 m_resampler(0) |
81 m_crapConverter(0), | |
82 m_resampleQuality(Preferences::getInstance()->getResampleQuality()) | |
83 { | 82 { |
84 m_viewManager->setAudioPlaySource(this); | 83 m_viewManager->setAudioPlaySource(this); |
85 | 84 |
86 connect(m_viewManager, SIGNAL(selectionChanged()), | 85 connect(m_viewManager, SIGNAL(selectionChanged()), |
87 this, SLOT(selectionChanged())); | 86 this, SLOT(selectionChanged())); |
159 } | 158 } |
160 | 159 |
161 bool buffersChanged = false, srChanged = false; | 160 bool buffersChanged = false, srChanged = false; |
162 | 161 |
163 int modelChannels = 1; | 162 int modelChannels = 1; |
164 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model); | 163 ReadOnlyWaveFileModel *rowfm = qobject_cast<ReadOnlyWaveFileModel *>(model); |
165 if (dtvm) modelChannels = dtvm->getChannelCount(); | 164 if (rowfm) modelChannels = rowfm->getChannelCount(); |
166 if (modelChannels > m_sourceChannelCount) { | 165 if (modelChannels > m_sourceChannelCount) { |
167 m_sourceChannelCount = modelChannels; | 166 m_sourceChannelCount = modelChannels; |
168 } | 167 } |
169 | 168 |
170 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 169 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
176 m_sourceSampleRate = model->getSampleRate(); | 175 m_sourceSampleRate = model->getSampleRate(); |
177 srChanged = true; | 176 srChanged = true; |
178 | 177 |
179 } else if (model->getSampleRate() != m_sourceSampleRate) { | 178 } else if (model->getSampleRate() != m_sourceSampleRate) { |
180 | 179 |
181 // If this is a dense time-value model and we have no other, we | 180 // If this is a read-only wave file model and we have no |
182 // can just switch to this model's sample rate | 181 // other, we can just switch to this model's sample rate |
183 | 182 |
184 if (dtvm) { | 183 if (rowfm) { |
185 | 184 |
186 bool conflicting = false; | 185 bool conflicting = false; |
187 | 186 |
188 for (std::set<Model *>::const_iterator i = m_models.begin(); | 187 for (std::set<Model *>::const_iterator i = m_models.begin(); |
189 i != m_models.end(); ++i) { | 188 i != m_models.end(); ++i) { |
190 // Only wave file models can be considered conflicting -- | 189 // Only read-only wave file models should be |
191 // writable wave file models are derived and we shouldn't | 190 // considered conflicting -- writable wave file models |
192 // take their rates into account. Also, don't give any | 191 // are derived and we shouldn't take their rates into |
193 // particular weight to a file that's already playing at | 192 // account. Also, don't give any particular weight to |
194 // the wrong rate anyway | 193 // a file that's already playing at the wrong rate |
195 WaveFileModel *wfm = dynamic_cast<WaveFileModel *>(*i); | 194 // anyway |
196 if (wfm && wfm != dtvm && | 195 ReadOnlyWaveFileModel *other = |
197 wfm->getSampleRate() != model->getSampleRate() && | 196 qobject_cast<ReadOnlyWaveFileModel *>(*i); |
198 wfm->getSampleRate() == m_sourceSampleRate) { | 197 if (other && other != rowfm && |
198 other->getSampleRate() != model->getSampleRate() && | |
199 other->getSampleRate() == m_sourceSampleRate) { | |
199 SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << endl; | 200 SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << endl; |
200 conflicting = true; | 201 conflicting = true; |
201 break; | 202 break; |
202 } | 203 } |
203 } | 204 } |
227 } else { | 228 } else { |
228 if (willPlay) clearRingBuffers(true); | 229 if (willPlay) clearRingBuffers(true); |
229 } | 230 } |
230 | 231 |
231 if (buffersChanged || srChanged) { | 232 if (buffersChanged || srChanged) { |
232 if (m_converter) { | 233 if (m_resampler) { |
233 src_delete(m_converter); | 234 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
234 src_delete(m_crapConverter); | 235 cerr << "AudioCallbackPlaySource::addModel: Buffers or sample rate changed, deleting existing resampler" << endl; |
235 m_converter = 0; | 236 #endif |
236 m_crapConverter = 0; | 237 delete m_resampler; |
238 m_resampler = 0; | |
237 } | 239 } |
238 } | 240 } |
239 | 241 |
240 rebuildRangeLists(); | 242 rebuildRangeLists(); |
241 | 243 |
242 m_mutex.unlock(); | 244 m_mutex.unlock(); |
243 | 245 |
246 initialiseResampler(); | |
247 | |
244 m_audioGenerator->setTargetChannelCount(getTargetChannelCount()); | 248 m_audioGenerator->setTargetChannelCount(getTargetChannelCount()); |
245 | 249 |
246 if (!m_fillThread) { | 250 if (!m_fillThread) { |
247 m_fillThread = new FillThread(*this); | 251 m_fillThread = new FillThread(*this); |
248 m_fillThread->start(); | 252 m_fillThread->start(); |
295 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); | 299 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); |
296 | 300 |
297 m_models.erase(model); | 301 m_models.erase(model); |
298 | 302 |
299 if (m_models.empty()) { | 303 if (m_models.empty()) { |
300 if (m_converter) { | 304 if (m_resampler) { |
301 src_delete(m_converter); | 305 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
302 src_delete(m_crapConverter); | 306 cerr << "AudioCallbackPlaySource::removeModel: No models left, deleting resampler" << endl; |
303 m_converter = 0; | 307 #endif |
304 m_crapConverter = 0; | 308 delete m_resampler; |
309 m_resampler = 0; | |
305 } | 310 } |
306 m_sourceSampleRate = 0; | 311 m_sourceSampleRate = 0; |
307 } | 312 } |
308 | 313 |
309 sv_frame_t lastEnd = 0; | 314 sv_frame_t lastEnd = 0; |
337 cout << "AudioCallbackPlaySource::clearModels()" << endl; | 342 cout << "AudioCallbackPlaySource::clearModels()" << endl; |
338 #endif | 343 #endif |
339 | 344 |
340 m_models.clear(); | 345 m_models.clear(); |
341 | 346 |
342 if (m_converter) { | 347 if (m_resampler) { |
343 src_delete(m_converter); | 348 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
344 src_delete(m_crapConverter); | 349 cerr << "AudioCallbackPlaySource::clearModels: Deleting resampler" << endl; |
345 m_converter = 0; | 350 #endif |
346 m_crapConverter = 0; | 351 delete m_resampler; |
352 m_resampler = 0; | |
347 } | 353 } |
348 | 354 |
349 m_lastModelEndFrame = 0; | 355 m_lastModelEndFrame = 0; |
350 | 356 |
351 m_sourceSampleRate = 0; | 357 m_sourceSampleRate = 0; |
405 } | 411 } |
406 | 412 |
407 void | 413 void |
408 AudioCallbackPlaySource::play(sv_frame_t startFrame) | 414 AudioCallbackPlaySource::play(sv_frame_t startFrame) |
409 { | 415 { |
416 if (!m_target) return; | |
417 | |
410 if (!m_sourceSampleRate) { | 418 if (!m_sourceSampleRate) { |
411 cerr << "AudioCallbackPlaySource::play: No source sample rate available, not playing" << endl; | 419 cerr << "AudioCallbackPlaySource::play: No source sample rate available, not playing" << endl; |
412 return; | 420 return; |
413 } | 421 } |
414 | 422 |
462 cerr << "reset ring buffer for channel " << c << endl; | 470 cerr << "reset ring buffer for channel " << c << endl; |
463 #endif | 471 #endif |
464 if (rb) rb->reset(); | 472 if (rb) rb->reset(); |
465 } | 473 } |
466 } | 474 } |
467 if (m_converter) src_reset(m_converter); | 475 if (m_resampler) { |
468 if (m_crapConverter) src_reset(m_crapConverter); | 476 m_resampler->reset(); |
477 } | |
469 | 478 |
470 m_mutex.unlock(); | 479 m_mutex.unlock(); |
471 | 480 |
472 m_audioGenerator->reset(); | 481 m_audioGenerator->reset(); |
473 | 482 |
549 } | 558 } |
550 | 559 |
551 void | 560 void |
552 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n) | 561 AudioCallbackPlaySource::preferenceChanged(PropertyContainer::PropertyName n) |
553 { | 562 { |
554 if (n == "Resample Quality") { | |
555 setResampleQuality(Preferences::getInstance()->getResampleQuality()); | |
556 } | |
557 } | 563 } |
558 | 564 |
559 void | 565 void |
560 AudioCallbackPlaySource::audioProcessingOverload() | 566 AudioCallbackPlaySource::audioProcessingOverload() |
561 { | 567 { |
939 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) | 945 AudioCallbackPlaySource::setSystemPlaybackSampleRate(int sr) |
940 { | 946 { |
941 bool first = (m_targetSampleRate == 0); | 947 bool first = (m_targetSampleRate == 0); |
942 | 948 |
943 m_targetSampleRate = sr; | 949 m_targetSampleRate = sr; |
944 initialiseConverter(); | 950 initialiseResampler(); |
945 | 951 |
946 if (first && (m_stretchRatio != 1.f)) { | 952 if (first && (m_stretchRatio != 1.f)) { |
947 // couldn't create a stretcher before because we had no sample | 953 // couldn't create a stretcher before because we had no sample |
948 // rate: make one now | 954 // rate: make one now |
949 setTimeStretch(m_stretchRatio); | 955 setTimeStretch(m_stretchRatio); |
950 } | 956 } |
951 } | 957 } |
952 | 958 |
953 void | 959 void |
954 AudioCallbackPlaySource::initialiseConverter() | 960 AudioCallbackPlaySource::initialiseResampler() |
955 { | 961 { |
956 m_mutex.lock(); | 962 m_mutex.lock(); |
957 | 963 |
958 if (m_converter) { | 964 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
959 src_delete(m_converter); | 965 cerr << "AudioCallbackPlaySource::initialiseResampler(): from " |
960 src_delete(m_crapConverter); | 966 << getSourceSampleRate() << " to " << getTargetSampleRate() << endl; |
961 m_converter = 0; | 967 #endif |
962 m_crapConverter = 0; | 968 |
969 if (m_resampler) { | |
970 delete m_resampler; | |
971 m_resampler = 0; | |
963 } | 972 } |
964 | 973 |
965 if (getSourceSampleRate() != getTargetSampleRate()) { | 974 if (getSourceSampleRate() != getTargetSampleRate()) { |
966 | 975 |
967 int err = 0; | 976 m_resampler = new breakfastquay::Resampler |
968 | 977 (breakfastquay::Resampler::FastestTolerable, |
969 m_converter = src_new(m_resampleQuality == 2 ? SRC_SINC_BEST_QUALITY : | 978 getTargetChannelCount()); |
970 m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY : | 979 |
971 m_resampleQuality == 0 ? SRC_SINC_FASTEST : | 980 m_mutex.unlock(); |
972 SRC_SINC_MEDIUM_QUALITY, | 981 |
973 getTargetChannelCount(), &err); | 982 emit sampleRateMismatch(getSourceSampleRate(), |
974 | 983 getTargetSampleRate(), |
975 if (m_converter) { | 984 true); |
976 m_crapConverter = src_new(SRC_LINEAR, | |
977 getTargetChannelCount(), | |
978 &err); | |
979 } | |
980 | |
981 if (!m_converter || !m_crapConverter) { | |
982 cerr | |
983 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " | |
984 << src_strerror(err) << endl; | |
985 | |
986 if (m_converter) { | |
987 src_delete(m_converter); | |
988 m_converter = 0; | |
989 } | |
990 | |
991 if (m_crapConverter) { | |
992 src_delete(m_crapConverter); | |
993 m_crapConverter = 0; | |
994 } | |
995 | |
996 m_mutex.unlock(); | |
997 | |
998 emit sampleRateMismatch(getSourceSampleRate(), | |
999 getTargetSampleRate(), | |
1000 false); | |
1001 } else { | |
1002 | |
1003 m_mutex.unlock(); | |
1004 | |
1005 emit sampleRateMismatch(getSourceSampleRate(), | |
1006 getTargetSampleRate(), | |
1007 true); | |
1008 } | |
1009 } else { | 985 } else { |
1010 m_mutex.unlock(); | 986 m_mutex.unlock(); |
1011 } | 987 } |
1012 } | |
1013 | |
1014 void | |
1015 AudioCallbackPlaySource::setResampleQuality(int q) | |
1016 { | |
1017 if (q == m_resampleQuality) return; | |
1018 m_resampleQuality = q; | |
1019 | |
1020 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
1021 SVDEBUG << "AudioCallbackPlaySource::setResampleQuality: setting to " | |
1022 << m_resampleQuality << endl; | |
1023 #endif | |
1024 | |
1025 initialiseConverter(); | |
1026 } | 988 } |
1027 | 989 |
1028 void | 990 void |
1029 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a) | 991 AudioCallbackPlaySource::setAuditioningEffect(Auditionable *a) |
1030 { | 992 { |
1391 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl; | 1353 cout << "AudioCallbackPlaySourceFillThread: no space to fill" << endl; |
1392 #endif | 1354 #endif |
1393 return false; | 1355 return false; |
1394 } | 1356 } |
1395 | 1357 |
1358 // space is now the number of samples that can be written on each | |
1359 // channel's write ringbuffer | |
1360 | |
1396 sv_frame_t f = m_writeBufferFill; | 1361 sv_frame_t f = m_writeBufferFill; |
1397 | 1362 |
1398 bool readWriteEqual = (m_readBuffers == m_writeBuffers); | 1363 bool readWriteEqual = (m_readBuffers == m_writeBuffers); |
1399 | 1364 |
1400 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 1365 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
1428 bufferPtrCount = channels; | 1393 bufferPtrCount = channels; |
1429 } | 1394 } |
1430 | 1395 |
1431 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize(); | 1396 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize(); |
1432 | 1397 |
1433 if (resample && !m_converter) { | 1398 if (resample && !m_resampler) { |
1434 static bool warned = false; | 1399 throw std::logic_error("Sample rates differ, but no resampler available!"); |
1435 if (!warned) { | 1400 } |
1436 cerr << "WARNING: sample rates differ, but no converter available!" << endl; | 1401 |
1437 warned = true; | 1402 if (resample && m_resampler) { |
1438 } | |
1439 } | |
1440 | |
1441 if (resample && m_converter) { | |
1442 | 1403 |
1443 double ratio = | 1404 double ratio = |
1444 double(getTargetSampleRate()) / double(getSourceSampleRate()); | 1405 double(getTargetSampleRate()) / double(getSourceSampleRate()); |
1445 orig = sv_frame_t(double(orig) / ratio + 0.1); | 1406 orig = sv_frame_t(double(orig) / ratio + 0.1); |
1446 | 1407 |
1488 for (int i = 0; i < got; ++i) { | 1449 for (int i = 0; i < got; ++i) { |
1489 float sample = nonintlv[c * got + i]; | 1450 float sample = nonintlv[c * got + i]; |
1490 intlv[channels * i + c] = sample; | 1451 intlv[channels * i + c] = sample; |
1491 } | 1452 } |
1492 } | 1453 } |
1493 | 1454 |
1455 sv_frame_t toCopy = m_resampler->resampleInterleaved | |
1456 (intlv, srcout, got, ratio, false); | |
1457 | |
1494 SRC_DATA data; | 1458 SRC_DATA data; |
1495 data.data_in = intlv; | 1459 data.data_in = intlv; |
1496 data.data_out = srcout; | 1460 data.data_out = srcout; |
1497 data.input_frames = long(got); | 1461 data.input_frames = long(got); |
1498 data.output_frames = long(work); | 1462 data.output_frames = long(work); |
1499 data.src_ratio = ratio; | 1463 data.src_ratio = ratio; |
1500 data.end_of_input = 0; | 1464 data.end_of_input = 0; |
1501 | 1465 |
1502 int err = 0; | 1466 int err = src_process(m_converter, &data); |
1503 | |
1504 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) { | |
1505 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
1506 cout << "Using crappy converter" << endl; | |
1507 #endif | |
1508 err = src_process(m_crapConverter, &data); | |
1509 } else { | |
1510 err = src_process(m_converter, &data); | |
1511 } | |
1512 | 1467 |
1513 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1); | 1468 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1); |
1514 | 1469 |
1515 if (err) { | 1470 if (err) { |
1516 cerr | 1471 cerr |