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