Mercurial > hg > svapp
comparison audioio/AudioGenerator.cpp @ 11:8dc0ae8fccdd
* Add LED button
* Add note model playback (currently assuming that value == MIDI pitch)
* Reorganise PlayParameters and move repository from ViewManager to new
PlayParameterRepository class
author | Chris Cannam |
---|---|
date | Wed, 15 Feb 2006 17:58:35 +0000 |
parents | b6dc944128da |
children | 89bb89894ad6 |
comparison
equal
deleted
inserted
replaced
10:b6dc944128da | 11:8dc0ae8fccdd |
---|---|
9 | 9 |
10 #include "AudioGenerator.h" | 10 #include "AudioGenerator.h" |
11 | 11 |
12 #include "base/ViewManager.h" | 12 #include "base/ViewManager.h" |
13 #include "base/PlayParameters.h" | 13 #include "base/PlayParameters.h" |
14 | 14 #include "base/PlayParameterRepository.h" |
15 | |
16 #include "model/NoteModel.h" | |
15 #include "model/DenseTimeValueModel.h" | 17 #include "model/DenseTimeValueModel.h" |
16 #include "model/SparseOneDimensionalModel.h" | 18 #include "model/SparseOneDimensionalModel.h" |
17 | 19 |
18 #include "plugin/RealTimePluginFactory.h" | 20 #include "plugin/RealTimePluginFactory.h" |
19 #include "plugin/RealTimePluginInstance.h" | 21 #include "plugin/RealTimePluginInstance.h" |
56 } | 58 } |
57 } | 59 } |
58 | 60 |
59 SparseOneDimensionalModel *sodm = | 61 SparseOneDimensionalModel *sodm = |
60 dynamic_cast<SparseOneDimensionalModel *>(model); | 62 dynamic_cast<SparseOneDimensionalModel *>(model); |
61 if (!sodm) return false; // nothing else to initialise | 63 if (sodm) { |
62 | 64 QString pluginId = QString("dssi:%1:sample_player"). |
65 arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME); | |
66 RealTimePluginInstance *plugin = loadPlugin(pluginId, "cowbell"); | |
67 if (plugin) { | |
68 QMutexLocker locker(&m_mutex); | |
69 m_synthMap[sodm] = plugin; | |
70 return true; | |
71 } else { | |
72 return false; | |
73 } | |
74 } | |
75 | |
76 NoteModel *nm = dynamic_cast<NoteModel *>(model); | |
77 if (nm) { | |
78 QString pluginId = QString("dssi:%1:sample_player"). | |
79 arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME); | |
80 RealTimePluginInstance *plugin = loadPlugin(pluginId, "piano"); | |
81 if (plugin) { | |
82 QMutexLocker locker(&m_mutex); | |
83 m_synthMap[nm] = plugin; | |
84 return true; | |
85 } else { | |
86 return false; | |
87 } | |
88 } | |
89 | |
90 | |
91 return false; | |
92 } | |
93 | |
94 RealTimePluginInstance * | |
95 AudioGenerator::loadPlugin(QString pluginId, QString program) | |
96 { | |
63 // QString pluginId = "dssi:/usr/lib/dssi/dssi-vst.so:FEARkILLERrev1.dll"; | 97 // QString pluginId = "dssi:/usr/lib/dssi/dssi-vst.so:FEARkILLERrev1.dll"; |
64 // QString pluginId = "dssi:/usr/lib/dssi/hexter.so:hexter"; | 98 // QString pluginId = "dssi:/usr/lib/dssi/hexter.so:hexter"; |
65 // QString pluginId = "dssi:/usr/lib/dssi/sineshaper.so:sineshaper"; | 99 // QString pluginId = "dssi:/usr/lib/dssi/sineshaper.so:sineshaper"; |
66 // QString pluginId = "dssi:/usr/local/lib/dssi/xsynth-dssi.so:Xsynth"; | 100 // QString pluginId = "dssi:/usr/local/lib/dssi/xsynth-dssi.so:Xsynth"; |
67 // QString pluginId = "dssi:/usr/local/lib/dssi/trivial_synth.so:TS"; | 101 // QString pluginId = "dssi:/usr/local/lib/dssi/trivial_synth.so:TS"; |
68 QString pluginId = QString("dssi:%1:sample_player"). | |
69 arg(PluginIdentifier::BUILTIN_PLUGIN_SONAME); | |
70 RealTimePluginFactory *factory = | 102 RealTimePluginFactory *factory = |
71 RealTimePluginFactory::instanceFor(pluginId); | 103 RealTimePluginFactory::instanceFor(pluginId); |
72 | 104 |
73 if (!factory) { | 105 if (!factory) { |
74 std::cerr << "Failed to get plugin factory" << std::endl; | 106 std::cerr << "Failed to get plugin factory" << std::endl; |
78 RealTimePluginInstance *instance = | 110 RealTimePluginInstance *instance = |
79 factory->instantiatePlugin | 111 factory->instantiatePlugin |
80 (pluginId, 0, 0, m_sourceSampleRate, m_pluginBlockSize, m_targetChannelCount); | 112 (pluginId, 0, 0, m_sourceSampleRate, m_pluginBlockSize, m_targetChannelCount); |
81 | 113 |
82 if (instance) { | 114 if (instance) { |
83 QMutexLocker locker(&m_mutex); | |
84 m_synthMap[sodm] = instance; | |
85 for (unsigned int i = 0; i < instance->getParameterCount(); ++i) { | 115 for (unsigned int i = 0; i < instance->getParameterCount(); ++i) { |
86 instance->setParameterValue(i, instance->getParameterDefault(i)); | 116 instance->setParameterValue(i, instance->getParameterDefault(i)); |
87 } | 117 } |
88 QString program = instance->getProgram(0, 0); | 118 QString defaultProgram = instance->getProgram(0, 0); |
119 if (defaultProgram != "") { | |
120 std::cerr << "first selecting default program " << defaultProgram.toLocal8Bit().data() << std::endl; | |
121 instance->selectProgram(defaultProgram); | |
122 } | |
89 if (program != "") { | 123 if (program != "") { |
90 std::cerr << "selecting program " << program.toLocal8Bit().data() << std::endl; | 124 std::cerr << "now selecting desired program " << program.toLocal8Bit().data() << std::endl; |
91 instance->selectProgram(program); | 125 instance->selectProgram(program); |
92 } | 126 } |
93 instance->selectProgram("cowbell"); //!!! | |
94 instance->setIdealChannelCount(m_targetChannelCount); // reset! | 127 instance->setIdealChannelCount(m_targetChannelCount); // reset! |
95 } else { | 128 } else { |
96 std::cerr << "Failed to instantiate plugin" << std::endl; | 129 std::cerr << "Failed to instantiate plugin" << std::endl; |
97 return false; | 130 } |
98 } | 131 |
99 | 132 return instance; |
100 return true; | |
101 } | 133 } |
102 | 134 |
103 void | 135 void |
104 AudioGenerator::removeModel(Model *model) | 136 AudioGenerator::removeModel(Model *model) |
105 { | 137 { |
167 return frameCount; | 199 return frameCount; |
168 } | 200 } |
169 | 201 |
170 QMutexLocker locker(&m_mutex); | 202 QMutexLocker locker(&m_mutex); |
171 | 203 |
172 PlayParameters *parameters = m_viewManager->getPlayParameters(model); | 204 PlayParameters *parameters = |
205 PlayParameterRepository::instance()->getPlayParameters(model); | |
173 if (!parameters) return frameCount; | 206 if (!parameters) return frameCount; |
174 | 207 |
175 bool playing = !parameters->isPlayMuted(); | 208 bool playing = !parameters->isPlayMuted(); |
176 if (!playing) return frameCount; | 209 if (!playing) return frameCount; |
177 | 210 |
187 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> | 220 SparseOneDimensionalModel *sodm = dynamic_cast<SparseOneDimensionalModel *> |
188 (model); | 221 (model); |
189 if (sodm) { | 222 if (sodm) { |
190 return mixSparseOneDimensionalModel(sodm, startFrame, frameCount, | 223 return mixSparseOneDimensionalModel(sodm, startFrame, frameCount, |
191 buffer, gain, pan, fadeIn, fadeOut); | 224 buffer, gain, pan, fadeIn, fadeOut); |
225 } | |
226 | |
227 NoteModel *nm = dynamic_cast<NoteModel *>(model); | |
228 if (nm) { | |
229 return mixNoteModel(nm, startFrame, frameCount, | |
230 buffer, gain, pan, fadeIn, fadeOut); | |
192 } | 231 } |
193 | 232 |
194 return frameCount; | 233 return frameCount; |
195 } | 234 } |
196 | 235 |
244 } | 283 } |
245 } | 284 } |
246 | 285 |
247 return got; | 286 return got; |
248 } | 287 } |
249 | 288 |
250 size_t | 289 size_t |
251 AudioGenerator::mixSparseOneDimensionalModel(SparseOneDimensionalModel *sodm, | 290 AudioGenerator::mixSparseOneDimensionalModel(SparseOneDimensionalModel *sodm, |
252 size_t startFrame, size_t frames, | 291 size_t startFrame, size_t frames, |
253 float **buffer, float gain, float pan, | 292 float **buffer, float gain, float pan, |
254 size_t /* fadeIn */, | 293 size_t /* fadeIn */, |
375 } | 414 } |
376 | 415 |
377 return got; | 416 return got; |
378 } | 417 } |
379 | 418 |
419 | |
420 //!!! mucho duplication with above -- refactor | |
421 size_t | |
422 AudioGenerator::mixNoteModel(NoteModel *nm, | |
423 size_t startFrame, size_t frames, | |
424 float **buffer, float gain, float pan, | |
425 size_t /* fadeIn */, | |
426 size_t /* fadeOut */) | |
427 { | |
428 RealTimePluginInstance *plugin = m_synthMap[nm]; | |
429 if (!plugin) return 0; | |
430 | |
431 size_t latency = plugin->getLatency(); | |
432 size_t blocks = frames / m_pluginBlockSize; | |
433 | |
434 //!!! hang on -- the fact that the audio callback play source's | |
435 //buffer is a multiple of the plugin's buffer size doesn't mean | |
436 //that we always get called for a multiple of it here (because it | |
437 //also depends on the JACK block size). how should we ensure that | |
438 //all models write the same amount in to the mix, and that we | |
439 //always have a multiple of the plugin buffer size? I guess this | |
440 //class has to be queryable for the plugin buffer size & the | |
441 //callback play source has to use that as a multiple for all the | |
442 //calls to mixModel | |
443 | |
444 size_t got = blocks * m_pluginBlockSize; | |
445 | |
446 #ifdef DEBUG_AUDIO_GENERATOR | |
447 std::cout << "mixModel [note]: frames " << frames | |
448 << ", blocks " << blocks << std::endl; | |
449 #endif | |
450 | |
451 snd_seq_event_t onEv; | |
452 onEv.type = SND_SEQ_EVENT_NOTEON; | |
453 onEv.data.note.channel = 0; | |
454 onEv.data.note.note = 64; | |
455 onEv.data.note.velocity = 127; | |
456 | |
457 snd_seq_event_t offEv; | |
458 offEv.type = SND_SEQ_EVENT_NOTEOFF; | |
459 offEv.data.note.channel = 0; | |
460 offEv.data.note.velocity = 0; | |
461 | |
462 NoteOffSet ¬eOffs = m_noteOffs[nm]; | |
463 | |
464 for (size_t i = 0; i < blocks; ++i) { | |
465 | |
466 size_t reqStart = startFrame + i * m_pluginBlockSize; | |
467 | |
468 NoteModel::PointList points = | |
469 nm->getPoints(reqStart + latency, | |
470 reqStart + latency + m_pluginBlockSize); | |
471 | |
472 RealTime blockTime = RealTime::frame2RealTime | |
473 (startFrame + i * m_pluginBlockSize, m_sourceSampleRate); | |
474 | |
475 for (NoteModel::PointList::iterator pli = | |
476 points.begin(); pli != points.end(); ++pli) { | |
477 | |
478 size_t pliFrame = pli->frame; | |
479 | |
480 if (pliFrame >= latency) pliFrame -= latency; | |
481 | |
482 if (pliFrame < reqStart || | |
483 pliFrame >= reqStart + m_pluginBlockSize) continue; | |
484 | |
485 while (noteOffs.begin() != noteOffs.end() && | |
486 noteOffs.begin()->frame <= pliFrame) { | |
487 | |
488 RealTime eventTime = RealTime::frame2RealTime | |
489 (noteOffs.begin()->frame, m_sourceSampleRate); | |
490 | |
491 offEv.data.note.note = noteOffs.begin()->pitch; | |
492 | |
493 #ifdef DEBUG_AUDIO_GENERATOR | |
494 std::cerr << "mixModel [note]: sending note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl; | |
495 #endif | |
496 | |
497 plugin->sendEvent(eventTime, &offEv); | |
498 noteOffs.erase(noteOffs.begin()); | |
499 } | |
500 | |
501 RealTime eventTime = RealTime::frame2RealTime | |
502 (pliFrame, m_sourceSampleRate); | |
503 | |
504 onEv.data.note.note = lrintf(pli->value); | |
505 | |
506 plugin->sendEvent(eventTime, &onEv); | |
507 | |
508 #ifdef DEBUG_AUDIO_GENERATOR | |
509 std::cout << "mixModel [note]: point at frame " << pliFrame << ", block start " << (startFrame + i * m_pluginBlockSize) << ", resulting time " << eventTime << std::endl; | |
510 #endif | |
511 | |
512 size_t duration = pli->duration; | |
513 NoteOff noff; | |
514 noff.pitch = onEv.data.note.note; | |
515 noff.frame = pliFrame + duration; | |
516 noteOffs.insert(noff); | |
517 } | |
518 | |
519 while (noteOffs.begin() != noteOffs.end() && | |
520 noteOffs.begin()->frame <= | |
521 startFrame + i * m_pluginBlockSize + m_pluginBlockSize) { | |
522 | |
523 RealTime eventTime = RealTime::frame2RealTime | |
524 (noteOffs.begin()->frame, m_sourceSampleRate); | |
525 | |
526 offEv.data.note.note = noteOffs.begin()->pitch; | |
527 | |
528 #ifdef DEBUG_AUDIO_GENERATOR | |
529 std::cerr << "mixModel [note]: sending leftover note-off event at time " << eventTime << " frame " << noteOffs.begin()->frame << std::endl; | |
530 #endif | |
531 | |
532 plugin->sendEvent(eventTime, &offEv); | |
533 noteOffs.erase(noteOffs.begin()); | |
534 } | |
535 | |
536 plugin->run(blockTime); | |
537 float **outs = plugin->getAudioOutputBuffers(); | |
538 | |
539 for (size_t c = 0; c < m_targetChannelCount && c < plugin->getAudioOutputCount(); ++c) { | |
540 #ifdef DEBUG_AUDIO_GENERATOR | |
541 std::cout << "mixModel [note]: adding " << m_pluginBlockSize << " samples from plugin output " << c << std::endl; | |
542 #endif | |
543 | |
544 for (size_t j = 0; j < m_pluginBlockSize; ++j) { | |
545 buffer[c][i * m_pluginBlockSize + j] += gain * outs[c][j]; | |
546 } | |
547 } | |
548 } | |
549 | |
550 return got; | |
551 } | |
552 |