Mercurial > hg > svapp
comparison audio/AudioCallbackPlaySource.cpp @ 506:39e94df71d24 3.0-integration
Remake SR converter when adding a model, if necessary; remove crap converter to simplify
author | Chris Cannam |
---|---|
date | Wed, 14 Oct 2015 13:34:46 +0100 |
parents | cd9dec2f47e8 |
children | 7cf6f5501212 |
comparison
equal
deleted
inserted
replaced
505:ce6917c761a3 | 506:39e94df71d24 |
---|---|
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 |
32 using namespace RubberBand; | 33 using namespace RubberBand; |
33 | 34 |
34 #include <iostream> | 35 #include <iostream> |
35 #include <cassert> | 36 #include <cassert> |
36 | 37 |
37 //#define DEBUG_AUDIO_PLAY_SOURCE 1 | 38 #define DEBUG_AUDIO_PLAY_SOURCE 1 |
38 //#define DEBUG_AUDIO_PLAY_SOURCE_PLAYING 1 | 39 //#define DEBUG_AUDIO_PLAY_SOURCE_PLAYING 1 |
39 | 40 |
40 static const int DEFAULT_RING_BUFFER_SIZE = 131071; | 41 static const int DEFAULT_RING_BUFFER_SIZE = 131071; |
41 | 42 |
42 AudioCallbackPlaySource::AudioCallbackPlaySource(ViewManagerBase *manager, | 43 AudioCallbackPlaySource::AudioCallbackPlaySource(ViewManagerBase *manager, |
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_converter(0), |
81 m_crapConverter(0), | |
82 m_resampleQuality(Preferences::getInstance()->getResampleQuality()) | 82 m_resampleQuality(Preferences::getInstance()->getResampleQuality()) |
83 { | 83 { |
84 m_viewManager->setAudioPlaySource(this); | 84 m_viewManager->setAudioPlaySource(this); |
85 | 85 |
86 connect(m_viewManager, SIGNAL(selectionChanged()), | 86 connect(m_viewManager, SIGNAL(selectionChanged()), |
159 } | 159 } |
160 | 160 |
161 bool buffersChanged = false, srChanged = false; | 161 bool buffersChanged = false, srChanged = false; |
162 | 162 |
163 int modelChannels = 1; | 163 int modelChannels = 1; |
164 DenseTimeValueModel *dtvm = dynamic_cast<DenseTimeValueModel *>(model); | 164 ReadOnlyWaveFileModel *rowfm = qobject_cast<ReadOnlyWaveFileModel *>(model); |
165 if (dtvm) modelChannels = dtvm->getChannelCount(); | 165 if (rowfm) modelChannels = rowfm->getChannelCount(); |
166 if (modelChannels > m_sourceChannelCount) { | 166 if (modelChannels > m_sourceChannelCount) { |
167 m_sourceChannelCount = modelChannels; | 167 m_sourceChannelCount = modelChannels; |
168 } | 168 } |
169 | 169 |
170 #ifdef DEBUG_AUDIO_PLAY_SOURCE | 170 #ifdef DEBUG_AUDIO_PLAY_SOURCE |
176 m_sourceSampleRate = model->getSampleRate(); | 176 m_sourceSampleRate = model->getSampleRate(); |
177 srChanged = true; | 177 srChanged = true; |
178 | 178 |
179 } else if (model->getSampleRate() != m_sourceSampleRate) { | 179 } else if (model->getSampleRate() != m_sourceSampleRate) { |
180 | 180 |
181 // If this is a dense time-value model and we have no other, we | 181 // If this is a read-only wave file model and we have no |
182 // can just switch to this model's sample rate | 182 // other, we can just switch to this model's sample rate |
183 | 183 |
184 if (dtvm) { | 184 if (rowfm) { |
185 | 185 |
186 bool conflicting = false; | 186 bool conflicting = false; |
187 | 187 |
188 for (std::set<Model *>::const_iterator i = m_models.begin(); | 188 for (std::set<Model *>::const_iterator i = m_models.begin(); |
189 i != m_models.end(); ++i) { | 189 i != m_models.end(); ++i) { |
190 // Only wave file models can be considered conflicting -- | 190 // Only read-only wave file models should be |
191 // writable wave file models are derived and we shouldn't | 191 // considered conflicting -- writable wave file models |
192 // take their rates into account. Also, don't give any | 192 // are derived and we shouldn't take their rates into |
193 // particular weight to a file that's already playing at | 193 // account. Also, don't give any particular weight to |
194 // the wrong rate anyway | 194 // a file that's already playing at the wrong rate |
195 WaveFileModel *wfm = dynamic_cast<WaveFileModel *>(*i); | 195 // anyway |
196 if (wfm && wfm != dtvm && | 196 ReadOnlyWaveFileModel *other = |
197 wfm->getSampleRate() != model->getSampleRate() && | 197 qobject_cast<ReadOnlyWaveFileModel *>(*i); |
198 wfm->getSampleRate() == m_sourceSampleRate) { | 198 if (other && other != rowfm && |
199 other->getSampleRate() != model->getSampleRate() && | |
200 other->getSampleRate() == m_sourceSampleRate) { | |
199 SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << endl; | 201 SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << endl; |
200 conflicting = true; | 202 conflicting = true; |
201 break; | 203 break; |
202 } | 204 } |
203 } | 205 } |
228 if (willPlay) clearRingBuffers(true); | 230 if (willPlay) clearRingBuffers(true); |
229 } | 231 } |
230 | 232 |
231 if (buffersChanged || srChanged) { | 233 if (buffersChanged || srChanged) { |
232 if (m_converter) { | 234 if (m_converter) { |
235 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
236 cerr << "AudioCallbackPlaySource::addModel: Buffers or sample rate changed, deleting existing SR converter" << endl; | |
237 #endif | |
233 src_delete(m_converter); | 238 src_delete(m_converter); |
234 src_delete(m_crapConverter); | |
235 m_converter = 0; | 239 m_converter = 0; |
236 m_crapConverter = 0; | |
237 } | 240 } |
238 } | 241 } |
239 | 242 |
240 rebuildRangeLists(); | 243 rebuildRangeLists(); |
241 | 244 |
242 m_mutex.unlock(); | 245 m_mutex.unlock(); |
243 | 246 |
247 initialiseConverter(); | |
248 | |
244 m_audioGenerator->setTargetChannelCount(getTargetChannelCount()); | 249 m_audioGenerator->setTargetChannelCount(getTargetChannelCount()); |
245 | 250 |
246 if (!m_fillThread) { | 251 if (!m_fillThread) { |
247 m_fillThread = new FillThread(*this); | 252 m_fillThread = new FillThread(*this); |
248 m_fillThread->start(); | 253 m_fillThread->start(); |
296 | 301 |
297 m_models.erase(model); | 302 m_models.erase(model); |
298 | 303 |
299 if (m_models.empty()) { | 304 if (m_models.empty()) { |
300 if (m_converter) { | 305 if (m_converter) { |
306 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
307 cerr << "AudioCallbackPlaySource::removeModel: No models left, deleting SR converter" << endl; | |
308 #endif | |
301 src_delete(m_converter); | 309 src_delete(m_converter); |
302 src_delete(m_crapConverter); | |
303 m_converter = 0; | 310 m_converter = 0; |
304 m_crapConverter = 0; | |
305 } | 311 } |
306 m_sourceSampleRate = 0; | 312 m_sourceSampleRate = 0; |
307 } | 313 } |
308 | 314 |
309 sv_frame_t lastEnd = 0; | 315 sv_frame_t lastEnd = 0; |
338 #endif | 344 #endif |
339 | 345 |
340 m_models.clear(); | 346 m_models.clear(); |
341 | 347 |
342 if (m_converter) { | 348 if (m_converter) { |
349 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
350 cerr << "AudioCallbackPlaySource::clearModels: Deleting SR converter" << endl; | |
351 #endif | |
343 src_delete(m_converter); | 352 src_delete(m_converter); |
344 src_delete(m_crapConverter); | |
345 m_converter = 0; | 353 m_converter = 0; |
346 m_crapConverter = 0; | |
347 } | 354 } |
348 | 355 |
349 m_lastModelEndFrame = 0; | 356 m_lastModelEndFrame = 0; |
350 | 357 |
351 m_sourceSampleRate = 0; | 358 m_sourceSampleRate = 0; |
465 #endif | 472 #endif |
466 if (rb) rb->reset(); | 473 if (rb) rb->reset(); |
467 } | 474 } |
468 } | 475 } |
469 if (m_converter) src_reset(m_converter); | 476 if (m_converter) src_reset(m_converter); |
470 if (m_crapConverter) src_reset(m_crapConverter); | |
471 | 477 |
472 m_mutex.unlock(); | 478 m_mutex.unlock(); |
473 | 479 |
474 m_audioGenerator->reset(); | 480 m_audioGenerator->reset(); |
475 | 481 |
957 void | 963 void |
958 AudioCallbackPlaySource::initialiseConverter() | 964 AudioCallbackPlaySource::initialiseConverter() |
959 { | 965 { |
960 m_mutex.lock(); | 966 m_mutex.lock(); |
961 | 967 |
968 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
969 cerr << "AudioCallbackPlaySource::initialiseConverter(): from " | |
970 << getSourceSampleRate() << " to " << getTargetSampleRate() << endl; | |
971 #endif | |
972 | |
962 if (m_converter) { | 973 if (m_converter) { |
963 src_delete(m_converter); | 974 src_delete(m_converter); |
964 src_delete(m_crapConverter); | |
965 m_converter = 0; | 975 m_converter = 0; |
966 m_crapConverter = 0; | |
967 } | 976 } |
968 | 977 |
969 if (getSourceSampleRate() != getTargetSampleRate()) { | 978 if (getSourceSampleRate() != getTargetSampleRate()) { |
970 | 979 |
971 int err = 0; | 980 int err = 0; |
974 m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY : | 983 m_resampleQuality == 1 ? SRC_SINC_MEDIUM_QUALITY : |
975 m_resampleQuality == 0 ? SRC_SINC_FASTEST : | 984 m_resampleQuality == 0 ? SRC_SINC_FASTEST : |
976 SRC_SINC_MEDIUM_QUALITY, | 985 SRC_SINC_MEDIUM_QUALITY, |
977 getTargetChannelCount(), &err); | 986 getTargetChannelCount(), &err); |
978 | 987 |
979 if (m_converter) { | 988 if (!m_converter) { |
980 m_crapConverter = src_new(SRC_LINEAR, | 989 cerr << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " |
981 getTargetChannelCount(), | 990 << src_strerror(err) << endl; |
982 &err); | |
983 } | |
984 | |
985 if (!m_converter || !m_crapConverter) { | |
986 cerr | |
987 << "AudioCallbackPlaySource::setModel: ERROR in creating samplerate converter: " | |
988 << src_strerror(err) << endl; | |
989 | |
990 if (m_converter) { | |
991 src_delete(m_converter); | |
992 m_converter = 0; | |
993 } | |
994 | |
995 if (m_crapConverter) { | |
996 src_delete(m_crapConverter); | |
997 m_crapConverter = 0; | |
998 } | |
999 | 991 |
1000 m_mutex.unlock(); | 992 m_mutex.unlock(); |
1001 | 993 |
1002 emit sampleRateMismatch(getSourceSampleRate(), | 994 emit sampleRateMismatch(getSourceSampleRate(), |
1003 getTargetSampleRate(), | 995 getTargetSampleRate(), |
1433 } | 1425 } |
1434 | 1426 |
1435 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize(); | 1427 sv_frame_t generatorBlockSize = m_audioGenerator->getBlockSize(); |
1436 | 1428 |
1437 if (resample && !m_converter) { | 1429 if (resample && !m_converter) { |
1438 static bool warned = false; | 1430 throw std::logic_error("Sample rates differ, but no converter available!"); |
1439 if (!warned) { | |
1440 cerr << "WARNING: sample rates differ, but no converter available!" << endl; | |
1441 warned = true; | |
1442 } | |
1443 } | 1431 } |
1444 | 1432 |
1445 if (resample && m_converter) { | 1433 if (resample && m_converter) { |
1446 | 1434 |
1447 double ratio = | 1435 double ratio = |
1501 data.input_frames = long(got); | 1489 data.input_frames = long(got); |
1502 data.output_frames = long(work); | 1490 data.output_frames = long(work); |
1503 data.src_ratio = ratio; | 1491 data.src_ratio = ratio; |
1504 data.end_of_input = 0; | 1492 data.end_of_input = 0; |
1505 | 1493 |
1506 int err = 0; | 1494 int err = src_process(m_converter, &data); |
1507 | |
1508 if (m_timeStretcher && m_timeStretcher->getTimeRatio() < 0.4) { | |
1509 #ifdef DEBUG_AUDIO_PLAY_SOURCE | |
1510 cout << "Using crappy converter" << endl; | |
1511 #endif | |
1512 err = src_process(m_crapConverter, &data); | |
1513 } else { | |
1514 err = src_process(m_converter, &data); | |
1515 } | |
1516 | 1495 |
1517 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1); | 1496 sv_frame_t toCopy = sv_frame_t(double(got) * ratio + 0.1); |
1518 | 1497 |
1519 if (err) { | 1498 if (err) { |
1520 cerr | 1499 cerr |