comparison audio/AudioCallbackPlaySource.cpp @ 682:161063152ddd by-id

Overhaul audio generator for ModelById
author Chris Cannam
date Tue, 02 Jul 2019 21:10:25 +0100
parents a82b9d410393
children e0b0f3e163ca
comparison
equal deleted inserted replaced
681:c7406ebcd51c 682:161063152ddd
149 SVDEBUG << "AudioCallbackPlaySource::~AudioCallbackPlaySource finishing" << endl; 149 SVDEBUG << "AudioCallbackPlaySource::~AudioCallbackPlaySource finishing" << endl;
150 #endif 150 #endif
151 } 151 }
152 152
153 void 153 void
154 AudioCallbackPlaySource::addModel(Model *model) 154 AudioCallbackPlaySource::addModel(ModelId modelId)
155 { 155 {
156 if (m_models.find(model) != m_models.end()) return; 156 if (m_models.find(modelId) != m_models.end()) return;
157 157
158 bool willPlay = m_audioGenerator->addModel(model); 158 bool willPlay = m_audioGenerator->addModel(modelId);
159
160 auto model = ModelById::get(modelId);
161 if (!model) return;
159 162
160 m_mutex.lock(); 163 m_mutex.lock();
161 164
162 m_models.insert(model); 165 m_models.insert(modelId);
166
163 if (model->getEndFrame() > m_lastModelEndFrame) { 167 if (model->getEndFrame() > m_lastModelEndFrame) {
164 m_lastModelEndFrame = model->getEndFrame(); 168 m_lastModelEndFrame = model->getEndFrame();
165 } 169 }
166 170
167 bool buffersIncreased = false, srChanged = false; 171 bool buffersIncreased = false, srChanged = false;
168 172
169 int modelChannels = 1; 173 int modelChannels = 1;
170 ReadOnlyWaveFileModel *rowfm = qobject_cast<ReadOnlyWaveFileModel *>(model); 174 auto rowfm = std::dynamic_pointer_cast<ReadOnlyWaveFileModel>(model);
171 if (rowfm) modelChannels = rowfm->getChannelCount(); 175 if (rowfm) modelChannels = rowfm->getChannelCount();
172 if (modelChannels > m_sourceChannelCount) { 176 if (modelChannels > m_sourceChannelCount) {
173 m_sourceChannelCount = modelChannels; 177 m_sourceChannelCount = modelChannels;
174 } 178 }
175 179
192 196
193 if (rowfm) { 197 if (rowfm) {
194 198
195 bool conflicting = false; 199 bool conflicting = false;
196 200
197 for (std::set<Model *>::const_iterator i = m_models.begin(); 201 for (ModelId otherId: m_models) {
198 i != m_models.end(); ++i) {
199 // Only read-only wave file models should be 202 // Only read-only wave file models should be
200 // considered conflicting -- writable wave file models 203 // considered conflicting -- writable wave file models
201 // are derived and we shouldn't take their rates into 204 // are derived and we shouldn't take their rates into
202 // account. Also, don't give any particular weight to 205 // account. Also, don't give any particular weight to
203 // a file that's already playing at the wrong rate 206 // a file that's already playing at the wrong rate
204 // anyway 207 // anyway
205 ReadOnlyWaveFileModel *other = 208 if (otherId == modelId) continue;
206 qobject_cast<ReadOnlyWaveFileModel *>(*i); 209 auto other = ModelById::getAs<ReadOnlyWaveFileModel>(otherId);
207 if (other && other != rowfm && 210 if (other &&
208 other->getSampleRate() != model->getSampleRate() && 211 other->getSampleRate() != model->getSampleRate() &&
209 other->getSampleRate() == m_sourceSampleRate) { 212 other->getSampleRate() == m_sourceSampleRate) {
210 SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << *i << " found" << endl; 213 SVDEBUG << "AudioCallbackPlaySource::addModel: Conflicting wave file model " << otherId << " found" << endl;
211 conflicting = true; 214 conflicting = true;
212 break; 215 break;
213 } 216 }
214 } 217 }
215 218
289 292
290 #ifdef DEBUG_AUDIO_PLAY_SOURCE 293 #ifdef DEBUG_AUDIO_PLAY_SOURCE
291 SVDEBUG << "AudioCallbackPlaySource::addModel: now have " << m_models.size() << " model(s)" << endl; 294 SVDEBUG << "AudioCallbackPlaySource::addModel: now have " << m_models.size() << " model(s)" << endl;
292 #endif 295 #endif
293 296
294 connect(model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)), 297 connect(model.get(), SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
295 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); 298 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
296 299
297 #ifdef DEBUG_AUDIO_PLAY_SOURCE 300 #ifdef DEBUG_AUDIO_PLAY_SOURCE
298 cout << "AudioCallbackPlaySource::addModel: awakening thread" << endl; 301 cout << "AudioCallbackPlaySource::addModel: awakening thread" << endl;
299 #endif 302 #endif
316 rebuildRangeLists(); 319 rebuildRangeLists();
317 } 320 }
318 } 321 }
319 322
320 void 323 void
321 AudioCallbackPlaySource::removeModel(Model *model) 324 AudioCallbackPlaySource::removeModel(ModelId modelId)
322 { 325 {
326 auto model = ModelById::get(modelId);
327 if (!model) return;
328
323 m_mutex.lock(); 329 m_mutex.lock();
324 330
325 #ifdef DEBUG_AUDIO_PLAY_SOURCE 331 #ifdef DEBUG_AUDIO_PLAY_SOURCE
326 cout << "AudioCallbackPlaySource::removeModel(" << model << ")" << endl; 332 cout << "AudioCallbackPlaySource::removeModel(" << modelId << ")" << endl;
327 #endif 333 #endif
328 334
329 disconnect(model, SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)), 335 disconnect(model.get(), SIGNAL(modelChangedWithin(sv_frame_t, sv_frame_t)),
330 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t))); 336 this, SLOT(modelChangedWithin(sv_frame_t, sv_frame_t)));
331 337
332 m_models.erase(model); 338 m_models.erase(modelId);
333
334 // I don't think we have to do this any more: if a new model is
335 // loaded at a different rate, we'll hit the non-conflicting path
336 // in addModel and the rate will be updated without problems; but
337 // if a new model is loaded at the rate that we were using for the
338 // last one, then we save work by not having reset this here
339 //
340 // if (m_models.empty()) {
341 // m_sourceSampleRate = 0;
342 // }
343 339
344 sv_frame_t lastEnd = 0; 340 sv_frame_t lastEnd = 0;
345 for (std::set<Model *>::const_iterator i = m_models.begin(); 341 for (ModelId otherId: m_models) {
346 i != m_models.end(); ++i) { 342 #ifdef DEBUG_AUDIO_PLAY_SOURCE
347 #ifdef DEBUG_AUDIO_PLAY_SOURCE 343 cout << "AudioCallbackPlaySource::removeModel(" << modelId << "): checking end frame on model " << otherId << endl;
348 cout << "AudioCallbackPlaySource::removeModel(" << model << "): checking end frame on model " << *i << endl; 344 #endif
349 #endif 345 if (auto other = ModelById::get(otherId)) {
350 if ((*i)->getEndFrame() > lastEnd) { 346 if (other->getEndFrame() > lastEnd) {
351 lastEnd = (*i)->getEndFrame(); 347 lastEnd = other->getEndFrame();
348 }
352 } 349 }
353 #ifdef DEBUG_AUDIO_PLAY_SOURCE 350 #ifdef DEBUG_AUDIO_PLAY_SOURCE
354 cout << "(done, lastEnd now " << lastEnd << ")" << endl; 351 cout << "(done, lastEnd now " << lastEnd << ")" << endl;
355 #endif 352 #endif
356 } 353 }
357 m_lastModelEndFrame = lastEnd; 354 m_lastModelEndFrame = lastEnd;
358 355
359 m_audioGenerator->removeModel(model); 356 m_audioGenerator->removeModel(modelId);
360 357
361 if (m_models.empty()) { 358 if (m_models.empty()) {
362 m_sourceSampleRate = 0; 359 m_sourceSampleRate = 0;
363 } 360 }
364 361
1012 m_auditioningPluginBypassed = false; 1009 m_auditioningPluginBypassed = false;
1013 m_mutex.unlock(); 1010 m_mutex.unlock();
1014 } 1011 }
1015 1012
1016 void 1013 void
1017 AudioCallbackPlaySource::setSoloModelSet(std::set<Model *> s) 1014 AudioCallbackPlaySource::setSoloModelSet(std::set<ModelId> s)
1018 { 1015 {
1019 m_audioGenerator->setSoloModelSet(s); 1016 m_audioGenerator->setSoloModelSet(s);
1020 clearRingBuffers(); 1017 clearRingBuffers();
1021 } 1018 }
1022 1019
1662 if ((count - processed - chunkSize) * 2 < fadeOut) { 1659 if ((count - processed - chunkSize) * 2 < fadeOut) {
1663 fadeOut = (count - processed - chunkSize) * 2; 1660 fadeOut = (count - processed - chunkSize) * 2;
1664 } 1661 }
1665 } 1662 }
1666 1663
1667 for (std::set<Model *>::iterator mi = m_models.begin(); 1664 for (std::set<ModelId>::iterator mi = m_models.begin();
1668 mi != m_models.end(); ++mi) { 1665 mi != m_models.end(); ++mi) {
1669 1666
1670 (void) m_audioGenerator->mixModel(*mi, chunkStart, 1667 (void) m_audioGenerator->mixModel(*mi, chunkStart,
1671 chunkSize, chunkBufferPtrs, 1668 chunkSize, chunkBufferPtrs,
1672 fadeIn, fadeOut); 1669 fadeIn, fadeOut);