svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 00008 This program is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU General Public License as 00010 published by the Free Software Foundation; either version 2 of the 00011 License, or (at your option) any later version. See the file 00012 COPYING included with this distribution for more information. 00013 */ 00014 00015 /* 00016 This is a modified version of a source file from the 00017 Rosegarden MIDI and audio sequencer and notation editor. 00018 This file copyright 2000-2006 Chris Cannam. 00019 */ 00020 00021 #include <iostream> 00022 #include <cassert> 00023 00024 #include "DSSIPluginInstance.h" 00025 #include "PluginIdentifier.h" 00026 #include "LADSPAPluginFactory.h" 00027 00028 #include <cstdlib> 00029 00030 #ifndef Q_OS_WIN32 00031 #include <alloca.h> 00032 #else 00033 #include <memory.h> 00034 #endif 00035 00036 //#define DEBUG_DSSI 1 00037 #define DEBUG_DSSI_PROCESS 1 00038 00039 #define EVENT_BUFFER_SIZE 1023 00040 00041 #ifdef DEBUG_DSSI 00042 static std::ostream &operator<<(std::ostream& o, const QString &s) 00043 { 00044 o << s; 00045 return o; 00046 } 00047 #endif 00048 00049 DSSIPluginInstance::GroupMap DSSIPluginInstance::m_groupMap; 00050 snd_seq_event_t **DSSIPluginInstance::m_groupLocalEventBuffers = 0; 00051 size_t DSSIPluginInstance::m_groupLocalEventBufferCount = 0; 00052 Scavenger<ScavengerArrayWrapper<snd_seq_event_t *> > DSSIPluginInstance::m_bufferScavenger(2, 10); 00053 std::map<LADSPA_Handle, std::set<DSSIPluginInstance::NonRTPluginThread *> > DSSIPluginInstance::m_threads; 00054 00055 00056 DSSIPluginInstance::DSSIPluginInstance(RealTimePluginFactory *factory, 00057 int clientId, 00058 QString identifier, 00059 int position, 00060 unsigned long sampleRate, 00061 size_t blockSize, 00062 int idealChannelCount, 00063 const DSSI_Descriptor* descriptor) : 00064 RealTimePluginInstance(factory, identifier), 00065 m_client(clientId), 00066 m_position(position), 00067 m_instanceHandle(0), 00068 m_descriptor(descriptor), 00069 m_programCacheValid(false), 00070 m_eventBuffer(EVENT_BUFFER_SIZE), 00071 m_blockSize(blockSize), 00072 m_idealChannelCount(idealChannelCount), 00073 m_sampleRate(sampleRate), 00074 m_latencyPort(0), 00075 m_run(false), 00076 m_bypassed(false), 00077 m_grouped(false), 00078 m_haveLastEventSendTime(false) 00079 { 00080 #ifdef DEBUG_DSSI 00081 SVDEBUG << "DSSIPluginInstance::DSSIPluginInstance(" << identifier << ")" 00082 << endl; 00083 #endif 00084 00085 init(); 00086 00087 m_inputBuffers = new sample_t*[m_audioPortsIn.size()]; 00088 m_outputBuffers = new sample_t*[m_outputBufferCount]; 00089 00090 for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { 00091 m_inputBuffers[i] = new sample_t[blockSize]; 00092 } 00093 for (size_t i = 0; i < m_outputBufferCount; ++i) { 00094 m_outputBuffers[i] = new sample_t[blockSize]; 00095 } 00096 00097 m_ownBuffers = true; 00098 00099 m_pending.lsb = m_pending.msb = m_pending.program = -1; 00100 00101 instantiate(sampleRate); 00102 if (isOK()) { 00103 connectPorts(); 00104 activate(); 00105 initialiseGroupMembership(); 00106 } 00107 } 00108 00109 std::string 00110 DSSIPluginInstance::getIdentifier() const 00111 { 00112 return m_descriptor->LADSPA_Plugin->Label; 00113 } 00114 00115 std::string 00116 DSSIPluginInstance::getName() const 00117 { 00118 return m_descriptor->LADSPA_Plugin->Name; 00119 } 00120 00121 std::string 00122 DSSIPluginInstance::getDescription() const 00123 { 00124 return ""; 00125 } 00126 00127 std::string 00128 DSSIPluginInstance::getMaker() const 00129 { 00130 return m_descriptor->LADSPA_Plugin->Maker; 00131 } 00132 00133 int 00134 DSSIPluginInstance::getPluginVersion() const 00135 { 00136 return -1; 00137 } 00138 00139 std::string 00140 DSSIPluginInstance::getCopyright() const 00141 { 00142 return m_descriptor->LADSPA_Plugin->Copyright; 00143 } 00144 00145 DSSIPluginInstance::ParameterList 00146 DSSIPluginInstance::getParameterDescriptors() const 00147 { 00148 ParameterList list; 00149 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); 00150 if (!f) return list; 00151 00152 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { 00153 00154 ParameterDescriptor pd; 00155 unsigned int pn = m_controlPortsIn[i].first; 00156 00157 pd.identifier = m_descriptor->LADSPA_Plugin->PortNames[pn]; 00158 pd.name = pd.identifier; 00159 pd.description = ""; 00160 pd.minValue = f->getPortMinimum(m_descriptor->LADSPA_Plugin, pn); 00161 pd.maxValue = f->getPortMaximum(m_descriptor->LADSPA_Plugin, pn); 00162 pd.defaultValue = f->getPortDefault(m_descriptor->LADSPA_Plugin, pn); 00163 00164 float q = f->getPortQuantization(m_descriptor->LADSPA_Plugin, pn); 00165 if (q == 0.0) { 00166 pd.isQuantized = false; 00167 } else { 00168 pd.isQuantized = true; 00169 pd.quantizeStep = q; 00170 } 00171 00172 list.push_back(pd); 00173 } 00174 00175 return list; 00176 } 00177 00178 float 00179 DSSIPluginInstance::getParameter(std::string id) const 00180 { 00181 #ifdef DEBUG_DSSI 00182 SVDEBUG << "DSSIPluginInstance::getParameter(" << id << ")" << endl; 00183 #endif 00184 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { 00185 if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) { 00186 #ifdef DEBUG_DSSI 00187 cerr << "Matches port " << i << endl; 00188 #endif 00189 float v = getParameterValue(i); 00190 #ifdef DEBUG_DSSI 00191 SVDEBUG << "Returning " << v << endl; 00192 #endif 00193 return v; 00194 } 00195 } 00196 00197 return 0.0; 00198 } 00199 00200 void 00201 DSSIPluginInstance::setParameter(std::string id, float value) 00202 { 00203 #ifdef DEBUG_DSSI 00204 SVDEBUG << "DSSIPluginInstance::setParameter(" << id << ", " << value << ")" << endl; 00205 #endif 00206 00207 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { 00208 if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) { 00209 setParameterValue(i, value); 00210 break; 00211 } 00212 } 00213 } 00214 00215 void 00216 DSSIPluginInstance::init() 00217 { 00218 #ifdef DEBUG_DSSI 00219 SVDEBUG << "DSSIPluginInstance::init" << endl; 00220 #endif 00221 00222 // Discover ports numbers and identities 00223 // 00224 const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; 00225 00226 for (unsigned long i = 0; i < descriptor->PortCount; ++i) 00227 { 00228 if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[i])) 00229 { 00230 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { 00231 m_audioPortsIn.push_back(i); 00232 } else { 00233 m_audioPortsOut.push_back(i); 00234 } 00235 } 00236 else 00237 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) 00238 { 00239 if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { 00240 00241 LADSPA_Data *data = new LADSPA_Data(0.0); 00242 00243 m_controlPortsIn.push_back(std::pair<unsigned long, LADSPA_Data*> 00244 (i, data)); 00245 00246 m_backupControlPortsIn.push_back(0.0); 00247 00248 } else { 00249 LADSPA_Data *data = new LADSPA_Data(0.0); 00250 m_controlPortsOut.push_back( 00251 std::pair<unsigned long, LADSPA_Data*>(i, data)); 00252 if (!strcmp(descriptor->PortNames[i], "latency") || 00253 !strcmp(descriptor->PortNames[i], "_latency")) { 00254 #ifdef DEBUG_DSSI 00255 cerr << "Wooo! We have a latency port!" << endl; 00256 #endif 00257 m_latencyPort = data; 00258 } 00259 } 00260 } 00261 #ifdef DEBUG_DSSI 00262 else 00263 SVDEBUG << "DSSIPluginInstance::DSSIPluginInstance - " 00264 << "unrecognised port type" << endl; 00265 #endif 00266 } 00267 00268 m_outputBufferCount = std::max(m_idealChannelCount, m_audioPortsOut.size()); 00269 } 00270 00271 size_t 00272 DSSIPluginInstance::getLatency() 00273 { 00274 size_t latency = 0; 00275 00276 #ifdef DEBUG_DSSI_PROCESS 00277 SVDEBUG << "DSSIPluginInstance::getLatency(): m_latencyPort " << m_latencyPort << ", m_run " << m_run << endl; 00278 #endif 00279 00280 if (m_latencyPort) { 00281 if (!m_run) { 00282 for (size_t i = 0; i < getAudioInputCount(); ++i) { 00283 for (size_t j = 0; j < m_blockSize; ++j) { 00284 m_inputBuffers[i][j] = 0.f; 00285 } 00286 } 00287 run(Vamp::RealTime::zeroTime); 00288 } 00289 latency = (size_t)(*m_latencyPort + 0.1); 00290 } 00291 00292 #ifdef DEBUG_DSSI_PROCESS 00293 SVDEBUG << "DSSIPluginInstance::getLatency(): latency is " << latency << endl; 00294 #endif 00295 00296 return latency; 00297 } 00298 00299 void 00300 DSSIPluginInstance::silence() 00301 { 00302 if (m_instanceHandle != 0) { 00303 deactivate(); 00304 activate(); 00305 } 00306 } 00307 00308 void 00309 DSSIPluginInstance::discardEvents() 00310 { 00311 m_eventBuffer.reset(); 00312 } 00313 00314 void 00315 DSSIPluginInstance::setIdealChannelCount(size_t channels) 00316 { 00317 #ifdef DEBUG_DSSI 00318 SVDEBUG << "DSSIPluginInstance::setIdealChannelCount: channel count " 00319 << channels << " (was " << m_idealChannelCount << ")" << endl; 00320 #endif 00321 00322 if (channels == m_idealChannelCount) { 00323 silence(); 00324 return; 00325 } 00326 00327 if (m_instanceHandle != 0) { 00328 deactivate(); 00329 } 00330 00331 m_idealChannelCount = channels; 00332 00333 if (channels > m_outputBufferCount) { 00334 00335 for (size_t i = 0; i < m_outputBufferCount; ++i) { 00336 delete[] m_outputBuffers[i]; 00337 } 00338 00339 delete[] m_outputBuffers; 00340 00341 m_outputBufferCount = channels; 00342 00343 m_outputBuffers = new sample_t*[m_outputBufferCount]; 00344 00345 for (size_t i = 0; i < m_outputBufferCount; ++i) { 00346 m_outputBuffers[i] = new sample_t[m_blockSize]; 00347 } 00348 00349 connectPorts(); 00350 } 00351 00352 if (m_instanceHandle != 0) { 00353 activate(); 00354 } 00355 } 00356 00357 void 00358 DSSIPluginInstance::detachFromGroup() 00359 { 00360 if (!m_grouped) return; 00361 m_groupMap[m_identifier].erase(this); 00362 m_grouped = false; 00363 } 00364 00365 void 00366 DSSIPluginInstance::initialiseGroupMembership() 00367 { 00368 if (!m_descriptor->run_multiple_synths) { 00369 m_grouped = false; 00370 return; 00371 } 00372 00374 00375 size_t pluginsInGroup = m_groupMap[m_identifier].size(); 00376 00377 if (++pluginsInGroup > m_groupLocalEventBufferCount) { 00378 00379 size_t nextBufferCount = pluginsInGroup * 2; 00380 00381 snd_seq_event_t **eventLocalBuffers = new snd_seq_event_t *[nextBufferCount]; 00382 00383 for (size_t i = 0; i < m_groupLocalEventBufferCount; ++i) { 00384 eventLocalBuffers[i] = m_groupLocalEventBuffers[i]; 00385 } 00386 for (size_t i = m_groupLocalEventBufferCount; i < nextBufferCount; ++i) { 00387 eventLocalBuffers[i] = new snd_seq_event_t[EVENT_BUFFER_SIZE]; 00388 } 00389 00390 if (m_groupLocalEventBuffers) { 00391 m_bufferScavenger.claim(new ScavengerArrayWrapper<snd_seq_event_t *> 00392 (m_groupLocalEventBuffers)); 00393 } 00394 00395 m_groupLocalEventBuffers = eventLocalBuffers; 00396 m_groupLocalEventBufferCount = nextBufferCount; 00397 } 00398 00399 m_grouped = true; 00400 m_groupMap[m_identifier].insert(this); 00401 } 00402 00403 DSSIPluginInstance::~DSSIPluginInstance() 00404 { 00405 #ifdef DEBUG_DSSI 00406 SVDEBUG << "DSSIPluginInstance::~DSSIPluginInstance" << endl; 00407 #endif 00408 00409 if (m_threads.find(m_instanceHandle) != m_threads.end()) { 00410 00411 for (std::set<NonRTPluginThread *>::iterator i = 00412 m_threads[m_instanceHandle].begin(); 00413 i != m_threads[m_instanceHandle].end(); ++i) { 00414 00415 (*i)->setExiting(); 00416 (*i)->wait(); 00417 delete *i; 00418 } 00419 00420 m_threads.erase(m_instanceHandle); 00421 } 00422 00423 detachFromGroup(); 00424 00425 if (m_instanceHandle != 0) { 00426 deactivate(); 00427 } 00428 00429 cleanup(); 00430 00431 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) 00432 delete m_controlPortsIn[i].second; 00433 00434 for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) 00435 delete m_controlPortsOut[i].second; 00436 00437 m_controlPortsIn.clear(); 00438 m_controlPortsOut.clear(); 00439 00440 if (m_ownBuffers) { 00441 for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { 00442 delete[] m_inputBuffers[i]; 00443 } 00444 for (size_t i = 0; i < m_outputBufferCount; ++i) { 00445 delete[] m_outputBuffers[i]; 00446 } 00447 00448 delete[] m_inputBuffers; 00449 delete[] m_outputBuffers; 00450 } 00451 00452 m_audioPortsIn.clear(); 00453 m_audioPortsOut.clear(); 00454 } 00455 00456 00457 void 00458 DSSIPluginInstance::instantiate(unsigned long sampleRate) 00459 { 00460 if (!m_descriptor) return; 00461 00462 #ifdef DEBUG_DSSI 00463 cout << "DSSIPluginInstance::instantiate - plugin \"unique\" id = " 00464 << m_descriptor->LADSPA_Plugin->UniqueID << endl; 00465 #endif 00466 const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; 00467 00468 if (!descriptor->instantiate) { 00469 cerr << "Bad plugin: plugin id " << descriptor->UniqueID 00470 << ":" << descriptor->Label 00471 << " has no instantiate method!" << endl; 00472 return; 00473 } 00474 00475 m_instanceHandle = descriptor->instantiate(descriptor, sampleRate); 00476 00477 if (m_instanceHandle) { 00478 00479 if (m_descriptor->get_midi_controller_for_port) { 00480 00481 for (unsigned long i = 0; i < descriptor->PortCount; ++i) { 00482 00483 if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i]) && 00484 LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { 00485 00486 int controller = m_descriptor->get_midi_controller_for_port 00487 (m_instanceHandle, i); 00488 00489 if (controller != 0 && controller != 32 && 00490 DSSI_IS_CC(controller)) { 00491 00492 m_controllerMap[DSSI_CC_NUMBER(controller)] = i; 00493 } 00494 } 00495 } 00496 } 00497 } 00498 } 00499 00500 void 00501 DSSIPluginInstance::checkProgramCache() const 00502 { 00503 if (m_programCacheValid) return; 00504 m_cachedPrograms.clear(); 00505 00506 #ifdef DEBUG_DSSI 00507 SVDEBUG << "DSSIPluginInstance::checkProgramCache" << endl; 00508 #endif 00509 00510 if (!m_descriptor || !m_descriptor->get_program) { 00511 m_programCacheValid = true; 00512 return; 00513 } 00514 00515 unsigned long index = 0; 00516 const DSSI_Program_Descriptor *programDescriptor; 00517 while ((programDescriptor = m_descriptor->get_program(m_instanceHandle, index))) { 00518 ++index; 00519 ProgramDescriptor d; 00520 d.bank = programDescriptor->Bank; 00521 d.program = programDescriptor->Program; 00522 d.name = programDescriptor->Name; 00523 m_cachedPrograms.push_back(d); 00524 } 00525 00526 #ifdef DEBUG_DSSI 00527 SVDEBUG << "DSSIPluginInstance::checkProgramCache: have " << m_cachedPrograms.size() << " programs" << endl; 00528 #endif 00529 00530 m_programCacheValid = true; 00531 } 00532 00533 DSSIPluginInstance::ProgramList 00534 DSSIPluginInstance::getPrograms() const 00535 { 00536 #ifdef DEBUG_DSSI 00537 SVDEBUG << "DSSIPluginInstance::getPrograms" << endl; 00538 #endif 00539 00540 if (!m_descriptor) return ProgramList(); 00541 00542 checkProgramCache(); 00543 00544 ProgramList programs; 00545 00546 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); 00547 i != m_cachedPrograms.end(); ++i) { 00548 programs.push_back(i->name); 00549 } 00550 00551 return programs; 00552 } 00553 00554 std::string 00555 DSSIPluginInstance::getProgram(int bank, int program) const 00556 { 00557 #ifdef DEBUG_DSSI 00558 SVDEBUG << "DSSIPluginInstance::getProgram(" << bank << "," << program << ")" << endl; 00559 #endif 00560 00561 if (!m_descriptor) return std::string(); 00562 00563 checkProgramCache(); 00564 00565 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); 00566 i != m_cachedPrograms.end(); ++i) { 00567 if (i->bank == bank && i->program == program) return i->name; 00568 } 00569 00570 return std::string(); 00571 } 00572 00573 unsigned long 00574 DSSIPluginInstance::getProgram(std::string name) const 00575 { 00576 #ifdef DEBUG_DSSI 00577 SVDEBUG << "DSSIPluginInstance::getProgram(" << name << ")" << endl; 00578 #endif 00579 00580 if (!m_descriptor) return 0; 00581 00582 checkProgramCache(); 00583 00584 unsigned long rv; 00585 00586 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); 00587 i != m_cachedPrograms.end(); ++i) { 00588 if (i->name == name) { 00589 rv = i->bank; 00590 rv = (rv << 16) + i->program; 00591 return rv; 00592 } 00593 } 00594 00595 return 0; 00596 } 00597 00598 std::string 00599 DSSIPluginInstance::getCurrentProgram() const 00600 { 00601 return m_program; 00602 } 00603 00604 void 00605 DSSIPluginInstance::selectProgram(std::string program) 00606 { 00607 selectProgramAux(program, true); 00608 } 00609 00610 void 00611 DSSIPluginInstance::selectProgramAux(std::string program, bool backupPortValues) 00612 { 00613 #ifdef DEBUG_DSSI 00614 SVDEBUG << "DSSIPluginInstance::selectProgram(" << program << ")" << endl; 00615 #endif 00616 00617 if (!m_descriptor) return; 00618 00619 checkProgramCache(); 00620 00621 if (!m_descriptor->select_program) return; 00622 00623 bool found = false; 00624 unsigned long bankNo = 0, programNo = 0; 00625 00626 for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); 00627 i != m_cachedPrograms.end(); ++i) { 00628 00629 if (i->name == program) { 00630 00631 bankNo = i->bank; 00632 programNo = i->program; 00633 found = true; 00634 00635 #ifdef DEBUG_DSSI 00636 SVDEBUG << "DSSIPluginInstance::selectProgram(" << program << "): found at bank " << bankNo << ", program " << programNo << endl; 00637 #endif 00638 00639 break; 00640 } 00641 } 00642 00643 if (!found) return; 00644 m_program = program; 00645 00646 // DSSI select_program is an audio context call 00647 m_processLock.lock(); 00648 m_descriptor->select_program(m_instanceHandle, bankNo, programNo); 00649 m_processLock.unlock(); 00650 00651 #ifdef DEBUG_DSSI 00652 SVDEBUG << "DSSIPluginInstance::selectProgram(" << program << "): made select_program(" << bankNo << "," << programNo << ") call" << endl; 00653 #endif 00654 00655 if (backupPortValues) { 00656 for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { 00657 m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; 00658 } 00659 } 00660 } 00661 00662 void 00663 DSSIPluginInstance::activate() 00664 { 00665 #ifdef DEBUG_DSSI 00666 SVDEBUG << "DSSIPluginInstance::activate" << endl; 00667 #endif 00668 00669 if (!m_descriptor || !m_descriptor->LADSPA_Plugin->activate) return; 00670 m_descriptor->LADSPA_Plugin->activate(m_instanceHandle); 00671 00672 if (m_program != "") { 00673 #ifdef DEBUG_DSSI 00674 SVDEBUG << "DSSIPluginInstance::activate: restoring program " << m_program << endl; 00675 #endif 00676 selectProgramAux(m_program, false); 00677 } 00678 00679 for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { 00680 #ifdef DEBUG_DSSI 00681 SVDEBUG << "DSSIPluginInstance::activate: setting port " << m_controlPortsIn[i].first << " to " << m_backupControlPortsIn[i] << endl; 00682 #endif 00683 *m_controlPortsIn[i].second = m_backupControlPortsIn[i]; 00684 } 00685 } 00686 00687 void 00688 DSSIPluginInstance::connectPorts() 00689 { 00690 if (!m_descriptor || !m_descriptor->LADSPA_Plugin->connect_port) return; 00691 #ifdef DEBUG_DSSI 00692 SVDEBUG << "DSSIPluginInstance::connectPorts: " << m_audioPortsIn.size() 00693 << " audio ports in, " << m_audioPortsOut.size() << " out, " 00694 << m_outputBufferCount << " output buffers" << endl; 00695 #endif 00696 00697 assert(sizeof(LADSPA_Data) == sizeof(float)); 00698 assert(sizeof(sample_t) == sizeof(float)); 00699 00700 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); 00701 int inbuf = 0, outbuf = 0; 00702 00703 for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) { 00704 m_descriptor->LADSPA_Plugin->connect_port 00705 (m_instanceHandle, 00706 m_audioPortsIn[i], 00707 (LADSPA_Data *)m_inputBuffers[inbuf]); 00708 ++inbuf; 00709 } 00710 00711 for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) { 00712 m_descriptor->LADSPA_Plugin->connect_port 00713 (m_instanceHandle, 00714 m_audioPortsOut[i], 00715 (LADSPA_Data *)m_outputBuffers[outbuf]); 00716 ++outbuf; 00717 } 00718 00719 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { 00720 m_descriptor->LADSPA_Plugin->connect_port 00721 (m_instanceHandle, 00722 m_controlPortsIn[i].first, 00723 m_controlPortsIn[i].second); 00724 00725 if (f) { 00726 float defaultValue = f->getPortDefault 00727 (m_descriptor->LADSPA_Plugin, m_controlPortsIn[i].first); 00728 *m_controlPortsIn[i].second = defaultValue; 00729 m_backupControlPortsIn[i] = defaultValue; 00730 #ifdef DEBUG_DSSI 00731 SVDEBUG << "DSSIPluginInstance::connectPorts: set control port " << i << " to default value " << defaultValue << endl; 00732 #endif 00733 } 00734 } 00735 00736 for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) { 00737 m_descriptor->LADSPA_Plugin->connect_port 00738 (m_instanceHandle, 00739 m_controlPortsOut[i].first, 00740 m_controlPortsOut[i].second); 00741 } 00742 } 00743 00744 unsigned int 00745 DSSIPluginInstance::getParameterCount() const 00746 { 00747 return m_controlPortsIn.size(); 00748 } 00749 00750 void 00751 DSSIPluginInstance::setParameterValue(unsigned int parameter, float value) 00752 { 00753 #ifdef DEBUG_DSSI 00754 SVDEBUG << "DSSIPluginInstance::setParameterValue(" << parameter << ") to " << value << endl; 00755 #endif 00756 if (parameter >= m_controlPortsIn.size()) return; 00757 00758 unsigned int portNumber = m_controlPortsIn[parameter].first; 00759 00760 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); 00761 if (f) { 00762 if (value < f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber)) { 00763 value = f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber); 00764 } 00765 if (value > f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber)) { 00766 value = f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber); 00767 } 00768 } 00769 00770 (*m_controlPortsIn[parameter].second) = value; 00771 m_backupControlPortsIn[parameter] = value; 00772 } 00773 00774 void 00775 DSSIPluginInstance::setPortValueFromController(unsigned int port, int cv) 00776 { 00777 #ifdef DEBUG_DSSI 00778 SVDEBUG << "DSSIPluginInstance::setPortValueFromController(" << port << ") to " << cv << endl; 00779 #endif 00780 00781 const LADSPA_Descriptor *p = m_descriptor->LADSPA_Plugin; 00782 LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor; 00783 LADSPA_Data lb = p->PortRangeHints[port].LowerBound; 00784 LADSPA_Data ub = p->PortRangeHints[port].UpperBound; 00785 00786 float value = (float)cv; 00787 00788 if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) { 00789 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { 00790 /* unbounded: might as well leave the value alone. */ 00791 } else { 00792 /* bounded above only. just shift the range. */ 00793 value = ub - 127.0f + value; 00794 } 00795 } else { 00796 if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { 00797 /* bounded below only. just shift the range. */ 00798 value = lb + value; 00799 } else { 00800 /* bounded both ends. more interesting. */ 00801 /* XXX !!! todo: fill in logarithmic, sample rate &c */ 00802 value = lb + ((ub - lb) * value / 127.0f); 00803 } 00804 } 00805 00806 for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { 00807 if (m_controlPortsIn[i].first == port) { 00808 setParameterValue(i, value); 00809 } 00810 } 00811 } 00812 00813 float 00814 DSSIPluginInstance::getControlOutputValue(size_t output) const 00815 { 00816 if (output > m_controlPortsOut.size()) return 0.0; 00817 return (*m_controlPortsOut[output].second); 00818 } 00819 00820 float 00821 DSSIPluginInstance::getParameterValue(unsigned int parameter) const 00822 { 00823 #ifdef DEBUG_DSSI 00824 SVDEBUG << "DSSIPluginInstance::getParameterValue(" << parameter << ")" << endl; 00825 #endif 00826 if (parameter >= m_controlPortsIn.size()) return 0.0; 00827 return (*m_controlPortsIn[parameter].second); 00828 } 00829 00830 float 00831 DSSIPluginInstance::getParameterDefault(unsigned int parameter) const 00832 { 00833 if (parameter >= m_controlPortsIn.size()) return 0.0; 00834 00835 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); 00836 if (f) { 00837 return f->getPortDefault(m_descriptor->LADSPA_Plugin, 00838 m_controlPortsIn[parameter].first); 00839 } else { 00840 return 0.0f; 00841 } 00842 } 00843 00844 int 00845 DSSIPluginInstance::getParameterDisplayHint(unsigned int parameter) const 00846 { 00847 if (parameter >= m_controlPortsIn.size()) return 0.0; 00848 00849 LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); 00850 if (f) { 00851 return f->getPortDisplayHint(m_descriptor->LADSPA_Plugin, 00852 m_controlPortsIn[parameter].first); 00853 } else { 00854 return PortHint::NoHint; 00855 } 00856 } 00857 00858 std::string 00859 DSSIPluginInstance::configure(std::string key, 00860 std::string value) 00861 { 00862 if (!m_descriptor || !m_descriptor->configure) return std::string(); 00863 00864 if (key == PluginIdentifier::RESERVED_PROJECT_DIRECTORY_KEY.toStdString()) { 00865 #ifdef DSSI_PROJECT_DIRECTORY_KEY 00866 key = DSSI_PROJECT_DIRECTORY_KEY; 00867 #else 00868 return std::string(); 00869 #endif 00870 } 00871 00872 00873 #ifdef DEBUG_DSSI 00874 SVDEBUG << "DSSIPluginInstance::configure(" << key << "," << value << ")" << endl; 00875 #endif 00876 00877 char *message = m_descriptor->configure(m_instanceHandle, 00878 key.c_str(), 00879 value.c_str()); 00880 00881 m_programCacheValid = false; 00882 00883 m_configurationData[key] = value; 00884 00885 std::string qm; 00886 00887 // Ignore return values from reserved key configuration calls such 00888 // as project directory 00889 #ifdef DSSI_RESERVED_CONFIGURE_PREFIX 00890 if (QString(key.c_str()).startsWith(DSSI_RESERVED_CONFIGURE_PREFIX)) { 00891 return qm; 00892 } 00893 #endif 00894 00895 if (message) { 00896 if (m_descriptor->LADSPA_Plugin && m_descriptor->LADSPA_Plugin->Label) { 00897 qm = std::string(m_descriptor->LADSPA_Plugin->Label) + ": "; 00898 } 00899 qm = qm + message; 00900 free(message); 00901 00902 cerr << "DSSIPluginInstance::configure: warning: configure returned message: \"" << qm << "\"" << endl; 00903 } 00904 00905 return qm; 00906 } 00907 00908 void 00909 DSSIPluginInstance::sendEvent(const Vamp::RealTime &eventTime, 00910 const void *e) 00911 { 00912 #ifdef DEBUG_DSSI_PROCESS 00913 SVDEBUG << "DSSIPluginInstance::sendEvent: last was " << m_lastEventSendTime << " (valid " << m_haveLastEventSendTime << "), this is " << eventTime << endl; 00914 #endif 00915 00916 // The process mechanism only works correctly if the events are 00917 // sorted. It's the responsibility of the caller to ensure that: 00918 // we will happily drop events here if we find the timeline going 00919 // backwards. 00920 if (m_haveLastEventSendTime && 00921 m_lastEventSendTime > eventTime) { 00922 #ifdef DEBUG_DSSI_PROCESS 00923 cerr << "... clearing down" << endl; 00924 #endif 00925 m_haveLastEventSendTime = false; 00926 clearEvents(); 00927 } 00928 00929 snd_seq_event_t *event = (snd_seq_event_t *)e; 00930 #ifdef DEBUG_DSSI_PROCESS 00931 SVDEBUG << "DSSIPluginInstance::sendEvent at " << eventTime << endl; 00932 #endif 00933 snd_seq_event_t ev(*event); 00934 00935 ev.time.time.tv_sec = eventTime.sec; 00936 ev.time.time.tv_nsec = eventTime.nsec; 00937 00938 // DSSI doesn't use MIDI channels, it uses run_multiple_synths instead. 00939 ev.data.note.channel = 0; 00940 00941 m_eventBuffer.write(&ev, 1); 00942 00943 m_lastEventSendTime = eventTime; 00944 m_haveLastEventSendTime = true; 00945 } 00946 00947 void 00948 DSSIPluginInstance::clearEvents() 00949 { 00950 m_haveLastEventSendTime = false; 00951 m_eventBuffer.reset(); 00952 } 00953 00954 bool 00955 DSSIPluginInstance::handleController(snd_seq_event_t *ev) 00956 { 00957 int controller = ev->data.control.param; 00958 00959 #ifdef DEBUG_DSSI_PROCESS 00960 SVDEBUG << "DSSIPluginInstance::handleController " << controller << endl; 00961 #endif 00962 00963 if (controller == 0) { // bank select MSB 00964 00965 m_pending.msb = ev->data.control.value; 00966 00967 } else if (controller == 32) { // bank select LSB 00968 00969 m_pending.lsb = ev->data.control.value; 00970 00971 } else if (controller > 0 && controller < 128) { 00972 00973 if (m_controllerMap.find(controller) != m_controllerMap.end()) { 00974 int port = m_controllerMap[controller]; 00975 setPortValueFromController(port, ev->data.control.value); 00976 } else { 00977 return true; // pass through to plugin 00978 } 00979 } 00980 00981 return false; 00982 } 00983 00984 void 00985 DSSIPluginInstance::run(const Vamp::RealTime &blockTime, size_t count) 00986 { 00987 static snd_seq_event_t localEventBuffer[EVENT_BUFFER_SIZE]; 00988 int evCount = 0; 00989 00990 if (count == 0) count = m_blockSize; 00991 00992 bool needLock = false; 00993 if (m_descriptor && m_descriptor->select_program) needLock = true; 00994 00995 if (needLock) { 00996 if (!m_processLock.tryLock()) { 00997 for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { 00998 memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); 00999 } 01000 return; 01001 } 01002 } 01003 01004 if (m_grouped) { 01005 runGrouped(blockTime); 01006 goto done; 01007 } 01008 01009 if (!m_descriptor || !m_descriptor->run_synth) { 01010 m_eventBuffer.skip(m_eventBuffer.getReadSpace()); 01011 m_haveLastEventSendTime = false; 01012 if (m_descriptor && m_descriptor->LADSPA_Plugin->run) { 01013 m_descriptor->LADSPA_Plugin->run(m_instanceHandle, count); 01014 } else { 01015 for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { 01016 memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); 01017 } 01018 } 01019 m_run = true; 01020 if (needLock) m_processLock.unlock(); 01021 return; 01022 } 01023 01024 #ifdef DEBUG_DSSI_PROCESS 01025 SVDEBUG << "DSSIPluginInstance::run(" << blockTime << ")" << endl; 01026 #endif 01027 01028 #ifdef DEBUG_DSSI_PROCESS 01029 if (m_eventBuffer.getReadSpace() > 0) { 01030 SVDEBUG << "DSSIPluginInstance::run: event buffer has " 01031 << m_eventBuffer.getReadSpace() << " event(s) in it" << endl; 01032 } 01033 #endif 01034 01035 while (m_eventBuffer.getReadSpace() > 0) { 01036 01037 snd_seq_event_t *ev = localEventBuffer + evCount; 01038 *ev = m_eventBuffer.peekOne(); 01039 bool accept = true; 01040 01041 Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); 01042 01043 int frameOffset = 0; 01044 if (evTime > blockTime) { 01045 frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); 01046 } 01047 01048 #ifdef DEBUG_DSSI_PROCESS 01049 SVDEBUG << "DSSIPluginInstance::run: evTime " << evTime << ", blockTime " << blockTime << ", frameOffset " << frameOffset 01050 << ", blockSize " << m_blockSize << endl; 01051 cerr << "Type: " << int(ev->type) << ", pitch: " << int(ev->data.note.note) << ", velocity: " << int(ev->data.note.velocity) << endl; 01052 #endif 01053 01054 if (frameOffset >= int(count)) break; 01055 if (frameOffset < 0) { 01056 frameOffset = 0; 01057 if (ev->type == SND_SEQ_EVENT_NOTEON) { 01058 m_eventBuffer.skip(1); 01059 continue; 01060 } 01061 } 01062 01063 ev->time.tick = frameOffset; 01064 m_eventBuffer.skip(1); 01065 01066 if (ev->type == SND_SEQ_EVENT_CONTROLLER) { 01067 accept = handleController(ev); 01068 } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { 01069 m_pending.program = ev->data.control.value; 01070 accept = false; 01071 } 01072 01073 if (accept) { 01074 if (++evCount >= EVENT_BUFFER_SIZE) break; 01075 } 01076 } 01077 01078 if (m_pending.program >= 0 && m_descriptor->select_program) { 01079 01080 int program = m_pending.program; 01081 int bank = m_pending.lsb + 128 * m_pending.msb; 01082 01083 #ifdef DEBUG_DSSI 01084 SVDEBUG << "DSSIPluginInstance::run: making select_program(" << bank << "," << program << ") call" << endl; 01085 #endif 01086 01087 m_pending.lsb = m_pending.msb = m_pending.program = -1; 01088 m_descriptor->select_program(m_instanceHandle, bank, program); 01089 01090 #ifdef DEBUG_DSSI 01091 SVDEBUG << "DSSIPluginInstance::run: made select_program(" << bank << "," << program << ") call" << endl; 01092 #endif 01093 } 01094 01095 #ifdef DEBUG_DSSI_PROCESS 01096 SVDEBUG << "DSSIPluginInstance::run: running with " << evCount << " events" 01097 << endl; 01098 #endif 01099 01100 m_descriptor->run_synth(m_instanceHandle, count, 01101 localEventBuffer, evCount); 01102 01103 #ifdef DEBUG_DSSI_PROCESS 01104 // for (int i = 0; i < count; ++i) { 01105 // cout << m_outputBuffers[0][i] << " "; 01106 // if (i % 8 == 0) cout << endl; 01107 // } 01108 #endif 01109 01110 done: 01111 if (needLock) m_processLock.unlock(); 01112 01113 if (m_audioPortsOut.size() == 0) { 01114 // copy inputs to outputs 01115 for (size_t ch = 0; ch < m_idealChannelCount; ++ch) { 01116 size_t sch = ch % m_audioPortsIn.size(); 01117 for (size_t i = 0; i < m_blockSize; ++i) { 01118 m_outputBuffers[ch][i] = m_inputBuffers[sch][i]; 01119 } 01120 } 01121 } else if (m_idealChannelCount < m_audioPortsOut.size()) { 01122 if (m_idealChannelCount == 1) { 01123 // mix down to mono 01124 for (size_t ch = 1; ch < m_audioPortsOut.size(); ++ch) { 01125 for (size_t i = 0; i < m_blockSize; ++i) { 01126 m_outputBuffers[0][i] += m_outputBuffers[ch][i]; 01127 } 01128 } 01129 } 01130 } else if (m_idealChannelCount > m_audioPortsOut.size()) { 01131 // duplicate 01132 for (size_t ch = m_audioPortsOut.size(); ch < m_idealChannelCount; ++ch) { 01133 size_t sch = (ch - m_audioPortsOut.size()) % m_audioPortsOut.size(); 01134 for (size_t i = 0; i < m_blockSize; ++i) { 01135 m_outputBuffers[ch][i] = m_outputBuffers[sch][i]; 01136 } 01137 } 01138 } 01139 01140 m_lastRunTime = blockTime; 01141 m_run = true; 01142 } 01143 01144 void 01145 DSSIPluginInstance::runGrouped(const Vamp::RealTime &blockTime) 01146 { 01147 // If something else in our group has just been called for this 01148 // block time (but we haven't) then we should just write out the 01149 // results and return; if we have just been called for this block 01150 // time or nothing else in the group has been, we should run the 01151 // whole group. 01152 01153 bool needRun = true; 01154 01155 PluginSet &s = m_groupMap[m_identifier]; 01156 01157 #ifdef DEBUG_DSSI_PROCESS 01158 SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): this is " << this << "; " << s.size() << " elements in m_groupMap[" << m_identifier << "]" << endl; 01159 #endif 01160 01161 if (m_lastRunTime != blockTime) { 01162 for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { 01163 DSSIPluginInstance *instance = *i; 01164 if (instance != this && instance->m_lastRunTime == blockTime) { 01165 #ifdef DEBUG_DSSI_PROCESS 01166 SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): plugin " << instance << " has already been run" << endl; 01167 #endif 01168 needRun = false; 01169 } 01170 } 01171 } 01172 01173 if (!needRun) { 01174 #ifdef DEBUG_DSSI_PROCESS 01175 SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): already run, returning" << endl; 01176 #endif 01177 return; 01178 } 01179 01180 #ifdef DEBUG_DSSI_PROCESS 01181 SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): I'm the first, running" << endl; 01182 #endif 01183 01184 size_t index = 0; 01185 unsigned long *counts = (unsigned long *) 01186 alloca(m_groupLocalEventBufferCount * sizeof(unsigned long)); 01187 LADSPA_Handle *instances = (LADSPA_Handle *) 01188 alloca(m_groupLocalEventBufferCount * sizeof(LADSPA_Handle)); 01189 01190 for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { 01191 01192 if (index >= m_groupLocalEventBufferCount) break; 01193 01194 DSSIPluginInstance *instance = *i; 01195 counts[index] = 0; 01196 instances[index] = instance->m_instanceHandle; 01197 01198 #ifdef DEBUG_DSSI_PROCESS 01199 SVDEBUG << "DSSIPluginInstance::runGrouped(" << blockTime << "): running " << instance << endl; 01200 #endif 01201 01202 if (instance->m_pending.program >= 0 && 01203 instance->m_descriptor->select_program) { 01204 int program = instance->m_pending.program; 01205 int bank = instance->m_pending.lsb + 128 * instance->m_pending.msb; 01206 instance->m_pending.lsb = instance->m_pending.msb = instance->m_pending.program = -1; 01207 instance->m_descriptor->select_program 01208 (instance->m_instanceHandle, bank, program); 01209 } 01210 01211 while (instance->m_eventBuffer.getReadSpace() > 0) { 01212 01213 snd_seq_event_t *ev = m_groupLocalEventBuffers[index] + counts[index]; 01214 *ev = instance->m_eventBuffer.peekOne(); 01215 bool accept = true; 01216 01217 Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); 01218 01219 int frameOffset = 0; 01220 if (evTime > blockTime) { 01221 frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); 01222 } 01223 01224 #ifdef DEBUG_DSSI_PROCESS 01225 SVDEBUG << "DSSIPluginInstance::runGrouped: evTime " << evTime << ", frameOffset " << frameOffset 01226 << ", block size " << m_blockSize << endl; 01227 #endif 01228 01229 if (frameOffset >= int(m_blockSize)) break; 01230 if (frameOffset < 0) frameOffset = 0; 01231 01232 ev->time.tick = frameOffset; 01233 instance->m_eventBuffer.skip(1); 01234 01235 if (ev->type == SND_SEQ_EVENT_CONTROLLER) { 01236 accept = instance->handleController(ev); 01237 } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { 01238 instance->m_pending.program = ev->data.control.value; 01239 accept = false; 01240 } 01241 01242 if (accept) { 01243 if (++counts[index] >= EVENT_BUFFER_SIZE) break; 01244 } 01245 } 01246 01247 ++index; 01248 } 01249 01250 m_descriptor->run_multiple_synths(index, 01251 instances, 01252 m_blockSize, 01253 m_groupLocalEventBuffers, 01254 counts); 01255 } 01256 01257 int 01258 DSSIPluginInstance::requestMidiSend(LADSPA_Handle /* instance */, 01259 unsigned char /* ports */, 01260 unsigned char /* channels */) 01261 { 01262 // This is called from a non-RT context (during instantiate) 01263 01264 SVDEBUG << "DSSIPluginInstance::requestMidiSend" << endl; 01265 return 1; 01266 } 01267 01268 void 01269 DSSIPluginInstance::midiSend(LADSPA_Handle /* instance */, 01270 snd_seq_event_t * /* events */, 01271 unsigned long /* eventCount */) 01272 { 01273 // This is likely to be called from an RT context 01274 01275 SVDEBUG << "DSSIPluginInstance::midiSend" << endl; 01276 } 01277 01278 void 01279 DSSIPluginInstance::NonRTPluginThread::run() 01280 { 01281 while (!m_exiting) { 01282 m_runFunction(m_handle); 01283 usleep(100000); 01284 } 01285 } 01286 01287 int 01288 DSSIPluginInstance::requestNonRTThread(LADSPA_Handle instance, 01289 void (*runFunction)(LADSPA_Handle)) 01290 { 01291 NonRTPluginThread *thread = new NonRTPluginThread(instance, runFunction); 01292 m_threads[instance].insert(thread); 01293 thread->start(); 01294 return 0; 01295 } 01296 01297 void 01298 DSSIPluginInstance::deactivate() 01299 { 01300 #ifdef DEBUG_DSSI 01301 SVDEBUG << "DSSIPluginInstance::deactivate " << m_identifier << endl; 01302 #endif 01303 if (!m_descriptor || !m_descriptor->LADSPA_Plugin->deactivate) return; 01304 01305 for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { 01306 m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; 01307 } 01308 01309 m_descriptor->LADSPA_Plugin->deactivate(m_instanceHandle); 01310 #ifdef DEBUG_DSSI 01311 SVDEBUG << "DSSIPluginInstance::deactivate " << m_identifier << " done" << endl; 01312 #endif 01313 01314 m_bufferScavenger.scavenge(); 01315 } 01316 01317 void 01318 DSSIPluginInstance::cleanup() 01319 { 01320 #ifdef DEBUG_DSSI 01321 SVDEBUG << "DSSIPluginInstance::cleanup " << m_identifier << endl; 01322 #endif 01323 if (!m_descriptor) return; 01324 01325 if (!m_descriptor->LADSPA_Plugin->cleanup) { 01326 cerr << "Bad plugin: plugin id " 01327 << m_descriptor->LADSPA_Plugin->UniqueID 01328 << ":" << m_descriptor->LADSPA_Plugin->Label 01329 << " has no cleanup method!" << endl; 01330 return; 01331 } 01332 01333 m_descriptor->LADSPA_Plugin->cleanup(m_instanceHandle); 01334 m_instanceHandle = 0; 01335 #ifdef DEBUG_DSSI 01336 SVDEBUG << "DSSIPluginInstance::cleanup " << m_identifier << " done" << endl; 01337 #endif 01338 } 01339