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