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