lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: This is a modified version of a source file from the lbajardsilogic@0: Rosegarden MIDI and audio sequencer and notation editor. lbajardsilogic@0: This file copyright 2000-2006 Chris Cannam. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include "DSSIPluginInstance.h" lbajardsilogic@0: #include "PluginIdentifier.h" lbajardsilogic@0: #include "LADSPAPluginFactory.h" lbajardsilogic@0: lbajardsilogic@0: //#define DEBUG_DSSI 1 lbajardsilogic@0: //#define DEBUG_DSSI_PROCESS 1 lbajardsilogic@0: lbajardsilogic@0: #define EVENT_BUFFER_SIZE 1023 lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: static std::ostream &operator<<(std::ostream& o, const QString &s) lbajardsilogic@0: { lbajardsilogic@0: o << s.toLocal8Bit().data(); lbajardsilogic@0: return o; lbajardsilogic@0: } lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: DSSIPluginInstance::GroupMap DSSIPluginInstance::m_groupMap; lbajardsilogic@0: snd_seq_event_t **DSSIPluginInstance::m_groupLocalEventBuffers = 0; lbajardsilogic@0: size_t DSSIPluginInstance::m_groupLocalEventBufferCount = 0; lbajardsilogic@0: Scavenger > DSSIPluginInstance::m_bufferScavenger(2, 10); lbajardsilogic@0: std::map > DSSIPluginInstance::m_threads; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: DSSIPluginInstance::DSSIPluginInstance(RealTimePluginFactory *factory, lbajardsilogic@0: int clientId, lbajardsilogic@0: QString identifier, lbajardsilogic@0: int position, lbajardsilogic@0: unsigned long sampleRate, lbajardsilogic@0: size_t blockSize, lbajardsilogic@0: int idealChannelCount, lbajardsilogic@0: const DSSI_Descriptor* descriptor) : lbajardsilogic@0: RealTimePluginInstance(factory, identifier), lbajardsilogic@0: m_client(clientId), lbajardsilogic@0: m_position(position), lbajardsilogic@0: m_descriptor(descriptor), lbajardsilogic@0: m_programCacheValid(false), lbajardsilogic@0: m_eventBuffer(EVENT_BUFFER_SIZE), lbajardsilogic@0: m_blockSize(blockSize), lbajardsilogic@0: m_idealChannelCount(idealChannelCount), lbajardsilogic@0: m_sampleRate(sampleRate), lbajardsilogic@0: m_latencyPort(0), lbajardsilogic@0: m_run(false), lbajardsilogic@0: m_bypassed(false), lbajardsilogic@0: m_grouped(false), lbajardsilogic@0: m_haveLastEventSendTime(false) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::DSSIPluginInstance(" << identifier << ")" lbajardsilogic@0: << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: init(); lbajardsilogic@0: lbajardsilogic@0: m_inputBuffers = new sample_t*[m_audioPortsIn.size()]; lbajardsilogic@0: m_outputBuffers = new sample_t*[m_outputBufferCount]; lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { lbajardsilogic@0: m_inputBuffers[i] = new sample_t[blockSize]; lbajardsilogic@0: } lbajardsilogic@0: for (size_t i = 0; i < m_outputBufferCount; ++i) { lbajardsilogic@0: m_outputBuffers[i] = new sample_t[blockSize]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_ownBuffers = true; lbajardsilogic@0: lbajardsilogic@0: m_pending.lsb = m_pending.msb = m_pending.program = -1; lbajardsilogic@0: lbajardsilogic@0: instantiate(sampleRate); lbajardsilogic@0: if (isOK()) { lbajardsilogic@0: connectPorts(); lbajardsilogic@0: activate(); lbajardsilogic@0: initialiseGroupMembership(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::getIdentifier() const lbajardsilogic@0: { lbajardsilogic@0: return m_descriptor->LADSPA_Plugin->Label; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::getName() const lbajardsilogic@0: { lbajardsilogic@0: return m_descriptor->LADSPA_Plugin->Name; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::getDescription() const lbajardsilogic@0: { lbajardsilogic@0: return ""; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::getMaker() const lbajardsilogic@0: { lbajardsilogic@0: return m_descriptor->LADSPA_Plugin->Maker; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int lbajardsilogic@0: DSSIPluginInstance::getPluginVersion() const lbajardsilogic@0: { lbajardsilogic@0: return 1; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::getCopyright() const lbajardsilogic@0: { lbajardsilogic@0: return m_descriptor->LADSPA_Plugin->Copyright; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: DSSIPluginInstance::ParameterList lbajardsilogic@0: DSSIPluginInstance::getParameterDescriptors() const lbajardsilogic@0: { lbajardsilogic@0: ParameterList list; lbajardsilogic@0: LADSPAPluginFactory *f = dynamic_cast(m_factory); lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { lbajardsilogic@0: lbajardsilogic@0: ParameterDescriptor pd; lbajardsilogic@0: unsigned int pn = m_controlPortsIn[i].first; lbajardsilogic@0: lbajardsilogic@0: pd.identifier = m_descriptor->LADSPA_Plugin->PortNames[pn]; lbajardsilogic@0: pd.name = pd.identifier; lbajardsilogic@0: pd.description = ""; lbajardsilogic@0: pd.minValue = f->getPortMinimum(m_descriptor->LADSPA_Plugin, pn); lbajardsilogic@0: pd.maxValue = f->getPortMaximum(m_descriptor->LADSPA_Plugin, pn); lbajardsilogic@0: pd.defaultValue = f->getPortDefault(m_descriptor->LADSPA_Plugin, pn); lbajardsilogic@0: lbajardsilogic@0: float q = f->getPortQuantization(m_descriptor->LADSPA_Plugin, pn); lbajardsilogic@0: if (q == 0.0) { lbajardsilogic@0: pd.isQuantized = false; lbajardsilogic@0: } else { lbajardsilogic@0: pd.isQuantized = true; lbajardsilogic@0: pd.quantizeStep = q; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: list.push_back(pd); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return list; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: float lbajardsilogic@0: DSSIPluginInstance::getParameter(std::string id) const lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::getParameter(" << id << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { lbajardsilogic@0: if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "Matches port " << i << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: float v = getParameterValue(i); lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "Returning " << v << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: return v; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return 0.0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::setParameter(std::string id, float value) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::setParameter(" << id << ", " << value << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { lbajardsilogic@0: if (id == m_descriptor->LADSPA_Plugin->PortNames[m_controlPortsIn[i].first]) { lbajardsilogic@0: setParameterValue(i, value); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::init() lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::init" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: // Discover ports numbers and identities lbajardsilogic@0: // lbajardsilogic@0: const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; lbajardsilogic@0: lbajardsilogic@0: for (unsigned long i = 0; i < descriptor->PortCount; ++i) lbajardsilogic@0: { lbajardsilogic@0: if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[i])) lbajardsilogic@0: { lbajardsilogic@0: if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { lbajardsilogic@0: m_audioPortsIn.push_back(i); lbajardsilogic@0: } else { lbajardsilogic@0: m_audioPortsOut.push_back(i); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: else lbajardsilogic@0: if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) lbajardsilogic@0: { lbajardsilogic@0: if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { lbajardsilogic@0: lbajardsilogic@0: LADSPA_Data *data = new LADSPA_Data(0.0); lbajardsilogic@0: lbajardsilogic@0: m_controlPortsIn.push_back(std::pair lbajardsilogic@0: (i, data)); lbajardsilogic@0: lbajardsilogic@0: m_backupControlPortsIn.push_back(0.0); lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: LADSPA_Data *data = new LADSPA_Data(0.0); lbajardsilogic@0: m_controlPortsOut.push_back( lbajardsilogic@0: std::pair(i, data)); lbajardsilogic@0: if (!strcmp(descriptor->PortNames[i], "latency") || lbajardsilogic@0: !strcmp(descriptor->PortNames[i], "_latency")) { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "Wooo! We have a latency port!" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: m_latencyPort = data; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: else lbajardsilogic@0: std::cerr << "DSSIPluginInstance::DSSIPluginInstance - " lbajardsilogic@0: << "unrecognised port type" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@191: m_outputBufferCount = MAX(m_idealChannelCount, m_audioPortsOut.size()); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: size_t lbajardsilogic@0: DSSIPluginInstance::getLatency() lbajardsilogic@0: { lbajardsilogic@0: size_t latency = 0; lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::getLatency(): m_latencyPort " << m_latencyPort << ", m_run " << m_run << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (m_latencyPort) { lbajardsilogic@0: if (!m_run) { lbajardsilogic@0: for (size_t i = 0; i < getAudioInputCount(); ++i) { lbajardsilogic@0: for (size_t j = 0; j < m_blockSize; ++j) { lbajardsilogic@0: m_inputBuffers[i][j] = 0.f; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: run(Vamp::RealTime::zeroTime); lbajardsilogic@0: } lbajardsilogic@0: latency = (size_t)(*m_latencyPort + 0.1); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::getLatency(): latency is " << latency << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: return latency; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::silence() lbajardsilogic@0: { lbajardsilogic@0: if (m_instanceHandle != 0) { lbajardsilogic@0: deactivate(); lbajardsilogic@0: activate(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::discardEvents() lbajardsilogic@0: { lbajardsilogic@0: m_eventBuffer.reset(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::setIdealChannelCount(size_t channels) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::setIdealChannelCount: channel count " lbajardsilogic@0: << channels << " (was " << m_idealChannelCount << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (channels == m_idealChannelCount) { lbajardsilogic@0: silence(); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_instanceHandle != 0) { lbajardsilogic@0: deactivate(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_idealChannelCount = channels; lbajardsilogic@0: lbajardsilogic@0: if (channels > m_outputBufferCount) { lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_outputBufferCount; ++i) { lbajardsilogic@0: delete[] m_outputBuffers[i]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: delete[] m_outputBuffers; lbajardsilogic@0: lbajardsilogic@0: m_outputBufferCount = channels; lbajardsilogic@0: lbajardsilogic@0: m_outputBuffers = new sample_t*[m_outputBufferCount]; lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_outputBufferCount; ++i) { lbajardsilogic@0: m_outputBuffers[i] = new sample_t[m_blockSize]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: connectPorts(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_instanceHandle != 0) { lbajardsilogic@0: activate(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::detachFromGroup() lbajardsilogic@0: { lbajardsilogic@0: if (!m_grouped) return; lbajardsilogic@0: m_groupMap[m_identifier].erase(this); lbajardsilogic@0: m_grouped = false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::initialiseGroupMembership() lbajardsilogic@0: { lbajardsilogic@0: if (!m_descriptor->run_multiple_synths) { lbajardsilogic@0: m_grouped = false; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: //!!! GroupMap is not actually thread-safe. lbajardsilogic@0: lbajardsilogic@0: size_t pluginsInGroup = m_groupMap[m_identifier].size(); lbajardsilogic@0: lbajardsilogic@0: if (++pluginsInGroup > m_groupLocalEventBufferCount) { lbajardsilogic@0: lbajardsilogic@0: size_t nextBufferCount = pluginsInGroup * 2; lbajardsilogic@0: lbajardsilogic@0: snd_seq_event_t **eventLocalBuffers = new snd_seq_event_t *[nextBufferCount]; lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_groupLocalEventBufferCount; ++i) { lbajardsilogic@0: eventLocalBuffers[i] = m_groupLocalEventBuffers[i]; lbajardsilogic@0: } lbajardsilogic@0: for (size_t i = m_groupLocalEventBufferCount; i < nextBufferCount; ++i) { lbajardsilogic@0: eventLocalBuffers[i] = new snd_seq_event_t[EVENT_BUFFER_SIZE]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_groupLocalEventBuffers) { lbajardsilogic@0: m_bufferScavenger.claim(new ScavengerArrayWrapper lbajardsilogic@0: (m_groupLocalEventBuffers)); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_groupLocalEventBuffers = eventLocalBuffers; lbajardsilogic@0: m_groupLocalEventBufferCount = nextBufferCount; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_grouped = true; lbajardsilogic@0: m_groupMap[m_identifier].insert(this); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: DSSIPluginInstance::~DSSIPluginInstance() lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::~DSSIPluginInstance" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (m_threads.find(m_instanceHandle) != m_threads.end()) { lbajardsilogic@0: lbajardsilogic@0: for (std::set::iterator i = lbajardsilogic@0: m_threads[m_instanceHandle].begin(); lbajardsilogic@0: i != m_threads[m_instanceHandle].end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: (*i)->setExiting(); lbajardsilogic@0: (*i)->wait(); lbajardsilogic@0: delete *i; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_threads.erase(m_instanceHandle); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: detachFromGroup(); lbajardsilogic@0: lbajardsilogic@0: if (m_instanceHandle != 0) { lbajardsilogic@0: deactivate(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: cleanup(); lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) lbajardsilogic@0: delete m_controlPortsIn[i].second; lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) lbajardsilogic@0: delete m_controlPortsOut[i].second; lbajardsilogic@0: lbajardsilogic@0: m_controlPortsIn.clear(); lbajardsilogic@0: m_controlPortsOut.clear(); lbajardsilogic@0: lbajardsilogic@0: if (m_ownBuffers) { lbajardsilogic@0: for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { lbajardsilogic@0: delete[] m_inputBuffers[i]; lbajardsilogic@0: } lbajardsilogic@0: for (size_t i = 0; i < m_outputBufferCount; ++i) { lbajardsilogic@0: delete[] m_outputBuffers[i]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: delete[] m_inputBuffers; lbajardsilogic@0: delete[] m_outputBuffers; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_audioPortsIn.clear(); lbajardsilogic@0: m_audioPortsOut.clear(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::instantiate(unsigned long sampleRate) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cout << "DSSIPluginInstance::instantiate - plugin \"unique\" id = " lbajardsilogic@0: << m_descriptor->LADSPA_Plugin->UniqueID << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: if (!m_descriptor) return; lbajardsilogic@0: lbajardsilogic@0: const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; lbajardsilogic@0: lbajardsilogic@0: if (!descriptor->instantiate) { lbajardsilogic@0: std::cerr << "Bad plugin: plugin id " << descriptor->UniqueID lbajardsilogic@0: << ":" << descriptor->Label lbajardsilogic@0: << " has no instantiate method!" << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_instanceHandle = descriptor->instantiate(descriptor, sampleRate); lbajardsilogic@0: lbajardsilogic@0: if (m_instanceHandle) { lbajardsilogic@0: lbajardsilogic@0: if (m_descriptor->get_midi_controller_for_port) { lbajardsilogic@0: lbajardsilogic@0: for (unsigned long i = 0; i < descriptor->PortCount; ++i) { lbajardsilogic@0: lbajardsilogic@0: if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i]) && lbajardsilogic@0: LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { lbajardsilogic@0: lbajardsilogic@0: int controller = m_descriptor->get_midi_controller_for_port lbajardsilogic@0: (m_instanceHandle, i); lbajardsilogic@0: lbajardsilogic@0: if (controller != 0 && controller != 32 && lbajardsilogic@0: DSSI_IS_CC(controller)) { lbajardsilogic@0: lbajardsilogic@0: m_controllerMap[DSSI_CC_NUMBER(controller)] = i; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::checkProgramCache() const lbajardsilogic@0: { lbajardsilogic@0: if (m_programCacheValid) return; lbajardsilogic@0: m_cachedPrograms.clear(); lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::checkProgramCache" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor || !m_descriptor->get_program) { lbajardsilogic@0: m_programCacheValid = true; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: unsigned long index = 0; lbajardsilogic@0: const DSSI_Program_Descriptor *programDescriptor; lbajardsilogic@0: while ((programDescriptor = m_descriptor->get_program(m_instanceHandle, index))) { lbajardsilogic@0: ++index; lbajardsilogic@0: ProgramDescriptor d; lbajardsilogic@0: d.bank = programDescriptor->Bank; lbajardsilogic@0: d.program = programDescriptor->Program; lbajardsilogic@0: d.name = programDescriptor->Name; lbajardsilogic@0: m_cachedPrograms.push_back(d); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::checkProgramCache: have " << m_cachedPrograms.size() << " programs" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: m_programCacheValid = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: DSSIPluginInstance::ProgramList lbajardsilogic@0: DSSIPluginInstance::getPrograms() const lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::getPrograms" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor) return ProgramList(); lbajardsilogic@0: lbajardsilogic@0: checkProgramCache(); lbajardsilogic@0: lbajardsilogic@0: ProgramList programs; lbajardsilogic@0: lbajardsilogic@0: for (std::vector::iterator i = m_cachedPrograms.begin(); lbajardsilogic@0: i != m_cachedPrograms.end(); ++i) { lbajardsilogic@0: programs.push_back(i->name); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return programs; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::getProgram(int bank, int program) const lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::getProgram(" << bank << "," << program << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor) return std::string(); lbajardsilogic@0: lbajardsilogic@0: checkProgramCache(); lbajardsilogic@0: lbajardsilogic@0: for (std::vector::iterator i = m_cachedPrograms.begin(); lbajardsilogic@0: i != m_cachedPrograms.end(); ++i) { lbajardsilogic@0: if (i->bank == bank && i->program == program) return i->name; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return std::string(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: unsigned long lbajardsilogic@0: DSSIPluginInstance::getProgram(std::string name) const lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::getProgram(" << name << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor) return 0; lbajardsilogic@0: lbajardsilogic@0: checkProgramCache(); lbajardsilogic@0: lbajardsilogic@0: unsigned long rv; lbajardsilogic@0: lbajardsilogic@0: for (std::vector::iterator i = m_cachedPrograms.begin(); lbajardsilogic@0: i != m_cachedPrograms.end(); ++i) { lbajardsilogic@0: if (i->name == name) { lbajardsilogic@0: rv = i->bank; lbajardsilogic@0: rv = (rv << 16) + i->program; lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return 0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::getCurrentProgram() const lbajardsilogic@0: { lbajardsilogic@0: return m_program; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::selectProgram(std::string program) lbajardsilogic@0: { lbajardsilogic@0: selectProgramAux(program, true); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::selectProgramAux(std::string program, bool backupPortValues) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::selectProgram(" << program << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor) return; lbajardsilogic@0: lbajardsilogic@0: checkProgramCache(); lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor->select_program) return; lbajardsilogic@0: lbajardsilogic@0: bool found = false; lbajardsilogic@0: unsigned long bankNo = 0, programNo = 0; lbajardsilogic@0: lbajardsilogic@0: for (std::vector::iterator i = m_cachedPrograms.begin(); lbajardsilogic@0: i != m_cachedPrograms.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: if (i->name == program) { lbajardsilogic@0: lbajardsilogic@0: bankNo = i->bank; lbajardsilogic@0: programNo = i->program; lbajardsilogic@0: found = true; lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::selectProgram(" << program << "): found at bank " << bankNo << ", program " << programNo << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (!found) return; lbajardsilogic@0: m_program = program; lbajardsilogic@0: lbajardsilogic@0: // DSSI select_program is an audio context call lbajardsilogic@0: m_processLock.lock(); lbajardsilogic@0: m_descriptor->select_program(m_instanceHandle, bankNo, programNo); lbajardsilogic@0: m_processLock.unlock(); lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::selectProgram(" << program << "): made select_program(" << bankNo << "," << programNo << ") call" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (backupPortValues) { lbajardsilogic@0: for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { lbajardsilogic@0: m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::activate() lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::activate" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor || !m_descriptor->LADSPA_Plugin->activate) return; lbajardsilogic@0: m_descriptor->LADSPA_Plugin->activate(m_instanceHandle); lbajardsilogic@0: lbajardsilogic@0: if (m_program != "") { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::activate: restoring program " << m_program << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: selectProgramAux(m_program, false); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::activate: setting port " << m_controlPortsIn[i].first << " to " << m_backupControlPortsIn[i] << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: *m_controlPortsIn[i].second = m_backupControlPortsIn[i]; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::connectPorts() lbajardsilogic@0: { lbajardsilogic@0: if (!m_descriptor || !m_descriptor->LADSPA_Plugin->connect_port) return; lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::connectPorts: " << m_audioPortsIn.size() lbajardsilogic@0: << " audio ports in, " << m_audioPortsOut.size() << " out, " lbajardsilogic@0: << m_outputBufferCount << " output buffers" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: assert(sizeof(LADSPA_Data) == sizeof(float)); lbajardsilogic@0: assert(sizeof(sample_t) == sizeof(float)); lbajardsilogic@0: lbajardsilogic@0: LADSPAPluginFactory *f = dynamic_cast(m_factory); lbajardsilogic@0: int inbuf = 0, outbuf = 0; lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) { lbajardsilogic@0: m_descriptor->LADSPA_Plugin->connect_port lbajardsilogic@0: (m_instanceHandle, lbajardsilogic@0: m_audioPortsIn[i], lbajardsilogic@0: (LADSPA_Data *)m_inputBuffers[inbuf]); lbajardsilogic@0: ++inbuf; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) { lbajardsilogic@0: m_descriptor->LADSPA_Plugin->connect_port lbajardsilogic@0: (m_instanceHandle, lbajardsilogic@0: m_audioPortsOut[i], lbajardsilogic@0: (LADSPA_Data *)m_outputBuffers[outbuf]); lbajardsilogic@0: ++outbuf; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { lbajardsilogic@0: m_descriptor->LADSPA_Plugin->connect_port lbajardsilogic@0: (m_instanceHandle, lbajardsilogic@0: m_controlPortsIn[i].first, lbajardsilogic@0: m_controlPortsIn[i].second); lbajardsilogic@0: lbajardsilogic@0: if (f) { lbajardsilogic@0: float defaultValue = f->getPortDefault lbajardsilogic@0: (m_descriptor->LADSPA_Plugin, m_controlPortsIn[i].first); lbajardsilogic@0: *m_controlPortsIn[i].second = defaultValue; lbajardsilogic@0: m_backupControlPortsIn[i] = defaultValue; lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::connectPorts: set control port " << i << " to default value " << defaultValue << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) { lbajardsilogic@0: m_descriptor->LADSPA_Plugin->connect_port lbajardsilogic@0: (m_instanceHandle, lbajardsilogic@0: m_controlPortsOut[i].first, lbajardsilogic@0: m_controlPortsOut[i].second); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: unsigned int lbajardsilogic@0: DSSIPluginInstance::getParameterCount() const lbajardsilogic@0: { lbajardsilogic@0: return m_controlPortsIn.size(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::setParameterValue(unsigned int parameter, float value) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::setParameterValue(" << parameter << ") to " << value << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: if (parameter >= m_controlPortsIn.size()) return; lbajardsilogic@0: lbajardsilogic@0: unsigned int portNumber = m_controlPortsIn[parameter].first; lbajardsilogic@0: lbajardsilogic@0: LADSPAPluginFactory *f = dynamic_cast(m_factory); lbajardsilogic@0: if (f) { lbajardsilogic@0: if (value < f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber)) { lbajardsilogic@0: value = f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber); lbajardsilogic@0: } lbajardsilogic@0: if (value > f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber)) { lbajardsilogic@0: value = f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: (*m_controlPortsIn[parameter].second) = value; lbajardsilogic@0: m_backupControlPortsIn[parameter] = value; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::setPortValueFromController(unsigned int port, int cv) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::setPortValueFromController(" << port << ") to " << cv << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: const LADSPA_Descriptor *p = m_descriptor->LADSPA_Plugin; lbajardsilogic@0: LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor; lbajardsilogic@0: LADSPA_Data lb = p->PortRangeHints[port].LowerBound; lbajardsilogic@0: LADSPA_Data ub = p->PortRangeHints[port].UpperBound; lbajardsilogic@0: lbajardsilogic@0: float value = (float)cv; lbajardsilogic@0: lbajardsilogic@0: if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) { lbajardsilogic@0: if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { lbajardsilogic@0: /* unbounded: might as well leave the value alone. */ lbajardsilogic@0: } else { lbajardsilogic@0: /* bounded above only. just shift the range. */ lbajardsilogic@0: value = ub - 127.0f + value; lbajardsilogic@0: } lbajardsilogic@0: } else { lbajardsilogic@0: if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { lbajardsilogic@0: /* bounded below only. just shift the range. */ lbajardsilogic@0: value = lb + value; lbajardsilogic@0: } else { lbajardsilogic@0: /* bounded both ends. more interesting. */ lbajardsilogic@0: /* XXX !!! todo: fill in logarithmic, sample rate &c */ lbajardsilogic@0: value = lb + ((ub - lb) * value / 127.0f); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { lbajardsilogic@0: if (m_controlPortsIn[i].first == port) { lbajardsilogic@0: setParameterValue(i, value); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: float lbajardsilogic@0: DSSIPluginInstance::getControlOutputValue(size_t output) const lbajardsilogic@0: { lbajardsilogic@0: if (output > m_controlPortsOut.size()) return 0.0; lbajardsilogic@0: return (*m_controlPortsOut[output].second); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: float lbajardsilogic@0: DSSIPluginInstance::getParameterValue(unsigned int parameter) const lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::getParameterValue(" << parameter << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: if (parameter >= m_controlPortsIn.size()) return 0.0; lbajardsilogic@0: return (*m_controlPortsIn[parameter].second); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: float lbajardsilogic@0: DSSIPluginInstance::getParameterDefault(unsigned int parameter) const lbajardsilogic@0: { lbajardsilogic@0: if (parameter >= m_controlPortsIn.size()) return 0.0; lbajardsilogic@0: lbajardsilogic@0: LADSPAPluginFactory *f = dynamic_cast(m_factory); lbajardsilogic@0: if (f) { lbajardsilogic@0: return f->getPortDefault(m_descriptor->LADSPA_Plugin, lbajardsilogic@0: m_controlPortsIn[parameter].first); lbajardsilogic@0: } else { lbajardsilogic@0: return 0.0f; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::string lbajardsilogic@0: DSSIPluginInstance::configure(std::string key, lbajardsilogic@0: std::string value) lbajardsilogic@0: { lbajardsilogic@0: if (!m_descriptor || !m_descriptor->configure) return std::string(); lbajardsilogic@0: lbajardsilogic@0: if (key == PluginIdentifier::RESERVED_PROJECT_DIRECTORY_KEY.toStdString()) { lbajardsilogic@0: #ifdef DSSI_PROJECT_DIRECTORY_KEY lbajardsilogic@0: key = DSSI_PROJECT_DIRECTORY_KEY; lbajardsilogic@0: #else lbajardsilogic@0: return std::string(); lbajardsilogic@0: #endif lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::configure(" << key << "," << value << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: char *message = m_descriptor->configure(m_instanceHandle, lbajardsilogic@0: key.c_str(), lbajardsilogic@0: value.c_str()); lbajardsilogic@0: lbajardsilogic@0: m_programCacheValid = false; lbajardsilogic@0: lbajardsilogic@0: m_configurationData[key] = value; lbajardsilogic@0: lbajardsilogic@0: std::string qm; lbajardsilogic@0: lbajardsilogic@0: // Ignore return values from reserved key configuration calls such lbajardsilogic@0: // as project directory lbajardsilogic@0: #ifdef DSSI_RESERVED_CONFIGURE_PREFIX lbajardsilogic@0: if (QString(key.c_str()).startsWith(DSSI_RESERVED_CONFIGURE_PREFIX)) { lbajardsilogic@0: return qm; lbajardsilogic@0: } lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (message) { lbajardsilogic@0: if (m_descriptor->LADSPA_Plugin && m_descriptor->LADSPA_Plugin->Label) { lbajardsilogic@0: qm = std::string(m_descriptor->LADSPA_Plugin->Label) + ": "; lbajardsilogic@0: } lbajardsilogic@0: qm = qm + message; lbajardsilogic@0: free(message); lbajardsilogic@0: lbajardsilogic@0: std::cerr << "DSSIPluginInstance::configure: warning: configure returned message: \"" << qm << "\"" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return qm; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::sendEvent(const Vamp::RealTime &eventTime, lbajardsilogic@0: const void *e) lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::sendEvent: last was " << m_lastEventSendTime << " (valid " << m_haveLastEventSendTime << "), this is " << eventTime << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: // The process mechanism only works correctly if the events are lbajardsilogic@0: // sorted. It's the responsibility of the caller to ensure that: lbajardsilogic@0: // we will happily drop events here if we find the timeline going lbajardsilogic@0: // backwards. lbajardsilogic@0: if (m_haveLastEventSendTime && lbajardsilogic@0: m_lastEventSendTime > eventTime) { lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "... clearing down" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: m_haveLastEventSendTime = false; lbajardsilogic@0: clearEvents(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: snd_seq_event_t *event = (snd_seq_event_t *)e; lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::sendEvent at " << eventTime << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: snd_seq_event_t ev(*event); lbajardsilogic@0: lbajardsilogic@0: ev.time.time.tv_sec = eventTime.sec; lbajardsilogic@0: ev.time.time.tv_nsec = eventTime.nsec; lbajardsilogic@0: lbajardsilogic@0: // DSSI doesn't use MIDI channels, it uses run_multiple_synths instead. lbajardsilogic@0: ev.data.note.channel = 0; lbajardsilogic@0: lbajardsilogic@0: m_eventBuffer.write(&ev, 1); lbajardsilogic@0: lbajardsilogic@0: m_lastEventSendTime = eventTime; lbajardsilogic@0: m_haveLastEventSendTime = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::clearEvents() lbajardsilogic@0: { lbajardsilogic@0: m_haveLastEventSendTime = false; lbajardsilogic@0: m_eventBuffer.reset(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: DSSIPluginInstance::handleController(snd_seq_event_t *ev) lbajardsilogic@0: { lbajardsilogic@0: int controller = ev->data.control.param; lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::handleController " << controller << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (controller == 0) { // bank select MSB lbajardsilogic@0: lbajardsilogic@0: m_pending.msb = ev->data.control.value; lbajardsilogic@0: lbajardsilogic@0: } else if (controller == 32) { // bank select LSB lbajardsilogic@0: lbajardsilogic@0: m_pending.lsb = ev->data.control.value; lbajardsilogic@0: lbajardsilogic@0: } else if (controller > 0 && controller < 128) { lbajardsilogic@0: lbajardsilogic@0: if (m_controllerMap.find(controller) != m_controllerMap.end()) { lbajardsilogic@0: int port = m_controllerMap[controller]; lbajardsilogic@0: setPortValueFromController(port, ev->data.control.value); lbajardsilogic@0: } else { lbajardsilogic@0: return true; // pass through to plugin lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::run(const Vamp::RealTime &blockTime) lbajardsilogic@0: { lbajardsilogic@0: static snd_seq_event_t localEventBuffer[EVENT_BUFFER_SIZE]; lbajardsilogic@0: int evCount = 0; lbajardsilogic@0: lbajardsilogic@0: bool needLock = false; lbajardsilogic@0: if (m_descriptor->select_program) needLock = true; lbajardsilogic@0: lbajardsilogic@0: if (needLock) { lbajardsilogic@0: if (!m_processLock.tryLock()) { lbajardsilogic@0: for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { lbajardsilogic@0: memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); lbajardsilogic@0: } lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_grouped) { lbajardsilogic@0: runGrouped(blockTime); lbajardsilogic@0: goto done; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor || !m_descriptor->run_synth) { lbajardsilogic@0: m_eventBuffer.skip(m_eventBuffer.getReadSpace()); lbajardsilogic@0: m_haveLastEventSendTime = false; lbajardsilogic@0: if (m_descriptor->LADSPA_Plugin->run) { lbajardsilogic@0: m_descriptor->LADSPA_Plugin->run(m_instanceHandle, m_blockSize); lbajardsilogic@0: } else { lbajardsilogic@0: for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { lbajardsilogic@0: memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: m_run = true; lbajardsilogic@0: if (needLock) m_processLock.unlock(); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::run(" << blockTime << ")" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: if (m_eventBuffer.getReadSpace() > 0) { lbajardsilogic@0: std::cerr << "DSSIPluginInstance::run: event buffer has " lbajardsilogic@0: << m_eventBuffer.getReadSpace() << " event(s) in it" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: while (m_eventBuffer.getReadSpace() > 0) { lbajardsilogic@0: lbajardsilogic@0: snd_seq_event_t *ev = localEventBuffer + evCount; lbajardsilogic@0: *ev = m_eventBuffer.peekOne(); lbajardsilogic@0: bool accept = true; lbajardsilogic@0: lbajardsilogic@0: Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); lbajardsilogic@0: lbajardsilogic@0: int frameOffset = 0; lbajardsilogic@0: if (evTime > blockTime) { lbajardsilogic@0: frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::run: evTime " << evTime << ", blockTime " << blockTime << ", frameOffset " << frameOffset lbajardsilogic@0: << ", blockSize " << m_blockSize << std::endl; lbajardsilogic@0: std::cerr << "Type: " << int(ev->type) << ", pitch: " << int(ev->data.note.note) << ", velocity: " << int(ev->data.note.velocity) << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (frameOffset >= int(m_blockSize)) break; lbajardsilogic@0: if (frameOffset < 0) { lbajardsilogic@0: frameOffset = 0; lbajardsilogic@0: if (ev->type == SND_SEQ_EVENT_NOTEON) { lbajardsilogic@0: m_eventBuffer.skip(1); lbajardsilogic@0: continue; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: ev->time.tick = frameOffset; lbajardsilogic@0: m_eventBuffer.skip(1); lbajardsilogic@0: lbajardsilogic@0: if (ev->type == SND_SEQ_EVENT_CONTROLLER) { lbajardsilogic@0: accept = handleController(ev); lbajardsilogic@0: } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { lbajardsilogic@0: m_pending.program = ev->data.control.value; lbajardsilogic@0: accept = false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (accept) { lbajardsilogic@0: if (++evCount >= EVENT_BUFFER_SIZE) break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_pending.program >= 0 && m_descriptor->select_program) { lbajardsilogic@0: lbajardsilogic@0: int program = m_pending.program; lbajardsilogic@0: int bank = m_pending.lsb + 128 * m_pending.msb; lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::run: making select_program(" << bank << "," << program << ") call" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: m_pending.lsb = m_pending.msb = m_pending.program = -1; lbajardsilogic@0: m_descriptor->select_program(m_instanceHandle, bank, program); lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::run: made select_program(" << bank << "," << program << ") call" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::run: running with " << evCount << " events" lbajardsilogic@0: << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: m_descriptor->run_synth(m_instanceHandle, m_blockSize, lbajardsilogic@0: localEventBuffer, evCount); lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: // for (int i = 0; i < m_blockSize; ++i) { lbajardsilogic@0: // std::cout << m_outputBuffers[0][i] << " "; lbajardsilogic@0: // if (i % 8 == 0) std::cout << std::endl; lbajardsilogic@0: // } lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: done: lbajardsilogic@0: if (needLock) m_processLock.unlock(); lbajardsilogic@0: lbajardsilogic@0: if (m_audioPortsOut.size() == 0) { lbajardsilogic@0: // copy inputs to outputs lbajardsilogic@0: for (size_t ch = 0; ch < m_idealChannelCount; ++ch) { lbajardsilogic@0: size_t sch = ch % m_audioPortsIn.size(); lbajardsilogic@0: for (size_t i = 0; i < m_blockSize; ++i) { lbajardsilogic@0: m_outputBuffers[ch][i] = m_inputBuffers[sch][i]; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } else if (m_idealChannelCount < m_audioPortsOut.size()) { lbajardsilogic@0: if (m_idealChannelCount == 1) { lbajardsilogic@0: // mix down to mono lbajardsilogic@0: for (size_t ch = 1; ch < m_audioPortsOut.size(); ++ch) { lbajardsilogic@0: for (size_t i = 0; i < m_blockSize; ++i) { lbajardsilogic@0: m_outputBuffers[0][i] += m_outputBuffers[ch][i]; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } else if (m_idealChannelCount > m_audioPortsOut.size()) { lbajardsilogic@0: // duplicate lbajardsilogic@0: for (size_t ch = m_audioPortsOut.size(); ch < m_idealChannelCount; ++ch) { lbajardsilogic@0: size_t sch = (ch - m_audioPortsOut.size()) % m_audioPortsOut.size(); lbajardsilogic@0: for (size_t i = 0; i < m_blockSize; ++i) { lbajardsilogic@0: m_outputBuffers[ch][i] = m_outputBuffers[sch][i]; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_lastRunTime = blockTime; lbajardsilogic@0: m_run = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::runGrouped(const Vamp::RealTime &blockTime) lbajardsilogic@0: { lbajardsilogic@0: // If something else in our group has just been called for this lbajardsilogic@0: // block time (but we haven't) then we should just write out the lbajardsilogic@0: // results and return; if we have just been called for this block lbajardsilogic@0: // time or nothing else in the group has been, we should run the lbajardsilogic@0: // whole group. lbajardsilogic@0: lbajardsilogic@0: bool needRun = true; lbajardsilogic@0: lbajardsilogic@0: PluginSet &s = m_groupMap[m_identifier]; lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): this is " << this << "; " << s.size() << " elements in m_groupMap[" << m_identifier << "]" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (m_lastRunTime != blockTime) { lbajardsilogic@0: for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { lbajardsilogic@0: DSSIPluginInstance *instance = *i; lbajardsilogic@0: if (instance != this && instance->m_lastRunTime == blockTime) { lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): plugin " << instance << " has already been run" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: needRun = false; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (!needRun) { lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): already run, returning" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): I'm the first, running" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: size_t index = 0; lbajardsilogic@0: unsigned long *counts = (unsigned long *) lbajardsilogic@0: alloca(m_groupLocalEventBufferCount * sizeof(unsigned long)); lbajardsilogic@0: LADSPA_Handle *instances = (LADSPA_Handle *) lbajardsilogic@0: alloca(m_groupLocalEventBufferCount * sizeof(LADSPA_Handle)); lbajardsilogic@0: lbajardsilogic@0: for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: if (index >= m_groupLocalEventBufferCount) break; lbajardsilogic@0: lbajardsilogic@0: DSSIPluginInstance *instance = *i; lbajardsilogic@0: counts[index] = 0; lbajardsilogic@0: instances[index] = instance->m_instanceHandle; lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): running " << instance << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (instance->m_pending.program >= 0 && lbajardsilogic@0: instance->m_descriptor->select_program) { lbajardsilogic@0: int program = instance->m_pending.program; lbajardsilogic@0: int bank = instance->m_pending.lsb + 128 * instance->m_pending.msb; lbajardsilogic@0: instance->m_pending.lsb = instance->m_pending.msb = instance->m_pending.program = -1; lbajardsilogic@0: instance->m_descriptor->select_program lbajardsilogic@0: (instance->m_instanceHandle, bank, program); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: while (instance->m_eventBuffer.getReadSpace() > 0) { lbajardsilogic@0: lbajardsilogic@0: snd_seq_event_t *ev = m_groupLocalEventBuffers[index] + counts[index]; lbajardsilogic@0: *ev = instance->m_eventBuffer.peekOne(); lbajardsilogic@0: bool accept = true; lbajardsilogic@0: lbajardsilogic@0: Vamp::RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); lbajardsilogic@0: lbajardsilogic@0: int frameOffset = 0; lbajardsilogic@0: if (evTime > blockTime) { lbajardsilogic@0: frameOffset = Vamp::RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: #ifdef DEBUG_DSSI_PROCESS lbajardsilogic@0: std::cerr << "DSSIPluginInstance::runGrouped: evTime " << evTime << ", frameOffset " << frameOffset lbajardsilogic@0: << ", block size " << m_blockSize << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: if (frameOffset >= int(m_blockSize)) break; lbajardsilogic@0: if (frameOffset < 0) frameOffset = 0; lbajardsilogic@0: lbajardsilogic@0: ev->time.tick = frameOffset; lbajardsilogic@0: instance->m_eventBuffer.skip(1); lbajardsilogic@0: lbajardsilogic@0: if (ev->type == SND_SEQ_EVENT_CONTROLLER) { lbajardsilogic@0: accept = instance->handleController(ev); lbajardsilogic@0: } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { lbajardsilogic@0: instance->m_pending.program = ev->data.control.value; lbajardsilogic@0: accept = false; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (accept) { lbajardsilogic@0: if (++counts[index] >= EVENT_BUFFER_SIZE) break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: ++index; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_descriptor->run_multiple_synths(index, lbajardsilogic@0: instances, lbajardsilogic@0: m_blockSize, lbajardsilogic@0: m_groupLocalEventBuffers, lbajardsilogic@0: counts); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int lbajardsilogic@0: DSSIPluginInstance::requestMidiSend(LADSPA_Handle /* instance */, lbajardsilogic@0: unsigned char /* ports */, lbajardsilogic@0: unsigned char /* channels */) lbajardsilogic@0: { lbajardsilogic@0: // This is called from a non-RT context (during instantiate) lbajardsilogic@0: lbajardsilogic@0: std::cerr << "DSSIPluginInstance::requestMidiSend" << std::endl; lbajardsilogic@0: return 1; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::midiSend(LADSPA_Handle /* instance */, lbajardsilogic@0: snd_seq_event_t * /* events */, lbajardsilogic@0: unsigned long /* eventCount */) lbajardsilogic@0: { lbajardsilogic@0: // This is likely to be called from an RT context lbajardsilogic@0: lbajardsilogic@0: std::cerr << "DSSIPluginInstance::midiSend" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::NonRTPluginThread::run() lbajardsilogic@0: { lbajardsilogic@0: while (!m_exiting) { lbajardsilogic@0: m_runFunction(m_handle); lbajardsilogic@0: usleep(100000); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int lbajardsilogic@0: DSSIPluginInstance::requestNonRTThread(LADSPA_Handle instance, lbajardsilogic@0: void (*runFunction)(LADSPA_Handle)) lbajardsilogic@0: { lbajardsilogic@0: NonRTPluginThread *thread = new NonRTPluginThread(instance, runFunction); lbajardsilogic@0: m_threads[instance].insert(thread); lbajardsilogic@0: thread->start(); lbajardsilogic@0: return 0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::deactivate() lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::deactivate " << m_identifier << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: if (!m_descriptor || !m_descriptor->LADSPA_Plugin->deactivate) return; lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { lbajardsilogic@0: m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_descriptor->LADSPA_Plugin->deactivate(m_instanceHandle); lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::deactivate " << m_identifier << " done" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: m_bufferScavenger.scavenge(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: DSSIPluginInstance::cleanup() lbajardsilogic@0: { lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::cleanup " << m_identifier << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: if (!m_descriptor) return; lbajardsilogic@0: lbajardsilogic@0: if (!m_descriptor->LADSPA_Plugin->cleanup) { lbajardsilogic@0: std::cerr << "Bad plugin: plugin id " lbajardsilogic@0: << m_descriptor->LADSPA_Plugin->UniqueID lbajardsilogic@0: << ":" << m_descriptor->LADSPA_Plugin->Label lbajardsilogic@0: << " has no cleanup method!" << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_descriptor->LADSPA_Plugin->cleanup(m_instanceHandle); lbajardsilogic@0: m_instanceHandle = 0; lbajardsilogic@0: #ifdef DEBUG_DSSI lbajardsilogic@0: std::cerr << "DSSIPluginInstance::cleanup " << m_identifier << " done" << std::endl; lbajardsilogic@0: #endif lbajardsilogic@0: } lbajardsilogic@0: