comparison audioio/AudioGenerator.cpp @ 305:9716c75499ef tonioni

Toward using a sample mixer (with arbitrary frequency target) instead of dssi player plugin
author Chris Cannam
date Tue, 07 Jan 2014 10:58:10 +0000
parents ae1eedd6951f
children 6eb15c3aee0a
comparison
equal deleted inserted replaced
303:b6358ba5ebc6 305:9716c75499ef
25 #include "data/model/FlexiNoteModel.h" 25 #include "data/model/FlexiNoteModel.h"
26 #include "data/model/DenseTimeValueModel.h" 26 #include "data/model/DenseTimeValueModel.h"
27 #include "data/model/SparseOneDimensionalModel.h" 27 #include "data/model/SparseOneDimensionalModel.h"
28 #include "data/model/NoteData.h" 28 #include "data/model/NoteData.h"
29 29
30 #include "plugin/RealTimePluginFactory.h"
31 #include "plugin/RealTimePluginInstance.h"
32 #include "plugin/PluginIdentifier.h"
33 #include "plugin/PluginXml.h"
34 #include "plugin/api/alsa/seq_event.h"
35
36 #include <iostream> 30 #include <iostream>
37 #include <cmath> 31 #include <cmath>
38 32
39 #include <QDir> 33 #include <QDir>
40 #include <QFile> 34 #include <QFile>
41 35
42 const size_t 36 const size_t
43 AudioGenerator::m_pluginBlockSize = 2048; 37 AudioGenerator::m_processingBlockSize = 2048;
44 38
45 QString 39 QString
46 AudioGenerator::m_sampleDir = ""; 40 AudioGenerator::m_sampleDir = "";
47 41
48 //#define DEBUG_AUDIO_GENERATOR 1 42 //#define DEBUG_AUDIO_GENERATOR 1
53 m_soloing(false) 47 m_soloing(false)
54 { 48 {
55 initialiseSampleDir(); 49 initialiseSampleDir();
56 50
57 connect(PlayParameterRepository::getInstance(), 51 connect(PlayParameterRepository::getInstance(),
58 SIGNAL(playPluginIdChanged(const Playable *, QString)), 52 SIGNAL(playSampleIdChanged(const Playable *, QString)),
59 this, 53 this,
60 SLOT(playPluginIdChanged(const Playable *, QString))); 54 SLOT(playSampleIdChanged(const Playable *, QString)));
61
62 connect(PlayParameterRepository::getInstance(),
63 SIGNAL(playPluginConfigurationChanged(const Playable *, QString)),
64 this,
65 SLOT(playPluginConfigurationChanged(const Playable *, QString)));
66 } 55 }
67 56
68 AudioGenerator::~AudioGenerator() 57 AudioGenerator::~AudioGenerator()
69 { 58 {
70 #ifdef DEBUG_AUDIO_GENERATOR 59 #ifdef DEBUG_AUDIO_GENERATOR
124 if (dtvm) { 113 if (dtvm) {
125 m_sourceSampleRate = model->getSampleRate(); 114 m_sourceSampleRate = model->getSampleRate();
126 return true; 115 return true;
127 } 116 }
128 } 117 }
129 118 /*!!!
130 RealTimePluginInstance *plugin = loadPluginFor(model); 119 RealTimePluginInstance *plugin = loadPluginFor(model);
131 if (plugin) { 120 if (plugin) {
132 QMutexLocker locker(&m_mutex); 121 QMutexLocker locker(&m_mutex);
133 m_synthMap[model] = plugin; 122 m_synthMap[model] = plugin;
134 return true; 123 return true;
135 } 124 }
136 125 */
137 return false; 126 return false;
138 } 127 }
139 128
140 void 129 void
141 AudioGenerator::playPluginIdChanged(const Playable *playable, QString) 130 AudioGenerator::playSampleIdChanged(const Playable *playable, QString)
142 { 131 {
143 const Model *model = dynamic_cast<const Model *>(playable); 132 const Model *model = dynamic_cast<const Model *>(playable);
144 if (!model) { 133 if (!model) {
145 cerr << "WARNING: AudioGenerator::playPluginIdChanged: playable " 134 cerr << "WARNING: AudioGenerator::playSampleIdChanged: playable "
146 << playable << " is not a supported model type" 135 << playable << " is not a supported model type"
147 << endl; 136 << endl;
148 return; 137 return;
149 } 138 }
150 139
151 if (m_synthMap.find(model) == m_synthMap.end()) return; 140 if (m_synthMap.find(model) == m_synthMap.end()) return;
152 141 /*!!!
153 RealTimePluginInstance *plugin = loadPluginFor(model); 142 RealTimePluginInstance *plugin = loadPluginFor(model);
154 if (plugin) { 143 if (plugin) {
155 QMutexLocker locker(&m_mutex); 144 QMutexLocker locker(&m_mutex);
156 delete m_synthMap[model]; 145 delete m_synthMap[model];
157 m_synthMap[model] = plugin; 146 m_synthMap[model] = plugin;
158 } 147 }
159 } 148 */
160 149 }
150 /*!!!
161 void 151 void
162 AudioGenerator::playPluginConfigurationChanged(const Playable *playable, 152 AudioGenerator::playPluginConfigurationChanged(const Playable *playable,
163 QString configurationXml) 153 QString configurationXml)
164 { 154 {
165 // SVDEBUG << "AudioGenerator::playPluginConfigurationChanged" << endl; 155 // SVDEBUG << "AudioGenerator::playPluginConfigurationChanged" << endl;
166 156
167 const Model *model = dynamic_cast<const Model *>(playable); 157 const Model *model = dynamic_cast<const Model *>(playable);
168 if (!model) { 158 if (!model) {
169 cerr << "WARNING: AudioGenerator::playPluginIdChanged: playable " 159 cerr << "WARNING: AudioGenerator::playSampleIdChanged: playable "
170 << playable << " is not a supported model type" 160 << playable << " is not a supported model type"
171 << endl; 161 << endl;
172 return; 162 return;
173 } 163 }
174 164
200 if (!playable || !playable->canPlay()) return 0; 190 if (!playable || !playable->canPlay()) return 0;
201 191
202 PlayParameters *parameters = 192 PlayParameters *parameters =
203 PlayParameterRepository::getInstance()->getPlayParameters(playable); 193 PlayParameterRepository::getInstance()->getPlayParameters(playable);
204 if (parameters) { 194 if (parameters) {
205 pluginId = parameters->getPlayPluginId(); 195 pluginId = parameters->getPlaySampleId();
206 configurationXml = parameters->getPlayPluginConfiguration(); 196 configurationXml = parameters->getPlayPluginConfiguration();
207 } 197 }
208 198
209 std::cerr << "AudioGenerator::loadPluginFor(" << model << "): id = " << pluginId << std::endl; 199 std::cerr << "AudioGenerator::loadPluginFor(" << model << "): id = " << pluginId << std::endl;
210 200
225 } 215 }
226 216
227 configurationXml = PluginXml(plugin).toXmlString(); 217 configurationXml = PluginXml(plugin).toXmlString();
228 218
229 if (parameters) { 219 if (parameters) {
230 parameters->setPlayPluginId(pluginId); 220 parameters->setPlaySampleId(pluginId);
231 parameters->setPlayPluginConfiguration(configurationXml); 221 parameters->setPlayPluginConfiguration(configurationXml);
232 } 222 }
233 223
234 return plugin; 224 return plugin;
235 } 225 }
245 return 0; 235 return 0;
246 } 236 }
247 237
248 RealTimePluginInstance *instance = 238 RealTimePluginInstance *instance =
249 factory->instantiatePlugin 239 factory->instantiatePlugin
250 (pluginId, 0, 0, m_sourceSampleRate, m_pluginBlockSize, m_targetChannelCount); 240 (pluginId, 0, 0, m_sourceSampleRate, m_processingBlockSize, m_targetChannelCount);
251 241
252 if (!instance) { 242 if (!instance) {
253 cerr << "Failed to instantiate plugin " << pluginId << endl; 243 cerr << "Failed to instantiate plugin " << pluginId << endl;
254 return 0; 244 return 0;
255 } 245 }
270 } 260 }
271 instance->setIdealChannelCount(m_targetChannelCount); // reset! 261 instance->setIdealChannelCount(m_targetChannelCount); // reset!
272 262
273 return instance; 263 return instance;
274 } 264 }
275 265 */
276 void 266 void
277 AudioGenerator::removeModel(Model *model) 267 AudioGenerator::removeModel(Model *model)
278 { 268 {
279 SparseOneDimensionalModel *sodm = 269 SparseOneDimensionalModel *sodm =
280 dynamic_cast<SparseOneDimensionalModel *>(model); 270 dynamic_cast<SparseOneDimensionalModel *>(model);
282 272
283 QMutexLocker locker(&m_mutex); 273 QMutexLocker locker(&m_mutex);
284 274
285 if (m_synthMap.find(sodm) == m_synthMap.end()) return; 275 if (m_synthMap.find(sodm) == m_synthMap.end()) return;
286 276
287 RealTimePluginInstance *instance = m_synthMap[sodm]; 277 //!!! RealTimePluginInstance *instance = m_synthMap[sodm];
288 m_synthMap.erase(sodm); 278 // m_synthMap.erase(sodm);
289 delete instance; 279 delete instance;
290 } 280 }
291 281
292 void 282 void
293 AudioGenerator::clearModels() 283 AudioGenerator::clearModels()
294 { 284 {
295 QMutexLocker locker(&m_mutex); 285 QMutexLocker locker(&m_mutex);
286 /*!!!
296 while (!m_synthMap.empty()) { 287 while (!m_synthMap.empty()) {
297 RealTimePluginInstance *instance = m_synthMap.begin()->second; 288 RealTimePluginInstance *instance = m_synthMap.begin()->second;
298 m_synthMap.erase(m_synthMap.begin()); 289 m_synthMap.erase(m_synthMap.begin());
299 delete instance; 290 delete instance;
300 } 291 }
292 */
301 } 293 }
302 294
303 void 295 void
304 AudioGenerator::reset() 296 AudioGenerator::reset()
305 { 297 {
306 QMutexLocker locker(&m_mutex); 298 QMutexLocker locker(&m_mutex);
299 /*!!!
307 for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) { 300 for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) {
308 if (i->second) { 301 if (i->second) {
309 i->second->silence(); 302 i->second->silence();
310 i->second->discardEvents(); 303 i->second->discardEvents();
311 } 304 }
312 } 305 }
306 */
313 307
314 m_noteOffs.clear(); 308 m_noteOffs.clear();
315 } 309 }
316 310
317 void 311 void
322 // SVDEBUG << "AudioGenerator::setTargetChannelCount(" << targetChannelCount << ")" << endl; 316 // SVDEBUG << "AudioGenerator::setTargetChannelCount(" << targetChannelCount << ")" << endl;
323 317
324 QMutexLocker locker(&m_mutex); 318 QMutexLocker locker(&m_mutex);
325 m_targetChannelCount = targetChannelCount; 319 m_targetChannelCount = targetChannelCount;
326 320
321 /*!!!
327 for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) { 322 for (PluginMap::iterator i = m_synthMap.begin(); i != m_synthMap.end(); ++i) {
328 if (i->second) i->second->setIdealChannelCount(targetChannelCount); 323 if (i->second) i->second->setIdealChannelCount(targetChannelCount);
329 } 324 }
325 */
330 } 326 }
331 327
332 size_t 328 size_t
333 AudioGenerator::getBlockSize() const 329 AudioGenerator::getBlockSize() const
334 { 330 {
335 return m_pluginBlockSize; 331 return m_processingBlockSize;
336 } 332 }
337 333
338 void 334 void
339 AudioGenerator::setSoloModelSet(std::set<Model *> s) 335 AudioGenerator::setSoloModelSet(std::set<Model *> s)
340 { 336 {
516 { 512 {
517 RealTimePluginInstance *plugin = m_synthMap[model]; 513 RealTimePluginInstance *plugin = m_synthMap[model];
518 if (!plugin) return 0; 514 if (!plugin) return 0;
519 515
520 size_t latency = plugin->getLatency(); 516 size_t latency = plugin->getLatency();
521 size_t blocks = frames / m_pluginBlockSize; 517 size_t blocks = frames / m_processingBlockSize;
522 518
523 //!!! hang on -- the fact that the audio callback play source's 519 //!!! hang on -- the fact that the audio callback play source's
524 //buffer is a multiple of the plugin's buffer size doesn't mean 520 //buffer is a multiple of the plugin's buffer size doesn't mean
525 //that we always get called for a multiple of it here (because it 521 //that we always get called for a multiple of it here (because it
526 //also depends on the JACK block size). how should we ensure that 522 //also depends on the JACK block size). how should we ensure that
528 //always have a multiple of the plugin buffer size? I guess this 524 //always have a multiple of the plugin buffer size? I guess this
529 //class has to be queryable for the plugin buffer size & the 525 //class has to be queryable for the plugin buffer size & the
530 //callback play source has to use that as a multiple for all the 526 //callback play source has to use that as a multiple for all the
531 //calls to mixModel 527 //calls to mixModel
532 528
533 size_t got = blocks * m_pluginBlockSize; 529 size_t got = blocks * m_processingBlockSize;
534 530
535 #ifdef DEBUG_AUDIO_GENERATOR 531 #ifdef DEBUG_AUDIO_GENERATOR
536 cout << "mixModel [synthetic note]: frames " << frames 532 cout << "mixModel [synthetic note]: frames " << frames
537 << ", blocks " << blocks << endl; 533 << ", blocks " << blocks << endl;
538 #endif 534 #endif
548 544
549 NoteOffSet &noteOffs = m_noteOffs[model]; 545 NoteOffSet &noteOffs = m_noteOffs[model];
550 546
551 for (size_t i = 0; i < blocks; ++i) { 547 for (size_t i = 0; i < blocks; ++i) {
552 548
553 size_t reqStart = startFrame + i * m_pluginBlockSize; 549 size_t reqStart = startFrame + i * m_processingBlockSize;
554 550
555 NoteList notes; 551 NoteList notes;
556 NoteExportable *exportable = dynamic_cast<NoteExportable *>(model); 552 NoteExportable *exportable = dynamic_cast<NoteExportable *>(model);
557 if (exportable) { 553 if (exportable) {
558 notes = exportable->getNotes(reqStart + latency, 554 notes = exportable->getNotes(reqStart + latency,
559 reqStart + latency + m_pluginBlockSize); 555 reqStart + latency + m_processingBlockSize);
560 } 556 }
561 557
562 Vamp::RealTime blockTime = Vamp::RealTime::frame2RealTime 558 Vamp::RealTime blockTime = Vamp::RealTime::frame2RealTime
563 (startFrame + i * m_pluginBlockSize, m_sourceSampleRate); 559 (startFrame + i * m_processingBlockSize, m_sourceSampleRate);
564 560
565 for (NoteList::const_iterator ni = notes.begin(); 561 for (NoteList::const_iterator ni = notes.begin();
566 ni != notes.end(); ++ni) { 562 ni != notes.end(); ++ni) {
567 563
568 size_t noteFrame = ni->start; 564 size_t noteFrame = ni->start;
569 565
570 if (noteFrame >= latency) noteFrame -= latency; 566 if (noteFrame >= latency) noteFrame -= latency;
571 567
572 if (noteFrame < reqStart || 568 if (noteFrame < reqStart ||
573 noteFrame >= reqStart + m_pluginBlockSize) continue; 569 noteFrame >= reqStart + m_processingBlockSize) continue;
574 570
575 while (noteOffs.begin() != noteOffs.end() && 571 while (noteOffs.begin() != noteOffs.end() &&
576 noteOffs.begin()->frame <= noteFrame) { 572 noteOffs.begin()->frame <= noteFrame) {
577 573
578 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime 574 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
603 onEv.data.note.velocity = ni->velocity; 599 onEv.data.note.velocity = ni->velocity;
604 600
605 plugin->sendEvent(eventTime, &onEv); 601 plugin->sendEvent(eventTime, &onEv);
606 602
607 #ifdef DEBUG_AUDIO_GENERATOR 603 #ifdef DEBUG_AUDIO_GENERATOR
608 cout << "mixModel [synthetic]: note at frame " << noteFrame << ", block start " << (startFrame + i * m_pluginBlockSize) << ", resulting time " << eventTime << endl; 604 cout << "mixModel [synthetic]: note at frame " << noteFrame << ", block start " << (startFrame + i * m_processingBlockSize) << ", resulting time " << eventTime << endl;
609 #endif 605 #endif
610 606
611 noteOffs.insert 607 noteOffs.insert
612 (NoteOff(onEv.data.note.note, noteFrame + ni->duration)); 608 (NoteOff(onEv.data.note.note, noteFrame + ni->duration));
613 } 609 }
614 610
615 while (noteOffs.begin() != noteOffs.end() && 611 while (noteOffs.begin() != noteOffs.end() &&
616 noteOffs.begin()->frame <= 612 noteOffs.begin()->frame <=
617 startFrame + i * m_pluginBlockSize + m_pluginBlockSize) { 613 startFrame + i * m_processingBlockSize + m_processingBlockSize) {
618 614
619 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime 615 Vamp::RealTime eventTime = Vamp::RealTime::frame2RealTime
620 (noteOffs.begin()->frame, m_sourceSampleRate); 616 (noteOffs.begin()->frame, m_sourceSampleRate);
621 617
622 offEv.data.note.note = noteOffs.begin()->pitch; 618 offEv.data.note.note = noteOffs.begin()->pitch;
632 plugin->run(blockTime); 628 plugin->run(blockTime);
633 float **outs = plugin->getAudioOutputBuffers(); 629 float **outs = plugin->getAudioOutputBuffers();
634 630
635 for (size_t c = 0; c < m_targetChannelCount; ++c) { 631 for (size_t c = 0; c < m_targetChannelCount; ++c) {
636 #ifdef DEBUG_AUDIO_GENERATOR 632 #ifdef DEBUG_AUDIO_GENERATOR
637 cout << "mixModel [synthetic]: adding " << m_pluginBlockSize << " samples from plugin output " << c << endl; 633 cout << "mixModel [synthetic]: adding " << m_processingBlockSize << " samples from plugin output " << c << endl;
638 #endif 634 #endif
639 635
640 size_t sourceChannel = (c % plugin->getAudioOutputCount()); 636 size_t sourceChannel = (c % plugin->getAudioOutputCount());
641 637
642 float channelGain = gain; 638 float channelGain = gain;
646 } else { 642 } else {
647 if (pan < 0.0) channelGain *= pan + 1.0; 643 if (pan < 0.0) channelGain *= pan + 1.0;
648 } 644 }
649 } 645 }
650 646
651 for (size_t j = 0; j < m_pluginBlockSize; ++j) { 647 for (size_t j = 0; j < m_processingBlockSize; ++j) {
652 buffer[c][i * m_pluginBlockSize + j] += 648 buffer[c][i * m_processingBlockSize + j] +=
653 channelGain * outs[sourceChannel][j]; 649 channelGain * outs[sourceChannel][j];
654 } 650 }
655 } 651 }
656 } 652 }
657 653