Mercurial > hg > easaier-soundaccess
comparison plugin/DSSIPluginInstance.cpp @ 0:fc9323a41f5a
start base : Sonic Visualiser sv1-1.0rc1
author | lbajardsilogic |
---|---|
date | Fri, 11 May 2007 09:08:14 +0000 |
parents | |
children | be6d31baecb9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:fc9323a41f5a |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Sonic Visualiser | |
5 An audio file viewer and annotation editor. | |
6 Centre for Digital Music, Queen Mary, University of London. | |
7 | |
8 This program is free software; you can redistribute it and/or | |
9 modify it under the terms of the GNU General Public License as | |
10 published by the Free Software Foundation; either version 2 of the | |
11 License, or (at your option) any later version. See the file | |
12 COPYING included with this distribution for more information. | |
13 */ | |
14 | |
15 /* | |
16 This is a modified version of a source file from the | |
17 Rosegarden MIDI and audio sequencer and notation editor. | |
18 This file copyright 2000-2006 Chris Cannam. | |
19 */ | |
20 | |
21 #include <iostream> | |
22 #include <cassert> | |
23 | |
24 #include "DSSIPluginInstance.h" | |
25 #include "PluginIdentifier.h" | |
26 #include "LADSPAPluginFactory.h" | |
27 | |
28 //#define DEBUG_DSSI 1 | |
29 //#define DEBUG_DSSI_PROCESS 1 | |
30 | |
31 #define EVENT_BUFFER_SIZE 1023 | |
32 | |
33 #ifdef DEBUG_DSSI | |
34 static std::ostream &operator<<(std::ostream& o, const QString &s) | |
35 { | |
36 o << s.toLocal8Bit().data(); | |
37 return o; | |
38 } | |
39 #endif | |
40 | |
41 DSSIPluginInstance::GroupMap DSSIPluginInstance::m_groupMap; | |
42 snd_seq_event_t **DSSIPluginInstance::m_groupLocalEventBuffers = 0; | |
43 size_t DSSIPluginInstance::m_groupLocalEventBufferCount = 0; | |
44 Scavenger<ScavengerArrayWrapper<snd_seq_event_t *> > DSSIPluginInstance::m_bufferScavenger(2, 10); | |
45 std::map<LADSPA_Handle, std::set<DSSIPluginInstance::NonRTPluginThread *> > DSSIPluginInstance::m_threads; | |
46 | |
47 | |
48 DSSIPluginInstance::DSSIPluginInstance(RealTimePluginFactory *factory, | |
49 int clientId, | |
50 QString identifier, | |
51 int position, | |
52 unsigned long sampleRate, | |
53 size_t blockSize, | |
54 int idealChannelCount, | |
55 const DSSI_Descriptor* descriptor) : | |
56 RealTimePluginInstance(factory, identifier), | |
57 m_client(clientId), | |
58 m_position(position), | |
59 m_descriptor(descriptor), | |
60 m_programCacheValid(false), | |
61 m_eventBuffer(EVENT_BUFFER_SIZE), | |
62 m_blockSize(blockSize), | |
63 m_idealChannelCount(idealChannelCount), | |
64 m_sampleRate(sampleRate), | |
65 m_latencyPort(0), | |
66 m_run(false), | |
67 m_bypassed(false), | |
68 m_grouped(false), | |
69 m_haveLastEventSendTime(false) | |
70 { | |
71 #ifdef DEBUG_DSSI | |
72 std::cerr << "DSSIPluginInstance::DSSIPluginInstance(" << identifier << ")" | |
73 << std::endl; | |
74 #endif | |
75 | |
76 init(); | |
77 | |
78 m_inputBuffers = new sample_t*[m_audioPortsIn.size()]; | |
79 m_outputBuffers = new sample_t*[m_outputBufferCount]; | |
80 | |
81 for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { | |
82 m_inputBuffers[i] = new sample_t[blockSize]; | |
83 } | |
84 for (size_t i = 0; i < m_outputBufferCount; ++i) { | |
85 m_outputBuffers[i] = new sample_t[blockSize]; | |
86 } | |
87 | |
88 m_ownBuffers = true; | |
89 | |
90 m_pending.lsb = m_pending.msb = m_pending.program = -1; | |
91 | |
92 instantiate(sampleRate); | |
93 if (isOK()) { | |
94 connectPorts(); | |
95 activate(); | |
96 initialiseGroupMembership(); | |
97 } | |
98 } | |
99 | |
100 std::string | |
101 DSSIPluginInstance::getIdentifier() const | |
102 { | |
103 return m_descriptor->LADSPA_Plugin->Label; | |
104 } | |
105 | |
106 std::string | |
107 DSSIPluginInstance::getName() const | |
108 { | |
109 return m_descriptor->LADSPA_Plugin->Name; | |
110 } | |
111 | |
112 std::string | |
113 DSSIPluginInstance::getDescription() const | |
114 { | |
115 return ""; | |
116 } | |
117 | |
118 std::string | |
119 DSSIPluginInstance::getMaker() const | |
120 { | |
121 return m_descriptor->LADSPA_Plugin->Maker; | |
122 } | |
123 | |
124 int | |
125 DSSIPluginInstance::getPluginVersion() const | |
126 { | |
127 return 1; | |
128 } | |
129 | |
130 std::string | |
131 DSSIPluginInstance::getCopyright() const | |
132 { | |
133 return m_descriptor->LADSPA_Plugin->Copyright; | |
134 } | |
135 | |
136 DSSIPluginInstance::ParameterList | |
137 DSSIPluginInstance::getParameterDescriptors() const | |
138 { | |
139 ParameterList list; | |
140 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); | |
141 | |
142 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { | |
143 | |
144 ParameterDescriptor pd; | |
145 unsigned int pn = m_controlPortsIn[i].first; | |
146 | |
147 pd.identifier = m_descriptor->LADSPA_Plugin->PortNames[pn]; | |
148 pd.name = pd.identifier; | |
149 pd.description = ""; | |
150 pd.minValue = f->getPortMinimum(m_descriptor->LADSPA_Plugin, pn); | |
151 pd.maxValue = f->getPortMaximum(m_descriptor->LADSPA_Plugin, pn); | |
152 pd.defaultValue = f->getPortDefault(m_descriptor->LADSPA_Plugin, pn); | |
153 | |
154 float q = f->getPortQuantization(m_descriptor->LADSPA_Plugin, pn); | |
155 if (q == 0.0) { | |
156 pd.isQuantized = false; | |
157 } else { | |
158 pd.isQuantized = true; | |
159 pd.quantizeStep = q; | |
160 } | |
161 | |
162 list.push_back(pd); | |
163 } | |
164 | |
165 return list; | |
166 } | |
167 | |
168 float | |
169 DSSIPluginInstance::getParameter(std::string id) const | |
170 { | |
171 #ifdef DEBUG_DSSI | |
172 std::cerr << "DSSIPluginInstance::getParameter(" << id << ")" << std::endl; | |
173 #endif | |
174 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { | |
175 if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) { | |
176 #ifdef DEBUG_DSSI | |
177 std::cerr << "Matches port " << i << std::endl; | |
178 #endif | |
179 float v = getParameterValue(i); | |
180 #ifdef DEBUG_DSSI | |
181 std::cerr << "Returning " << v << std::endl; | |
182 #endif | |
183 return v; | |
184 } | |
185 } | |
186 | |
187 return 0.0; | |
188 } | |
189 | |
190 void | |
191 DSSIPluginInstance::setParameter(std::string id, float value) | |
192 { | |
193 #ifdef DEBUG_DSSI | |
194 std::cerr << "DSSIPluginInstance::setParameter(" << id << ", " << value << ")" << std::endl; | |
195 #endif | |
196 | |
197 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { | |
198 if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) { | |
199 setParameterValue(i, value); | |
200 break; | |
201 } | |
202 } | |
203 } | |
204 | |
205 void | |
206 DSSIPluginInstance::init() | |
207 { | |
208 #ifdef DEBUG_DSSI | |
209 std::cerr << "DSSIPluginInstance::init" << std::endl; | |
210 #endif | |
211 | |
212 // Discover ports numbers and identities | |
213 // | |
214 const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; | |
215 | |
216 for (unsigned long i = 0; i < descriptor->PortCount; ++i) | |
217 { | |
218 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[i])) | |
219 { | |
220 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { | |
221 m_audioPortsIn.push_back(i); | |
222 } else { | |
223 m_audioPortsOut.push_back(i); | |
224 } | |
225 } | |
226 else | |
227 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) | |
228 { | |
229 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { | |
230 | |
231 LADSPA_Data *data = new LADSPA_Data(0.0); | |
232 | |
233 m_controlPortsIn.push_back(std::pair<unsigned long, LADSPA_Data*> | |
234 (i, data)); | |
235 | |
236 m_backupControlPortsIn.push_back(0.0); | |
237 | |
238 } else { | |
239 LADSPA_Data *data = new LADSPA_Data(0.0); | |
240 m_controlPortsOut.push_back( | |
241 std::pair<unsigned long, LADSPA_Data*>(i, data)); | |
242 if (!strcmp(descriptor->PortNames[i], "latency") || | |
243 !strcmp(descriptor->PortNames[i], "_latency")) { | |
244 #ifdef DEBUG_DSSI | |
245 std::cerr << "Wooo! We have a latency port!" << std::endl; | |
246 #endif | |
247 m_latencyPort = data; | |
248 } | |
249 } | |
250 } | |
251 #ifdef DEBUG_DSSI | |
252 else | |
253 std::cerr << "DSSIPluginInstance::DSSIPluginInstance - " | |
254 << "unrecognised port type" << std::endl; | |
255 #endif | |
256 } | |
257 | |
258 m_outputBufferCount = max(m_idealChannelCount, m_audioPortsOut.size()); | |
259 } | |
260 | |
261 size_t | |
262 DSSIPluginInstance::getLatency() | |
263 { | |
264 size_t latency = 0; | |
265 | |
266 #ifdef DEBUG_DSSI_PROCESS | |
267 std::cerr << "DSSIPluginInstance::getLatency(): m_latencyPort " << m_latencyPort << ", m_run " << m_run << std::endl; | |
268 #endif | |
269 | |
270 if (m_latencyPort) { | |
271 if (!m_run) { | |
272 for (size_t i = 0; i < getAudioInputCount(); ++i) { | |
273 for (size_t j = 0; j < m_blockSize; ++j) { | |
274 m_inputBuffers[i][j] = 0.f; | |
275 } | |
276 } | |
277 run(Vamp::RealTime::zeroTime); | |
278 } | |
279 latency = (size_t)(*m_latencyPort + 0.1); | |
280 } | |
281 | |
282 #ifdef DEBUG_DSSI_PROCESS | |
283 std::cerr << "DSSIPluginInstance::getLatency(): latency is " << latency << std::endl; | |
284 #endif | |
285 | |
286 return latency; | |
287 } | |
288 | |
289 void | |
290 DSSIPluginInstance::silence() | |
291 { | |
292 if (m_instanceHandle != 0) { | |
293 deactivate(); | |
294 activate(); | |
295 } | |
296 } | |
297 | |
298 void | |
299 DSSIPluginInstance::discardEvents() | |
300 { | |
301 m_eventBuffer.reset(); | |
302 } | |
303 | |
304 void | |
305 DSSIPluginInstance::setIdealChannelCount(size_t channels) | |
306 { | |
307 #ifdef DEBUG_DSSI | |
308 std::cerr << "DSSIPluginInstance::setIdealChannelCount: channel count " | |
309 << channels << " (was " << m_idealChannelCount << ")" << std::endl; | |
310 #endif | |
311 | |
312 if (channels == m_idealChannelCount) { | |
313 silence(); | |
314 return; | |
315 } | |
316 | |
317 if (m_instanceHandle != 0) { | |
318 deactivate(); | |
319 } | |
320 | |
321 m_idealChannelCount = channels; | |
322 | |
323 if (channels > m_outputBufferCount) { | |
324 | |
325 for (size_t i = 0; i < m_outputBufferCount; ++i) { | |
326 delete[] m_outputBuffers[i]; | |
327 } | |
328 | |
329 delete[] m_outputBuffers; | |
330 | |
331 m_outputBufferCount = channels; | |
332 | |
333 m_outputBuffers = new sample_t*[m_outputBufferCount]; | |
334 | |
335 for (size_t i = 0; i < m_outputBufferCount; ++i) { | |
336 m_outputBuffers[i] = new sample_t[m_blockSize]; | |
337 } | |
338 | |
339 connectPorts(); | |
340 } | |
341 | |
342 if (m_instanceHandle != 0) { | |
343 activate(); | |
344 } | |
345 } | |
346 | |
347 void | |
348 DSSIPluginInstance::detachFromGroup() | |
349 { | |
350 if (!m_grouped) return; | |
351 m_groupMap[m_identifier].erase(this); | |
352 m_grouped = false; | |
353 } | |
354 | |
355 void | |
356 DSSIPluginInstance::initialiseGroupMembership() | |
357 { | |
358 if (!m_descriptor->run_multiple_synths) { | |
359 m_grouped = false; | |
360 return; | |
361 } | |
362 | |
363 //!!! GroupMap is not actually thread-safe. | |
364 | |
365 size_t pluginsInGroup = m_groupMap[m_identifier].size(); | |
366 | |
367 if (++pluginsInGroup > m_groupLocalEventBufferCount) { | |
368 | |
369 size_t nextBufferCount = pluginsInGroup * 2; | |
370 | |
371 snd_seq_event_t **eventLocalBuffers = new snd_seq_event_t *[nextBufferCount]; | |
372 | |
373 for (size_t i = 0; i < m_groupLocalEventBufferCount; ++i) { | |
374 eventLocalBuffers[i] = m_groupLocalEventBuffers[i]; | |
375 } | |
376 for (size_t i = m_groupLocalEventBufferCount; i < nextBufferCount; ++i) { | |
377 eventLocalBuffers[i] = new snd_seq_event_t[EVENT_BUFFER_SIZE]; | |
378 } | |
379 | |
380 if (m_groupLocalEventBuffers) { | |
381 m_bufferScavenger.claim(new ScavengerArrayWrapper<snd_seq_event_t *> | |
382 (m_groupLocalEventBuffers)); | |
383 } | |
384 | |
385 m_groupLocalEventBuffers = eventLocalBuffers; | |
386 m_groupLocalEventBufferCount = nextBufferCount; | |
387 } | |
388 | |
389 m_grouped = true; | |
390 m_groupMap[m_identifier].insert(this); | |
391 } | |
392 | |
393 DSSIPluginInstance::~DSSIPluginInstance() | |
394 { | |
395 #ifdef DEBUG_DSSI | |
396 std::cerr << "DSSIPluginInstance::~DSSIPluginInstance" << std::endl; | |
397 #endif | |
398 | |
399 if (m_threads.find(m_instanceHandle) != m_threads.end()) { | |
400 | |
401 for (std::set<NonRTPluginThread *>::iterator i = | |
402 m_threads[m_instanceHandle].begin(); | |
403 i != m_threads[m_instanceHandle].end(); ++i) { | |
404 | |
405 (*i)->setExiting(); | |
406 (*i)->wait(); | |
407 delete *i; | |
408 } | |
409 | |
410 m_threads.erase(m_instanceHandle); | |
411 } | |
412 | |
413 detachFromGroup(); | |
414 | |
415 if (m_instanceHandle != 0) { | |
416 deactivate(); | |
417 } | |
418 | |
419 cleanup(); | |
420 | |
421 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) | |
422 delete m_controlPortsIn[i].second; | |
423 | |
424 for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) | |
425 delete m_controlPortsOut[i].second; | |
426 | |
427 m_controlPortsIn.clear(); | |
428 m_controlPortsOut.clear(); | |
429 | |
430 if (m_ownBuffers) { | |
431 for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { | |
432 delete[] m_inputBuffers[i]; | |
433 } | |
434 for (size_t i = 0; i < m_outputBufferCount; ++i) { | |
435 delete[] m_outputBuffers[i]; | |
436 } | |
437 | |
438 delete[] m_inputBuffers; | |
439 delete[] m_outputBuffers; | |
440 } | |
441 | |
442 m_audioPortsIn.clear(); | |
443 m_audioPortsOut.clear(); | |
444 } | |
445 | |
446 | |
447 void | |
448 DSSIPluginInstance::instantiate(unsigned long sampleRate) | |
449 { | |
450 #ifdef DEBUG_DSSI | |
451 std::cout << "DSSIPluginInstance::instantiate - plugin \"unique\" id = " | |
452 << m_descriptor->LADSPA_Plugin->UniqueID << std::endl; | |
453 #endif | |
454 if (!m_descriptor) return; | |
455 | |
456 const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; | |
457 | |
458 if (!descriptor->instantiate) { | |
459 std::cerr << "Bad plugin: plugin id " << descriptor->UniqueID | |
460 << ":" << descriptor->Label | |
461 << " has no instantiate method!" << std::endl; | |
462 return; | |
463 } | |
464 | |
465 m_instanceHandle = descriptor->instantiate(descriptor, sampleRate); | |
466 | |
467 if (m_instanceHandle) { | |
468 | |
469 if (m_descriptor->get_midi_controller_for_port) { | |
470 | |
471 for (unsigned long i = 0; i < descriptor->PortCount; ++i) { | |
472 | |
473 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i]) && | |
474 LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { | |
475 | |
476 int controller = m_descriptor->get_midi_controller_for_port | |
477 (m_instanceHandle, i); | |
478 | |
479 if (controller != 0 && controller != 32 && | |
480 DSSI_IS_CC(controller)) { | |
481 | |
482 m_controllerMap[DSSI_CC_NUMBER(controller)] = i; | |
483 } | |
484 } | |
485 } | |
486 } | |
487 } | |
488 } | |
489 | |
490 void | |
491 DSSIPluginInstance::checkProgramCache() const | |
492 { | |
493 if (m_programCacheValid) return; | |
494 m_cachedPrograms.clear(); | |
495 | |
496 #ifdef DEBUG_DSSI | |
497 std::cerr << "DSSIPluginInstance::checkProgramCache" << std::endl; | |
498 #endif | |
499 | |
500 if (!m_descriptor || !m_descriptor->get_program) { | |
501 m_programCacheValid = true; | |
502 return; | |
503 } | |
504 | |
505 unsigned long index = 0; | |
506 const DSSI_Program_Descriptor *programDescriptor; | |
507 while ((programDescriptor = m_descriptor->get_program(m_instanceHandle, index))) { | |
508 ++index; | |
509 ProgramDescriptor d; | |
510 d.bank = programDescriptor->Bank; | |
511 d.program = programDescriptor->Program; | |
512 d.name = programDescriptor->Name; | |
513 m_cachedPrograms.push_back(d); | |
514 } | |
515 | |
516 #ifdef DEBUG_DSSI | |
517 std::cerr << "DSSIPluginInstance::checkProgramCache: have " << m_cachedPrograms.size() << " programs" << std::endl; | |
518 #endif | |
519 | |
520 m_programCacheValid = true; | |
521 } | |
522 | |
523 DSSIPluginInstance::ProgramList | |
524 DSSIPluginInstance::getPrograms() const | |
525 { | |
526 #ifdef DEBUG_DSSI | |
527 std::cerr << "DSSIPluginInstance::getPrograms" << std::endl; | |
528 #endif | |
529 | |
530 if (!m_descriptor) return ProgramList(); | |
531 | |
532 checkProgramCache(); | |
533 | |
534 ProgramList programs; | |
535 | |
536 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); | |
537 i != m_cachedPrograms.end(); ++i) { | |
538 programs.push_back(i->name); | |
539 } | |
540 | |
541 return programs; | |
542 } | |
543 | |
544 std::string | |
545 DSSIPluginInstance::getProgram(int bank, int program) const | |
546 { | |
547 #ifdef DEBUG_DSSI | |
548 std::cerr << "DSSIPluginInstance::getProgram(" << bank << "," << program << ")" << std::endl; | |
549 #endif | |
550 | |
551 if (!m_descriptor) return std::string(); | |
552 | |
553 checkProgramCache(); | |
554 | |
555 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); | |
556 i != m_cachedPrograms.end(); ++i) { | |
557 if (i->bank == bank && i->program == program) return i->name; | |
558 } | |
559 | |
560 return std::string(); | |
561 } | |
562 | |
563 unsigned long | |
564 DSSIPluginInstance::getProgram(std::string name) const | |
565 { | |
566 #ifdef DEBUG_DSSI | |
567 std::cerr << "DSSIPluginInstance::getProgram(" << name << ")" << std::endl; | |
568 #endif | |
569 | |
570 if (!m_descriptor) return 0; | |
571 | |
572 checkProgramCache(); | |
573 | |
574 unsigned long rv; | |
575 | |
576 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); | |
577 i != m_cachedPrograms.end(); ++i) { | |
578 if (i->name == name) { | |
579 rv = i->bank; | |
580 rv = (rv << 16) + i->program; | |
581 return rv; | |
582 } | |
583 } | |
584 | |
585 return 0; | |
586 } | |
587 | |
588 std::string | |
589 DSSIPluginInstance::getCurrentProgram() const | |
590 { | |
591 return m_program; | |
592 } | |
593 | |
594 void | |
595 DSSIPluginInstance::selectProgram(std::string program) | |
596 { | |
597 selectProgramAux(program, true); | |
598 } | |
599 | |
600 void | |
601 DSSIPluginInstance::selectProgramAux(std::string program, bool backupPortValues) | |
602 { | |
603 #ifdef DEBUG_DSSI | |
604 std::cerr << "DSSIPluginInstance::selectProgram(" << program << ")" << std::endl; | |
605 #endif | |
606 | |
607 if (!m_descriptor) return; | |
608 | |
609 checkProgramCache(); | |
610 | |
611 if (!m_descriptor->select_program) return; | |
612 | |
613 bool found = false; | |
614 unsigned long bankNo = 0, programNo = 0; | |
615 | |
616 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); | |
617 i != m_cachedPrograms.end(); ++i) { | |
618 | |
619 if (i->name == program) { | |
620 | |
621 bankNo = i->bank; | |
622 programNo = i->program; | |
623 found = true; | |
624 | |
625 #ifdef DEBUG_DSSI | |
626 std::cerr << "DSSIPluginInstance::selectProgram(" << program << "): found at bank " << bankNo << ", program " << programNo << std::endl; | |
627 #endif | |
628 | |
629 break; | |
630 } | |
631 } | |
632 | |
633 if (!found) return; | |
634 m_program = program; | |
635 | |
636 // DSSI select_program is an audio context call | |
637 m_processLock.lock(); | |
638 m_descriptor->select_program(m_instanceHandle, bankNo, programNo); | |
639 m_processLock.unlock(); | |
640 | |
641 #ifdef DEBUG_DSSI | |
642 std::cerr << "DSSIPluginInstance::selectProgram(" << program << "): made select_program(" << bankNo << "," << programNo << ") call" << std::endl; | |
643 #endif | |
644 | |
645 if (backupPortValues) { | |
646 for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { | |
647 m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; | |
648 } | |
649 } | |
650 } | |
651 | |
652 void | |
653 DSSIPluginInstance::activate() | |
654 { | |
655 #ifdef DEBUG_DSSI | |
656 std::cerr << "DSSIPluginInstance::activate" << std::endl; | |
657 #endif | |
658 | |
659 if (!m_descriptor || !m_descriptor->LADSPA_Plugin->activate) return; | |
660 m_descriptor->LADSPA_Plugin->activate(m_instanceHandle); | |
661 | |
662 if (m_program != "") { | |
663 #ifdef DEBUG_DSSI | |
664 std::cerr << "DSSIPluginInstance::activate: restoring program " << m_program << std::endl; | |
665 #endif | |
666 selectProgramAux(m_program, false); | |
667 } | |
668 | |
669 for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { | |
670 #ifdef DEBUG_DSSI | |
671 std::cerr << "DSSIPluginInstance::activate: setting port " << m_controlPortsIn[i].first << " to " << m_backupControlPortsIn[i] << std::endl; | |
672 #endif | |
673 *m_controlPortsIn[i].second = m_backupControlPortsIn[i]; | |
674 } | |
675 } | |
676 | |
677 void | |
678 DSSIPluginInstance::connectPorts() | |
679 { | |
680 if (!m_descriptor || !m_descriptor->LADSPA_Plugin->connect_port) return; | |
681 #ifdef DEBUG_DSSI | |
682 std::cerr << "DSSIPluginInstance::connectPorts: " << m_audioPortsIn.size() | |
683 << " audio ports in, " << m_audioPortsOut.size() << " out, " | |
684 << m_outputBufferCount << " output buffers" << std::endl; | |
685 #endif | |
686 | |
687 assert(sizeof(LADSPA_Data) == sizeof(float)); | |
688 assert(sizeof(sample_t) == sizeof(float)); | |
689 | |
690 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); | |
691 int inbuf = 0, outbuf = 0; | |
692 | |
693 for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) { | |
694 m_descriptor->LADSPA_Plugin->connect_port | |
695 (m_instanceHandle, | |
696 m_audioPortsIn[i], | |
697 (LADSPA_Data *)m_inputBuffers[inbuf]); | |
698 ++inbuf; | |
699 } | |
700 | |
701 for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) { | |
702 m_descriptor->LADSPA_Plugin->connect_port | |
703 (m_instanceHandle, | |
704 m_audioPortsOut[i], | |
705 (LADSPA_Data *)m_outputBuffers[outbuf]); | |
706 ++outbuf; | |
707 } | |
708 | |
709 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { | |
710 m_descriptor->LADSPA_Plugin->connect_port | |
711 (m_instanceHandle, | |
712 m_controlPortsIn[i].first, | |
713 m_controlPortsIn[i].second); | |
714 | |
715 if (f) { | |
716 float defaultValue = f->getPortDefault | |
717 (m_descriptor->LADSPA_Plugin, m_controlPortsIn[i].first); | |
718 *m_controlPortsIn[i].second = defaultValue; | |
719 m_backupControlPortsIn[i] = defaultValue; | |
720 #ifdef DEBUG_DSSI | |
721 std::cerr << "DSSIPluginInstance::connectPorts: set control port " << i << " to default value " << defaultValue << std::endl; | |
722 #endif | |
723 } | |
724 } | |
725 | |
726 for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) { | |
727 m_descriptor->LADSPA_Plugin->connect_port | |
728 (m_instanceHandle, | |
729 m_controlPortsOut[i].first, | |
730 m_controlPortsOut[i].second); | |
731 } | |
732 } | |
733 | |
734 unsigned int | |
735 DSSIPluginInstance::getParameterCount() const | |
736 { | |
737 return m_controlPortsIn.size(); | |
738 } | |
739 | |
740 void | |
741 DSSIPluginInstance::setParameterValue(unsigned int parameter, float value) | |
742 { | |
743 #ifdef DEBUG_DSSI | |
744 std::cerr << "DSSIPluginInstance::setParameterValue(" << parameter << ") to " << value << std::endl; | |
745 #endif | |
746 if (parameter >= m_controlPortsIn.size()) return; | |
747 | |
748 unsigned int portNumber = m_controlPortsIn[parameter].first; | |
749 | |
750 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); | |
751 if (f) { | |
752 if (value < f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber)) { | |
753 value = f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber); | |
754 } | |
755 if (value > f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber)) { | |
756 value = f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber); | |
757 } | |
758 } | |
759 | |
760 (*m_controlPortsIn[parameter].second) = value; | |
761 m_backupControlPortsIn[parameter] = value; | |
762 } | |
763 | |
764 void | |
765 DSSIPluginInstance::setPortValueFromController(unsigned int port, int cv) | |
766 { | |
767 #ifdef DEBUG_DSSI | |
768 std::cerr << "DSSIPluginInstance::setPortValueFromController(" << port << ") to " << cv << std::endl; | |
769 #endif | |
770 | |
771 const LADSPA_Descriptor *p = m_descriptor->LADSPA_Plugin; | |
772 LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor; | |
773 LADSPA_Data lb = p->PortRangeHints[port].LowerBound; | |
774 LADSPA_Data ub = p->PortRangeHints[port].UpperBound; | |
775 | |
776 float value = (float)cv; | |
777 | |
778 if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) { | |
779 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { | |
780 /* unbounded: might as well leave the value alone. */ | |
781 } else { | |
782 /* bounded above only. just shift the range. */ | |
783 value = ub - 127.0f + value; | |
784 } | |
785 } else { | |
786 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { | |
787 /* bounded below only. just shift the range. */ | |
788 value = lb + value; | |
789 } else { | |
790 /* bounded both ends. more interesting. */ | |
791 /* XXX !!! todo: fill in logarithmic, sample rate &c */ | |
792 value = lb + ((ub - lb) * value / 127.0f); | |
793 } | |
794 } | |
795 | |
796 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { | |
797 if (m_controlPortsIn[i].first == port) { | |
798 setParameterValue(i, value); | |
799 } | |
800 } | |
801 } | |
802 | |
803 float | |
804 DSSIPluginInstance::getControlOutputValue(size_t output) const | |
805 { | |
806 if (output > m_controlPortsOut.size()) return 0.0; | |
807 return (*m_controlPortsOut[output].second); | |
808 } | |
809 | |
810 float | |
811 DSSIPluginInstance::getParameterValue(unsigned int parameter) const | |
812 { | |
813 #ifdef DEBUG_DSSI | |
814 std::cerr << "DSSIPluginInstance::getParameterValue(" << parameter << ")" << std::endl; | |
815 #endif | |
816 if (parameter >= m_controlPortsIn.size()) return 0.0; | |
817 return (*m_controlPortsIn[parameter].second); | |
818 } | |
819 | |
820 float | |
821 DSSIPluginInstance::getParameterDefault(unsigned int parameter) const | |
822 { | |
823 if (parameter >= m_controlPortsIn.size()) return 0.0; | |
824 | |
825 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); | |
826 if (f) { | |
827 return f->getPortDefault(m_descriptor->LADSPA_Plugin, | |
828 m_controlPortsIn[parameter].first); | |
829 } else { | |
830 return 0.0f; | |
831 } | |
832 } | |
833 | |
834 std::string | |
835 DSSIPluginInstance::configure(std::string key, | |
836 std::string value) | |
837 { | |
838 if (!m_descriptor || !m_descriptor->configure) return std::string(); | |
839 | |
840 if (key == PluginIdentifier::RESERVED_PROJECT_DIRECTORY_KEY.toStdString()) { | |
841 #ifdef DSSI_PROJECT_DIRECTORY_KEY | |
842 key = DSSI_PROJECT_DIRECTORY_KEY; | |
843 #else | |
844 return std::string(); | |
845 #endif | |
846 } | |
847 | |
848 | |
849 #ifdef DEBUG_DSSI | |
850 std::cerr << "DSSIPluginInstance::configure(" << key << "," << value << ")" << std::endl; | |
851 #endif | |
852 | |
853 char *message = m_descriptor->configure(m_instanceHandle, | |
854 key.c_str(), | |
855 value.c_str()); | |
856 | |
857 m_programCacheValid = false; | |
858 | |
859 m_configurationData[key] = value; | |
860 | |
861 std::string qm; | |
862 | |
863 // Ignore return values from reserved key configuration calls such | |
864 // as project directory | |
865 #ifdef DSSI_RESERVED_CONFIGURE_PREFIX | |
866 if (QString(key.c_str()).startsWith(DSSI_RESERVED_CONFIGURE_PREFIX)) { | |
867 return qm; | |
868 } | |
869 #endif | |
870 | |
871 if (message) { | |
872 if (m_descriptor->LADSPA_Plugin && m_descriptor->LADSPA_Plugin->Label) { | |
873 qm = std::string(m_descriptor->LADSPA_Plugin->Label) + ": "; | |
874 } | |
875 qm = qm + message; | |
876 free(message); | |
877 | |
878 std::cerr << "DSSIPluginInstance::configure: warning: configure returned message: \"" << qm << "\"" << std::endl; | |
879 } | |
880 | |
881 return qm; | |
882 } | |
883 | |
884 void | |
885 DSSIPluginInstance::sendEvent(const Vamp::RealTime &eventTime, | |
886 const void *e) | |
887 { | |
888 #ifdef DEBUG_DSSI_PROCESS | |
889 std::cerr << "DSSIPluginInstance::sendEvent: last was " << m_lastEventSendTime << " (valid " << m_haveLastEventSendTime << "), this is " << eventTime << std::endl; | |
890 #endif | |
891 | |
892 // The process mechanism only works correctly if the events are | |
893 // sorted. It's the responsibility of the caller to ensure that: | |
894 // we will happily drop events here if we find the timeline going | |
895 // backwards. | |
896 if (m_haveLastEventSendTime && | |
897 m_lastEventSendTime > eventTime) { | |
898 #ifdef DEBUG_DSSI_PROCESS | |
899 std::cerr << "... clearing down" << std::endl; | |
900 #endif | |
901 m_haveLastEventSendTime = false; | |
902 clearEvents(); | |
903 } | |
904 | |
905 snd_seq_event_t *event = (snd_seq_event_t *)e; | |
906 #ifdef DEBUG_DSSI_PROCESS | |
907 std::cerr << "DSSIPluginInstance::sendEvent at " << eventTime << std::endl; | |
908 #endif | |
909 snd_seq_event_t ev(*event); | |
910 | |
911 ev.time.time.tv_sec = eventTime.sec; | |
912 ev.time.time.tv_nsec = eventTime.nsec; | |
913 | |
914 // DSSI doesn't use MIDI channels, it uses run_multiple_synths instead. | |
915 ev.data.note.channel = 0; | |
916 | |
917 m_eventBuffer.write(&ev, 1); | |
918 | |
919 m_lastEventSendTime = eventTime; | |
920 m_haveLastEventSendTime = true; | |
921 } | |
922 | |
923 void | |
924 DSSIPluginInstance::clearEvents() | |
925 { | |
926 m_haveLastEventSendTime = false; | |
927 m_eventBuffer.reset(); | |
928 } | |
929 | |
930 bool | |
931 DSSIPluginInstance::handleController(snd_seq_event_t *ev) | |
932 { | |
933 int controller = ev->data.control.param; | |
934 | |
935 #ifdef DEBUG_DSSI_PROCESS | |
936 std::cerr << "DSSIPluginInstance::handleController " << controller << std::endl; | |
937 #endif | |
938 | |
939 if (controller == 0) { // bank select MSB | |
940 | |
941 m_pending.msb = ev->data.control.value; | |
942 | |
943 } else if (controller == 32) { // bank select LSB | |
944 | |
945 m_pending.lsb = ev->data.control.value; | |
946 | |
947 } else if (controller > 0 && controller < 128) { | |
948 | |
949 if (m_controllerMap.find(controller) != m_controllerMap.end()) { | |
950 int port = m_controllerMap[controller]; | |
951 setPortValueFromController(port, ev->data.control.value); | |
952 } else { | |
953 return true; // pass through to plugin | |
954 } | |
955 } | |
956 | |
957 return false; | |
958 } | |
959 | |
960 void | |
961 DSSIPluginInstance::run(const Vamp::RealTime &blockTime) | |
962 { | |
963 static snd_seq_event_t localEventBuffer[EVENT_BUFFER_SIZE]; | |
964 int evCount = 0; | |
965 | |
966 bool needLock = false; | |
967 if (m_descriptor->select_program) needLock = true; | |
968 | |
969 if (needLock) { | |
970 if (!m_processLock.tryLock()) { | |
971 for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { | |
972 memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); | |
973 } | |
974 return; | |
975 } | |
976 } | |
977 | |
978 if (m_grouped) { | |
979 runGrouped(blockTime); | |
980 goto done; | |
981 } | |
982 | |
983 if (!m_descriptor || !m_descriptor->run_synth) { | |
984 m_eventBuffer.skip(m_eventBuffer.getReadSpace()); | |
985 m_haveLastEventSendTime = false; | |
986 if (m_descriptor->LADSPA_Plugin->run) { | |
987 m_descriptor->LADSPA_Plugin->run(m_instanceHandle, m_blockSize); | |
988 } else { | |
989 for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { | |
990 memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); | |
991 } | |
992 } | |
993 m_run = true; | |
994 if (needLock) m_processLock.unlock(); | |
995 return; | |
996 } | |
997 | |
998 #ifdef DEBUG_DSSI_PROCESS | |
999 std::cerr << "DSSIPluginInstance::run(" << blockTime << ")" << std::endl; | |
1000 #endif | |
1001 | |
1002 #ifdef DEBUG_DSSI_PROCESS | |
1003 if (m_eventBuffer.getReadSpace() > 0) { | |
1004 std::cerr << "DSSIPluginInstance::run: event buffer has " | |
1005 << m_eventBuffer.getReadSpace() << " event(s) in it" << std::endl; | |
1006 } | |
1007 #endif | |
1008 | |
1009 while (m_eventBuffer.getReadSpace() > 0) { | |
1010 | |
1011 snd_seq_event_t *ev = localEventBuffer + evCount; | |
1012 *ev = m_eventBuffer.peekOne(); | |
1013 bool accept = true; | |
1014 | |
1015 Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); | |
1016 | |
1017 int frameOffset = 0; | |
1018 if (evTime > blockTime) { | |
1019 frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); | |
1020 } | |
1021 | |
1022 #ifdef DEBUG_DSSI_PROCESS | |
1023 std::cerr << "DSSIPluginInstance::run: evTime " << evTime << ", blockTime " << blockTime << ", frameOffset " << frameOffset | |
1024 << ", blockSize " << m_blockSize << std::endl; | |
1025 std::cerr << "Type: " << int(ev->type) << ", pitch: " << int(ev->data.note.note) << ", velocity: " << int(ev->data.note.velocity) << std::endl; | |
1026 #endif | |
1027 | |
1028 if (frameOffset >= int(m_blockSize)) break; | |
1029 if (frameOffset < 0) { | |
1030 frameOffset = 0; | |
1031 if (ev->type == SND_SEQ_EVENT_NOTEON) { | |
1032 m_eventBuffer.skip(1); | |
1033 continue; | |
1034 } | |
1035 } | |
1036 | |
1037 ev->time.tick = frameOffset; | |
1038 m_eventBuffer.skip(1); | |
1039 | |
1040 if (ev->type == SND_SEQ_EVENT_CONTROLLER) { | |
1041 accept = handleController(ev); | |
1042 } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { | |
1043 m_pending.program = ev->data.control.value; | |
1044 accept = false; | |
1045 } | |
1046 | |
1047 if (accept) { | |
1048 if (++evCount >= EVENT_BUFFER_SIZE) break; | |
1049 } | |
1050 } | |
1051 | |
1052 if (m_pending.program >= 0 && m_descriptor->select_program) { | |
1053 | |
1054 int program = m_pending.program; | |
1055 int bank = m_pending.lsb + 128 * m_pending.msb; | |
1056 | |
1057 #ifdef DEBUG_DSSI | |
1058 std::cerr << "DSSIPluginInstance::run: making select_program(" << bank << "," << program << ") call" << std::endl; | |
1059 #endif | |
1060 | |
1061 m_pending.lsb = m_pending.msb = m_pending.program = -1; | |
1062 m_descriptor->select_program(m_instanceHandle, bank, program); | |
1063 | |
1064 #ifdef DEBUG_DSSI | |
1065 std::cerr << "DSSIPluginInstance::run: made select_program(" << bank << "," << program << ") call" << std::endl; | |
1066 #endif | |
1067 } | |
1068 | |
1069 #ifdef DEBUG_DSSI_PROCESS | |
1070 std::cerr << "DSSIPluginInstance::run: running with " << evCount << " events" | |
1071 << std::endl; | |
1072 #endif | |
1073 | |
1074 m_descriptor->run_synth(m_instanceHandle, m_blockSize, | |
1075 localEventBuffer, evCount); | |
1076 | |
1077 #ifdef DEBUG_DSSI_PROCESS | |
1078 // for (int i = 0; i < m_blockSize; ++i) { | |
1079 // std::cout << m_outputBuffers[0][i] << " "; | |
1080 // if (i % 8 == 0) std::cout << std::endl; | |
1081 // } | |
1082 #endif | |
1083 | |
1084 done: | |
1085 if (needLock) m_processLock.unlock(); | |
1086 | |
1087 if (m_audioPortsOut.size() == 0) { | |
1088 // copy inputs to outputs | |
1089 for (size_t ch = 0; ch < m_idealChannelCount; ++ch) { | |
1090 size_t sch = ch % m_audioPortsIn.size(); | |
1091 for (size_t i = 0; i < m_blockSize; ++i) { | |
1092 m_outputBuffers[ch][i] = m_inputBuffers[sch][i]; | |
1093 } | |
1094 } | |
1095 } else if (m_idealChannelCount < m_audioPortsOut.size()) { | |
1096 if (m_idealChannelCount == 1) { | |
1097 // mix down to mono | |
1098 for (size_t ch = 1; ch < m_audioPortsOut.size(); ++ch) { | |
1099 for (size_t i = 0; i < m_blockSize; ++i) { | |
1100 m_outputBuffers[0][i] += m_outputBuffers[ch][i]; | |
1101 } | |
1102 } | |
1103 } | |
1104 } else if (m_idealChannelCount > m_audioPortsOut.size()) { | |
1105 // duplicate | |
1106 for (size_t ch = m_audioPortsOut.size(); ch < m_idealChannelCount; ++ch) { | |
1107 size_t sch = (ch - m_audioPortsOut.size()) % m_audioPortsOut.size(); | |
1108 for (size_t i = 0; i < m_blockSize; ++i) { | |
1109 m_outputBuffers[ch][i] = m_outputBuffers[sch][i]; | |
1110 } | |
1111 } | |
1112 } | |
1113 | |
1114 m_lastRunTime = blockTime; | |
1115 m_run = true; | |
1116 } | |
1117 | |
1118 void | |
1119 DSSIPluginInstance::runGrouped(const Vamp::RealTime &blockTime) | |
1120 { | |
1121 // If something else in our group has just been called for this | |
1122 // block time (but we haven't) then we should just write out the | |
1123 // results and return; if we have just been called for this block | |
1124 // time or nothing else in the group has been, we should run the | |
1125 // whole group. | |
1126 | |
1127 bool needRun = true; | |
1128 | |
1129 PluginSet &s = m_groupMap[m_identifier]; | |
1130 | |
1131 #ifdef DEBUG_DSSI_PROCESS | |
1132 std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): this is " << this << "; " << s.size() << " elements in m_groupMap[" << m_identifier << "]" << std::endl; | |
1133 #endif | |
1134 | |
1135 if (m_lastRunTime != blockTime) { | |
1136 for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { | |
1137 DSSIPluginInstance *instance = *i; | |
1138 if (instance != this && instance->m_lastRunTime == blockTime) { | |
1139 #ifdef DEBUG_DSSI_PROCESS | |
1140 std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): plugin " << instance << " has already been run" << std::endl; | |
1141 #endif | |
1142 needRun = false; | |
1143 } | |
1144 } | |
1145 } | |
1146 | |
1147 if (!needRun) { | |
1148 #ifdef DEBUG_DSSI_PROCESS | |
1149 std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): already run, returning" << std::endl; | |
1150 #endif | |
1151 return; | |
1152 } | |
1153 | |
1154 #ifdef DEBUG_DSSI_PROCESS | |
1155 std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): I'm the first, running" << std::endl; | |
1156 #endif | |
1157 | |
1158 size_t index = 0; | |
1159 unsigned long *counts = (unsigned long *) | |
1160 alloca(m_groupLocalEventBufferCount * sizeof(unsigned long)); | |
1161 LADSPA_Handle *instances = (LADSPA_Handle *) | |
1162 alloca(m_groupLocalEventBufferCount * sizeof(LADSPA_Handle)); | |
1163 | |
1164 for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { | |
1165 | |
1166 if (index >= m_groupLocalEventBufferCount) break; | |
1167 | |
1168 DSSIPluginInstance *instance = *i; | |
1169 counts[index] = 0; | |
1170 instances[index] = instance->m_instanceHandle; | |
1171 | |
1172 #ifdef DEBUG_DSSI_PROCESS | |
1173 std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): running " << instance << std::endl; | |
1174 #endif | |
1175 | |
1176 if (instance->m_pending.program >= 0 && | |
1177 instance->m_descriptor->select_program) { | |
1178 int program = instance->m_pending.program; | |
1179 int bank = instance->m_pending.lsb + 128 * instance->m_pending.msb; | |
1180 instance->m_pending.lsb = instance->m_pending.msb = instance->m_pending.program = -1; | |
1181 instance->m_descriptor->select_program | |
1182 (instance->m_instanceHandle, bank, program); | |
1183 } | |
1184 | |
1185 while (instance->m_eventBuffer.getReadSpace() > 0) { | |
1186 | |
1187 snd_seq_event_t *ev = m_groupLocalEventBuffers[index] + counts[index]; | |
1188 *ev = instance->m_eventBuffer.peekOne(); | |
1189 bool accept = true; | |
1190 | |
1191 Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); | |
1192 | |
1193 int frameOffset = 0; | |
1194 if (evTime > blockTime) { | |
1195 frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); | |
1196 } | |
1197 | |
1198 #ifdef DEBUG_DSSI_PROCESS | |
1199 std::cerr << "DSSIPluginInstance::runGrouped: evTime " << evTime << ", frameOffset " << frameOffset | |
1200 << ", block size " << m_blockSize << std::endl; | |
1201 #endif | |
1202 | |
1203 if (frameOffset >= int(m_blockSize)) break; | |
1204 if (frameOffset < 0) frameOffset = 0; | |
1205 | |
1206 ev->time.tick = frameOffset; | |
1207 instance->m_eventBuffer.skip(1); | |
1208 | |
1209 if (ev->type == SND_SEQ_EVENT_CONTROLLER) { | |
1210 accept = instance->handleController(ev); | |
1211 } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { | |
1212 instance->m_pending.program = ev->data.control.value; | |
1213 accept = false; | |
1214 } | |
1215 | |
1216 if (accept) { | |
1217 if (++counts[index] >= EVENT_BUFFER_SIZE) break; | |
1218 } | |
1219 } | |
1220 | |
1221 ++index; | |
1222 } | |
1223 | |
1224 m_descriptor->run_multiple_synths(index, | |
1225 instances, | |
1226 m_blockSize, | |
1227 m_groupLocalEventBuffers, | |
1228 counts); | |
1229 } | |
1230 | |
1231 int | |
1232 DSSIPluginInstance::requestMidiSend(LADSPA_Handle /* instance */, | |
1233 unsigned char /* ports */, | |
1234 unsigned char /* channels */) | |
1235 { | |
1236 // This is called from a non-RT context (during instantiate) | |
1237 | |
1238 std::cerr << "DSSIPluginInstance::requestMidiSend" << std::endl; | |
1239 return 1; | |
1240 } | |
1241 | |
1242 void | |
1243 DSSIPluginInstance::midiSend(LADSPA_Handle /* instance */, | |
1244 snd_seq_event_t * /* events */, | |
1245 unsigned long /* eventCount */) | |
1246 { | |
1247 // This is likely to be called from an RT context | |
1248 | |
1249 std::cerr << "DSSIPluginInstance::midiSend" << std::endl; | |
1250 } | |
1251 | |
1252 void | |
1253 DSSIPluginInstance::NonRTPluginThread::run() | |
1254 { | |
1255 while (!m_exiting) { | |
1256 m_runFunction(m_handle); | |
1257 usleep(100000); | |
1258 } | |
1259 } | |
1260 | |
1261 int | |
1262 DSSIPluginInstance::requestNonRTThread(LADSPA_Handle instance, | |
1263 void (*runFunction)(LADSPA_Handle)) | |
1264 { | |
1265 NonRTPluginThread *thread = new NonRTPluginThread(instance, runFunction); | |
1266 m_threads[instance].insert(thread); | |
1267 thread->start(); | |
1268 return 0; | |
1269 } | |
1270 | |
1271 void | |
1272 DSSIPluginInstance::deactivate() | |
1273 { | |
1274 #ifdef DEBUG_DSSI | |
1275 std::cerr << "DSSIPluginInstance::deactivate " << m_identifier << std::endl; | |
1276 #endif | |
1277 if (!m_descriptor || !m_descriptor->LADSPA_Plugin->deactivate) return; | |
1278 | |
1279 for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { | |
1280 m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; | |
1281 } | |
1282 | |
1283 m_descriptor->LADSPA_Plugin->deactivate(m_instanceHandle); | |
1284 #ifdef DEBUG_DSSI | |
1285 std::cerr << "DSSIPluginInstance::deactivate " << m_identifier << " done" << std::endl; | |
1286 #endif | |
1287 | |
1288 m_bufferScavenger.scavenge(); | |
1289 } | |
1290 | |
1291 void | |
1292 DSSIPluginInstance::cleanup() | |
1293 { | |
1294 #ifdef DEBUG_DSSI | |
1295 std::cerr << "DSSIPluginInstance::cleanup " << m_identifier << std::endl; | |
1296 #endif | |
1297 if (!m_descriptor) return; | |
1298 | |
1299 if (!m_descriptor->LADSPA_Plugin->cleanup) { | |
1300 std::cerr << "Bad plugin: plugin id " | |
1301 << m_descriptor->LADSPA_Plugin->UniqueID | |
1302 << ":" << m_descriptor->LADSPA_Plugin->Label | |
1303 << " has no cleanup method!" << std::endl; | |
1304 return; | |
1305 } | |
1306 | |
1307 m_descriptor->LADSPA_Plugin->cleanup(m_instanceHandle); | |
1308 m_instanceHandle = 0; | |
1309 #ifdef DEBUG_DSSI | |
1310 std::cerr << "DSSIPluginInstance::cleanup " << m_identifier << " done" << std::endl; | |
1311 #endif | |
1312 } | |
1313 |