svcore  1.9
DSSIPluginInstance.cpp
Go to the documentation of this file.
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