Mercurial > hg > svapp
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 ¬eOffs = m_noteOffs[model]; | 545 NoteOffSet ¬eOffs = 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 |