diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-03-01 18:37:05 +0000 |
commit | 145364a8af6a1fec06556221e66d4b724a62fc9a (patch) | |
tree | 53bd71a544008c518034f208d64c932dc2883f50 /src/sound/DSSIPluginInstance.cpp | |
download | rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.tar.gz rosegarden-145364a8af6a1fec06556221e66d4b724a62fc9a.zip |
Added old abandoned KDE3 version of the RoseGarden MIDI tool
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/rosegarden@1097595 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/sound/DSSIPluginInstance.cpp')
-rw-r--r-- | src/sound/DSSIPluginInstance.cpp | 1208 |
1 files changed, 1208 insertions, 0 deletions
diff --git a/src/sound/DSSIPluginInstance.cpp b/src/sound/DSSIPluginInstance.cpp new file mode 100644 index 0000000..2ceb0df --- /dev/null +++ b/src/sound/DSSIPluginInstance.cpp @@ -0,0 +1,1208 @@ +// -*- c-basic-offset: 4 -*- + +/* + Rosegarden + A sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <[email protected]>, + Chris Cannam <[email protected]>, + Richard Bown <[email protected]> + + The moral right of the authors to claim authorship of this work + has been asserted. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#include <iostream> +#include <cassert> +#include <cstdlib> + +#include "DSSIPluginInstance.h" +#include "PluginIdentifier.h" +#include "LADSPAPluginFactory.h" + +#ifdef HAVE_DSSI + +//#define DEBUG_DSSI 1 +//#define DEBUG_DSSI_PROCESS 1 + +namespace Rosegarden +{ + +#define EVENT_BUFFER_SIZE 1023 + +DSSIPluginInstance::GroupMap DSSIPluginInstance::m_groupMap; +snd_seq_event_t **DSSIPluginInstance::m_groupLocalEventBuffers = 0; +size_t DSSIPluginInstance::m_groupLocalEventBufferCount = 0; +Scavenger<ScavengerArrayWrapper<snd_seq_event_t *> > DSSIPluginInstance::m_bufferScavenger(2, 10); + + +DSSIPluginInstance::DSSIPluginInstance(PluginFactory *factory, + InstrumentId instrument, + QString identifier, + int position, + unsigned long sampleRate, + size_t blockSize, + int idealChannelCount, + const DSSI_Descriptor* descriptor) : + RunnablePluginInstance(factory, identifier), + m_instrument(instrument), + m_position(position), + m_descriptor(descriptor), + m_programCacheValid(false), + m_eventBuffer(EVENT_BUFFER_SIZE), + m_blockSize(blockSize), + m_idealChannelCount(idealChannelCount), + m_sampleRate(sampleRate), + m_latencyPort(0), + m_run(false), + m_runSinceReset(false), + m_bypassed(false), + m_grouped(false) +{ + pthread_mutex_t initialisingMutex = PTHREAD_MUTEX_INITIALIZER; + memcpy(&m_processLock, &initialisingMutex, sizeof(pthread_mutex_t)); + +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::DSSIPluginInstance(" << identifier << ")" + << std::endl; +#endif + + init(); + + m_inputBuffers = new sample_t * [m_audioPortsIn.size()]; + m_outputBuffers = new sample_t * [m_outputBufferCount]; + + for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { + m_inputBuffers[i] = new sample_t[blockSize]; + } + for (size_t i = 0; i < m_outputBufferCount; ++i) { + m_outputBuffers[i] = new sample_t[blockSize]; + } + + m_ownBuffers = true; + + m_pending.lsb = m_pending.msb = m_pending.program = -1; + + instantiate(sampleRate); + if (isOK()) { + connectPorts(); + activate(); + initialiseGroupMembership(); + } +} + +DSSIPluginInstance::DSSIPluginInstance(PluginFactory *factory, + InstrumentId instrument, + QString identifier, + int position, + unsigned long sampleRate, + size_t blockSize, + sample_t **inputBuffers, + sample_t **outputBuffers, + const DSSI_Descriptor* descriptor) : + RunnablePluginInstance(factory, identifier), + m_instrument(instrument), + m_position(position), + m_descriptor(descriptor), + m_eventBuffer(EVENT_BUFFER_SIZE), + m_blockSize(blockSize), + m_inputBuffers(inputBuffers), + m_outputBuffers(outputBuffers), + m_ownBuffers(false), + m_idealChannelCount(0), + m_sampleRate(sampleRate), + m_latencyPort(0), + m_run(false), + m_runSinceReset(false), + m_bypassed(false), + m_grouped(false) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::DSSIPluginInstance[buffers supplied](" << identifier << ")" + << std::endl; +#endif + + init(); + + m_pending.lsb = m_pending.msb = m_pending.program = -1; + + instantiate(sampleRate); + if (isOK()) { + connectPorts(); + activate(); + if (m_descriptor->run_multiple_synths) { + m_grouped = true; + initialiseGroupMembership(); + } + } +} + + +void +DSSIPluginInstance::init() +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::init" << std::endl; +#endif + + // Discover ports numbers and identities + // + const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; + + for (unsigned long i = 0; i < descriptor->PortCount; ++i) { + if (LADSPA_IS_PORT_AUDIO(descriptor->PortDescriptors[i])) { + if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { + m_audioPortsIn.push_back(i); + } else { + m_audioPortsOut.push_back(i); + } + } else + if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i])) { + if (LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { + + LADSPA_Data *data = new LADSPA_Data(0.0); + + m_controlPortsIn.push_back(std::pair<unsigned long, LADSPA_Data*> + (i, data)); + + m_backupControlPortsIn.push_back(0.0); + m_portChangedSinceProgramChange.push_back(false); + + } else { + LADSPA_Data *data = new LADSPA_Data(0.0); + m_controlPortsOut.push_back( + std::pair<unsigned long, LADSPA_Data*>(i, data)); + if (!strcmp(descriptor->PortNames[i], "latency") || + !strcmp(descriptor->PortNames[i], "_latency")) { +#ifdef DEBUG_DSSI + std::cerr << "Wooo! We have a latency port!" << std::endl; +#endif + + m_latencyPort = data; + } + } + } +#ifdef DEBUG_DSSI + else + std::cerr << "DSSIPluginInstance::DSSIPluginInstance - " + << "unrecognised port type" << std::endl; +#endif + + } + + m_outputBufferCount = std::max(m_idealChannelCount, m_audioPortsOut.size()); +} + +size_t +DSSIPluginInstance::getLatency() +{ +#ifdef DEBUG_DSSI + // std::cerr << "DSSIPluginInstance::getLatency(): m_latencyPort " << m_latencyPort << ", m_run " << m_run << std::endl; +#endif + + if (m_latencyPort) { + if (!m_run) { + for (int i = 0; i < getAudioInputCount(); ++i) { + for (int j = 0; j < m_blockSize; ++j) { + m_inputBuffers[i][j] = 0.f; + } + } + run(RealTime::zeroTime); + } +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::getLatency(): latency is " << (size_t)(*m_latencyPort + 0.1) << std::endl; +#endif + + return (size_t)(*m_latencyPort + 0.1); + } + return 0; +} + +void +DSSIPluginInstance::silence() +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::silence: m_run " << m_run << ", m_runSinceReset " << m_runSinceReset << std::endl; +#endif + + if (m_run && !m_runSinceReset) { + return ; + } + if (m_instanceHandle != 0) { + deactivate(); + activate(); + } + m_runSinceReset = false; +} + +void +DSSIPluginInstance::discardEvents() +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::discardEvents" << std::endl; +#endif + + m_eventBuffer.reset(); +} + +void +DSSIPluginInstance::setIdealChannelCount(size_t channels) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::setIdealChannelCount: channel count " + << channels << " (was " << m_idealChannelCount << ")" << std::endl; +#endif + + if (channels == m_idealChannelCount) { + silence(); + return ; + } + + if (m_instanceHandle != 0) { + deactivate(); + } + + m_idealChannelCount = channels; + + if (channels > m_outputBufferCount) { + + for (size_t i = 0; i < m_outputBufferCount; ++i) { + delete[] m_outputBuffers[i]; + } + + delete[] m_outputBuffers; + + m_outputBufferCount = channels; + + m_outputBuffers = new sample_t * [m_outputBufferCount]; + + for (size_t i = 0; i < m_outputBufferCount; ++i) { + m_outputBuffers[i] = new sample_t[m_blockSize]; + } + + connectPorts(); + } + + if (m_instanceHandle != 0) { + activate(); + } +} + +void +DSSIPluginInstance::detachFromGroup() +{ + if (!m_grouped) + return ; + m_groupMap[m_identifier].erase(this); + m_grouped = false; +} + +void +DSSIPluginInstance::initialiseGroupMembership() +{ + if (!m_descriptor->run_multiple_synths) { + m_grouped = false; + return ; + } + + //!!! GroupMap is not actually thread-safe. + + size_t pluginsInGroup = m_groupMap[m_identifier].size(); + + if (++pluginsInGroup > m_groupLocalEventBufferCount) { + + size_t nextBufferCount = pluginsInGroup * 2; + + snd_seq_event_t **eventLocalBuffers = new snd_seq_event_t * [nextBufferCount]; + + for (size_t i = 0; i < m_groupLocalEventBufferCount; ++i) { + eventLocalBuffers[i] = m_groupLocalEventBuffers[i]; + } + for (size_t i = m_groupLocalEventBufferCount; i < nextBufferCount; ++i) { + eventLocalBuffers[i] = new snd_seq_event_t[EVENT_BUFFER_SIZE]; + } + + if (m_groupLocalEventBuffers) { + m_bufferScavenger.claim(new ScavengerArrayWrapper<snd_seq_event_t *> + (m_groupLocalEventBuffers)); + } + + m_groupLocalEventBuffers = eventLocalBuffers; + m_groupLocalEventBufferCount = nextBufferCount; + } + + m_grouped = true; + m_groupMap[m_identifier].insert(this); +} + +DSSIPluginInstance::~DSSIPluginInstance() +{ +// std::cerr << "DSSIPluginInstance::~DSSIPluginInstance" << std::endl; + + detachFromGroup(); + + if (m_instanceHandle != 0) { + deactivate(); + } + + cleanup(); + + for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) + delete m_controlPortsIn[i].second; + + for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) + delete m_controlPortsOut[i].second; + + m_controlPortsIn.clear(); + m_controlPortsOut.clear(); + + if (m_ownBuffers) { + for (size_t i = 0; i < m_audioPortsIn.size(); ++i) { + delete[] m_inputBuffers[i]; + } + for (size_t i = 0; i < m_outputBufferCount; ++i) { + delete[] m_outputBuffers[i]; + } + + delete[] m_inputBuffers; + delete[] m_outputBuffers; + } + + m_audioPortsIn.clear(); + m_audioPortsOut.clear(); +} + + +void +DSSIPluginInstance::instantiate(unsigned long sampleRate) +{ +#ifdef DEBUG_DSSI + std::cout << "DSSIPluginInstance::instantiate - plugin unique id = " + << m_descriptor->LADSPA_Plugin->UniqueID << std::endl; +#endif + + if (!m_descriptor) + return ; + + const LADSPA_Descriptor *descriptor = m_descriptor->LADSPA_Plugin; + + if (!descriptor->instantiate) { + std::cerr << "Bad plugin: plugin id " << descriptor->UniqueID + << ":" << descriptor->Label + << " has no instantiate method!" << std::endl; + return ; + } + + m_instanceHandle = descriptor->instantiate(descriptor, sampleRate); + + if (m_instanceHandle) { + + if (m_descriptor->get_midi_controller_for_port) { + + for (unsigned long i = 0; i < descriptor->PortCount; ++i) { + + if (LADSPA_IS_PORT_CONTROL(descriptor->PortDescriptors[i]) && + LADSPA_IS_PORT_INPUT(descriptor->PortDescriptors[i])) { + + int controller = m_descriptor->get_midi_controller_for_port + (m_instanceHandle, i); + + if (controller != 0 && controller != 32 && + DSSI_IS_CC(controller)) { + + m_controllerMap[DSSI_CC_NUMBER(controller)] = i; + } + } + } + } + } +} + +void +DSSIPluginInstance::checkProgramCache() +{ + if (m_programCacheValid) + return ; + m_cachedPrograms.clear(); + +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::checkProgramCache" << std::endl; +#endif + + if (!m_descriptor || !m_descriptor->get_program) { + m_programCacheValid = true; + return ; + } + + unsigned long index = 0; + const DSSI_Program_Descriptor *programDescriptor; + while ((programDescriptor = m_descriptor->get_program(m_instanceHandle, index))) { + ++index; + ProgramDescriptor d; + d.bank = programDescriptor->Bank; + d.program = programDescriptor->Program; + d.name = QString("%1. %2").arg(index).arg(programDescriptor->Name); + m_cachedPrograms.push_back(d); + } + +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::checkProgramCache: have " << m_cachedPrograms.size() << " programs" << std::endl; +#endif + + m_programCacheValid = true; +} + +QStringList +DSSIPluginInstance::getPrograms() +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::getPrograms" << std::endl; +#endif + + if (!m_descriptor) + return QStringList(); + + checkProgramCache(); + + QStringList programs; + + for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); + i != m_cachedPrograms.end(); ++i) { + programs.push_back(i->name); + } + + return programs; +} + +QString +DSSIPluginInstance::getProgram(int bank, int program) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::getProgram(" << bank << "," << program << ")" << std::endl; +#endif + + if (!m_descriptor) + return QString(); + + checkProgramCache(); + + for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); + i != m_cachedPrograms.end(); ++i) { + if (i->bank == bank && i->program == program) + return i->name; + } + + return QString(); +} + +unsigned long +DSSIPluginInstance::getProgram(QString name) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::getProgram(" << name << ")" << std::endl; +#endif + + if (!m_descriptor) + return 0; + + checkProgramCache(); + + unsigned long rv; + + for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); + i != m_cachedPrograms.end(); ++i) { + if (i->name == name) { + rv = i->bank; + rv = (rv << 16) + i->program; + return rv; + } + } + + return 0; +} + +QString +DSSIPluginInstance::getCurrentProgram() +{ + return m_program; +} + +void +DSSIPluginInstance::selectProgram(QString program) +{ + selectProgramAux(program, true); +} + +void +DSSIPluginInstance::selectProgramAux(QString program, bool backupPortValues) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance[" << this << "]::selectProgram(" << program << ", " << backupPortValues << ")" << std::endl; +#endif + + if (!m_descriptor) + return ; + + checkProgramCache(); + + if (!m_descriptor->select_program) + return ; + + bool found = false; + unsigned long bankNo = 0, programNo = 0; + + for (std::vector<ProgramDescriptor>::iterator i = m_cachedPrograms.begin(); + i != m_cachedPrograms.end(); ++i) { + + if (i->name == program) { + + bankNo = i->bank; + programNo = i->program; + found = true; + +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::selectProgram(" << program << "): found at bank " << bankNo << ", program " << programNo << std::endl; +#endif + + break; + } + } + + if (!found) + return ; + m_program = program; + + // DSSI select_program is an audio context call + pthread_mutex_lock(&m_processLock); + m_descriptor->select_program(m_instanceHandle, bankNo, programNo); + pthread_mutex_unlock(&m_processLock); + +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::selectProgram(" << program << "): made select_program(" << bankNo << "," << programNo << ") call" << std::endl; +#endif + + if (backupPortValues) { + for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { + m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; + m_portChangedSinceProgramChange[i] = false; + } + } +} + +void +DSSIPluginInstance::activate() +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance[" << this << "]::activate" << std::endl; +#endif + + if (!m_descriptor || !m_descriptor->LADSPA_Plugin->activate) + return ; + m_descriptor->LADSPA_Plugin->activate(m_instanceHandle); + + for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { + if (m_portChangedSinceProgramChange[i]) { +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::activate: setting port " << m_controlPortsIn[i].first << " to " << m_backupControlPortsIn[i] << std::endl; +#endif + + *m_controlPortsIn[i].second = m_backupControlPortsIn[i]; + } + } + + if (m_program) { +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::activate: restoring program " << m_program << std::endl; +#endif + + selectProgramAux(m_program, false); + + for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { + if (m_portChangedSinceProgramChange[i]) { +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::activate: setting port " << m_controlPortsIn[i].first << " to " << m_backupControlPortsIn[i] << std::endl; +#endif + + *m_controlPortsIn[i].second = m_backupControlPortsIn[i]; + } + } + } +} + +void +DSSIPluginInstance::connectPorts() +{ + if (!m_descriptor || !m_descriptor->LADSPA_Plugin->connect_port) + return ; +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::connectPorts: " << m_audioPortsIn.size() + << " audio ports in, " << m_audioPortsOut.size() << " out, " + << m_outputBufferCount << " output buffers" << std::endl; +#endif + + assert(sizeof(LADSPA_Data) == sizeof(float)); + assert(sizeof(sample_t) == sizeof(float)); + + int inbuf = 0, outbuf = 0; + + for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) { + m_descriptor->LADSPA_Plugin->connect_port + (m_instanceHandle, + m_audioPortsIn[i], + (LADSPA_Data *)m_inputBuffers[inbuf]); + ++inbuf; + } + + for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) { + m_descriptor->LADSPA_Plugin->connect_port + (m_instanceHandle, + m_audioPortsOut[i], + (LADSPA_Data *)m_outputBuffers[outbuf]); + ++outbuf; + } + + for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { + m_descriptor->LADSPA_Plugin->connect_port + (m_instanceHandle, + m_controlPortsIn[i].first, + m_controlPortsIn[i].second); + } + + for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) { + m_descriptor->LADSPA_Plugin->connect_port + (m_instanceHandle, + m_controlPortsOut[i].first, + m_controlPortsOut[i].second); + } +} + +void +DSSIPluginInstance::setPortValue(unsigned int portNumber, float value) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance[" << this << "]::setPortValue(" << portNumber << ") to " << value << std::endl; +#endif + + for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { + if (m_controlPortsIn[i].first == portNumber) { + LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory); + if (f) { + if (value < f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber)) { + value = f->getPortMinimum(m_descriptor->LADSPA_Plugin, portNumber); + } + if (value > f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber)) { + value = f->getPortMaximum(m_descriptor->LADSPA_Plugin, portNumber); + } + } + (*m_controlPortsIn[i].second) = value; + m_backupControlPortsIn[i] = value; + m_portChangedSinceProgramChange[i] = true; + } + } +} + +void +DSSIPluginInstance::setPortValueFromController(unsigned int port, int cv) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::setPortValueFromController(" << port << ") to " << cv << std::endl; +#endif + + const LADSPA_Descriptor *p = m_descriptor->LADSPA_Plugin; + LADSPA_PortRangeHintDescriptor d = p->PortRangeHints[port].HintDescriptor; + LADSPA_Data lb = p->PortRangeHints[port].LowerBound; + LADSPA_Data ub = p->PortRangeHints[port].UpperBound; + + float value = (float)cv; + + if (!LADSPA_IS_HINT_BOUNDED_BELOW(d)) { + if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { + /* unbounded: might as well leave the value alone. */ + } else { + /* bounded above only. just shift the range. */ + value = ub - 127.0f + value; + } + } else { + if (!LADSPA_IS_HINT_BOUNDED_ABOVE(d)) { + /* bounded below only. just shift the range. */ + value = lb + value; + } else { + /* bounded both ends. more interesting. */ + /* XXX !!! todo: fill in logarithmic, sample rate &c */ + value = lb + ((ub - lb) * value / 127.0f); + } + } + + setPortValue(port, value); +} + +float +DSSIPluginInstance::getPortValue(unsigned int portNumber) +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::getPortValue(" << portNumber << ")" << std::endl; +#endif + + for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { + if (m_controlPortsIn[i].first == portNumber) { + return (*m_controlPortsIn[i].second); + } + } + + return 0.0; +} + +QString +DSSIPluginInstance::configure(QString key, + QString value) +{ + if (!m_descriptor || !m_descriptor->configure) + return QString(); + + if (key == PluginIdentifier::RESERVED_PROJECT_DIRECTORY_KEY) { +#ifdef DSSI_PROJECT_DIRECTORY_KEY + key = DSSI_PROJECT_DIRECTORY_KEY; +#else + + return QString(); +#endif + + } + + +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::configure(" << key << "," << value << ")" << std::endl; +#endif + + char *message = m_descriptor->configure(m_instanceHandle, key.data(), value.data()); + + m_programCacheValid = false; + + QString qm; + + // Ignore return values from reserved key configuration calls such + // as project directory +#ifdef DSSI_RESERVED_CONFIGURE_PREFIX + + if (key.startsWith(DSSI_RESERVED_CONFIGURE_PREFIX)) { + return qm; + } +#endif + + if (message) { + if (m_descriptor->LADSPA_Plugin && m_descriptor->LADSPA_Plugin->Label) { + qm = QString(m_descriptor->LADSPA_Plugin->Label) + ": "; + } + qm = qm + message; + free(message); + } + + return qm; +} + +void +DSSIPluginInstance::sendEvent(const RealTime &eventTime, + const void *e) +{ + snd_seq_event_t *event = (snd_seq_event_t *)e; +#ifdef DEBUG_DSSI_PROCESS + + std::cerr << "DSSIPluginInstance::sendEvent at " << eventTime << std::endl; +#endif + + snd_seq_event_t ev(*event); + + ev.time.time.tv_sec = eventTime.sec; + ev.time.time.tv_nsec = eventTime.nsec; + + // DSSI doesn't use MIDI channels, it uses run_multiple_synths instead. + ev.data.note.channel = 0; + + m_eventBuffer.write(&ev, 1); +} + +bool +DSSIPluginInstance::handleController(snd_seq_event_t *ev) +{ + int controller = ev->data.control.param; + +#ifdef DEBUG_DSSI_PROCESS + + std::cerr << "DSSIPluginInstance::handleController " << controller << std::endl; +#endif + + if (controller == 0) { // bank select MSB + + m_pending.msb = ev->data.control.value; + + } else if (controller == 32) { // bank select LSB + + m_pending.lsb = ev->data.control.value; + + } else if (controller > 0 && controller < 128) { + + if (m_controllerMap.find(controller) != m_controllerMap.end()) { + int port = m_controllerMap[controller]; + setPortValueFromController(port, ev->data.control.value); + } else { + return true; // pass through to plugin + } + } + + return false; +} + +void +DSSIPluginInstance::run(const RealTime &blockTime) +{ + static snd_seq_event_t localEventBuffer[EVENT_BUFFER_SIZE]; + int evCount = 0; + + bool needLock = false; + if (m_descriptor->select_program) + needLock = true; + + if (needLock) { + if (pthread_mutex_trylock(&m_processLock) != 0) { + for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { + memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); + } + return ; + } + } + + if (m_grouped) { + runGrouped(blockTime); + goto done; + } + + if (!m_descriptor || !m_descriptor->run_synth) { + m_eventBuffer.skip(m_eventBuffer.getReadSpace()); + if (m_descriptor->LADSPA_Plugin->run) { + m_descriptor->LADSPA_Plugin->run(m_instanceHandle, m_blockSize); + } else { + for (size_t ch = 0; ch < m_audioPortsOut.size(); ++ch) { + memset(m_outputBuffers[ch], 0, m_blockSize * sizeof(sample_t)); + } + } + m_run = true; + m_runSinceReset = true; + if (needLock) + pthread_mutex_unlock(&m_processLock); + return ; + } + +#ifdef DEBUG_DSSI_PROCESS + std::cerr << "DSSIPluginInstance::run(" << blockTime << ")" << std::endl; +#endif + +#ifdef DEBUG_DSSI_PROCESS + + if (m_eventBuffer.getReadSpace() > 0) { + std::cerr << "DSSIPluginInstance::run: event buffer has " + << m_eventBuffer.getReadSpace() << " event(s) in it" << std::endl; + } +#endif + + while (m_eventBuffer.getReadSpace() > 0) { + + snd_seq_event_t *ev = localEventBuffer + evCount; + *ev = m_eventBuffer.peek(); + bool accept = true; + + RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); + + int frameOffset = 0; + if (evTime > blockTime) { + frameOffset = RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); + } + +#ifdef DEBUG_DSSI_PROCESS + std::cerr << "DSSIPluginInstance::run: evTime " << evTime << ", blockTime " << blockTime << ", frameOffset " << frameOffset + << ", blockSize " << m_blockSize << std::endl; + std::cerr << "Type: " << int(ev->type) << ", pitch: " << int(ev->data.note.note) << ", velocity: " << int(ev->data.note.velocity) << std::endl; +#endif + + if (frameOffset >= int(m_blockSize)) + break; + if (frameOffset < 0) + frameOffset = 0; + + ev->time.tick = frameOffset; + m_eventBuffer.skip(1); + + if (ev->type == SND_SEQ_EVENT_CONTROLLER) { + accept = handleController(ev); + } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { + m_pending.program = ev->data.control.value; + accept = false; + } + + if (accept) { + if (++evCount >= EVENT_BUFFER_SIZE) + break; + } + } + + if (m_pending.program >= 0 && m_descriptor->select_program) { + + int program = m_pending.program; + int bank = m_pending.lsb + 128 * m_pending.msb; + +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::run: making select_program(" << bank << "," << program << " call" << std::endl; +#endif + + m_pending.lsb = m_pending.msb = m_pending.program = -1; + m_descriptor->select_program(m_instanceHandle, bank, program); + +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::run: made select_program(" << bank << "," << program << " call" << std::endl; +#endif + + } + +#ifdef DEBUG_DSSI_PROCESS + std::cerr << "DSSIPluginInstance::run: running with " << evCount << " events" + << std::endl; +#endif + + m_descriptor->run_synth(m_instanceHandle, m_blockSize, + localEventBuffer, evCount); + +#ifdef DEBUG_DSSI_PROCESS + // for (int i = 0; i < m_blockSize; ++i) { + // std::cout << m_outputBuffers[0][i] << " "; + // if (i % 8 == 0) std::cout << std::endl; + // } +#endif + +done: + if (needLock) + pthread_mutex_unlock(&m_processLock); + + if (m_audioPortsOut.size() == 0) { + // copy inputs to outputs + for (size_t ch = 0; ch < m_idealChannelCount; ++ch) { + size_t sch = ch % m_audioPortsIn.size(); + for (size_t i = 0; i < m_blockSize; ++i) { + m_outputBuffers[ch][i] = m_inputBuffers[sch][i]; + } + } + } else if (m_idealChannelCount < m_audioPortsOut.size()) { + if (m_idealChannelCount == 1) { + // mix down to mono + for (size_t ch = 1; ch < m_audioPortsOut.size(); ++ch) { + for (size_t i = 0; i < m_blockSize; ++i) { + m_outputBuffers[0][i] += m_outputBuffers[ch][i]; + } + } + } + } else if (m_idealChannelCount > m_audioPortsOut.size()) { + // duplicate + for (size_t ch = m_audioPortsOut.size(); ch < m_idealChannelCount; ++ch) { + size_t sch = (ch - m_audioPortsOut.size()) % m_audioPortsOut.size(); + for (size_t i = 0; i < m_blockSize; ++i) { + m_outputBuffers[ch][i] = m_outputBuffers[sch][i]; + } + } + } + + m_lastRunTime = blockTime; + m_run = true; + m_runSinceReset = true; +} + +void +DSSIPluginInstance::runGrouped(const RealTime &blockTime) +{ + // If something else in our group has just been called for this + // block time (but we haven't) then we should just write out the + // results and return; if we have just been called for this block + // time or nothing else in the group has been, we should run the + // whole group. + + bool needRun = true; + + PluginSet &s = m_groupMap[m_identifier]; + +#ifdef DEBUG_DSSI_PROCESS + + std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): this is " << this << "; " << s.size() << " elements in m_groupMap[" << m_identifier << "]" << std::endl; +#endif + + if (m_lastRunTime != blockTime) { + for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { + DSSIPluginInstance *instance = *i; + if (instance != this && instance->m_lastRunTime == blockTime) { +#ifdef DEBUG_DSSI_PROCESS + std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): plugin " << instance << " has already been run" << std::endl; +#endif + + needRun = false; + } + } + } + + if (!needRun) { +#ifdef DEBUG_DSSI_PROCESS + std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): already run, returning" << std::endl; +#endif + + return ; + } + +#ifdef DEBUG_DSSI_PROCESS + std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): I'm the first, running" << std::endl; +#endif + + size_t index = 0; + unsigned long *counts = (unsigned long *) + alloca(m_groupLocalEventBufferCount * sizeof(unsigned long)); + LADSPA_Handle *instances = (LADSPA_Handle *) + alloca(m_groupLocalEventBufferCount * sizeof(LADSPA_Handle)); + + for (PluginSet::iterator i = s.begin(); i != s.end(); ++i) { + + if (index >= m_groupLocalEventBufferCount) + break; + + DSSIPluginInstance *instance = *i; + counts[index] = 0; + instances[index] = instance->m_instanceHandle; + +#ifdef DEBUG_DSSI_PROCESS + + std::cerr << "DSSIPluginInstance::runGrouped(" << blockTime << "): running " << instance << std::endl; +#endif + + if (instance->m_pending.program >= 0 && + instance->m_descriptor->select_program) { + int program = instance->m_pending.program; + int bank = instance->m_pending.lsb + 128 * instance->m_pending.msb; + instance->m_pending.lsb = instance->m_pending.msb = instance->m_pending.program = -1; + instance->m_descriptor->select_program + (instance->m_instanceHandle, bank, program); + } + + while (instance->m_eventBuffer.getReadSpace() > 0) { + + snd_seq_event_t *ev = m_groupLocalEventBuffers[index] + counts[index]; + *ev = instance->m_eventBuffer.peek(); + bool accept = true; + + RealTime evTime(ev->time.time.tv_sec, ev->time.time.tv_nsec); + + int frameOffset = 0; + if (evTime > blockTime) { + frameOffset = RealTime::realTime2Frame(evTime - blockTime, m_sampleRate); + } + +#ifdef DEBUG_DSSI_PROCESS + std::cerr << "DSSIPluginInstance::runGrouped: evTime " << evTime << ", frameOffset " << frameOffset + << ", block size " << m_blockSize << std::endl; +#endif + + if (frameOffset >= int(m_blockSize)) + break; + if (frameOffset < 0) + frameOffset = 0; + + ev->time.tick = frameOffset; + instance->m_eventBuffer.skip(1); + + if (ev->type == SND_SEQ_EVENT_CONTROLLER) { + accept = instance->handleController(ev); + } else if (ev->type == SND_SEQ_EVENT_PGMCHANGE) { + instance->m_pending.program = ev->data.control.value; + accept = false; + } + + if (accept) { + if (++counts[index] >= EVENT_BUFFER_SIZE) + break; + } + } + + ++index; + } + + m_descriptor->run_multiple_synths(index, + instances, + m_blockSize, + m_groupLocalEventBuffers, + counts); +} + + +void +DSSIPluginInstance::deactivate() +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::deactivate " << m_identifier << std::endl; +#endif + + if (!m_descriptor || !m_descriptor->LADSPA_Plugin->deactivate) + return ; + + for (size_t i = 0; i < m_backupControlPortsIn.size(); ++i) { + m_backupControlPortsIn[i] = *m_controlPortsIn[i].second; + } + + m_descriptor->LADSPA_Plugin->deactivate(m_instanceHandle); +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::deactivate " << m_identifier << " done" << std::endl; +#endif + + m_bufferScavenger.scavenge(); +} + +void +DSSIPluginInstance::cleanup() +{ +#ifdef DEBUG_DSSI + std::cerr << "DSSIPluginInstance::cleanup " << m_identifier << std::endl; +#endif + + if (!m_descriptor) + return ; + + if (!m_descriptor->LADSPA_Plugin->cleanup) { + std::cerr << "Bad plugin: plugin id " + << m_descriptor->LADSPA_Plugin->UniqueID + << ":" << m_descriptor->LADSPA_Plugin->Label + << " has no cleanup method!" << std::endl; + return ; + } + + m_descriptor->LADSPA_Plugin->cleanup(m_instanceHandle); + m_instanceHandle = 0; +#ifdef DEBUG_DSSI + + std::cerr << "DSSIPluginInstance::cleanup " << m_identifier << " done" << std::endl; +#endif +} + + + +} + +#endif // HAVE_DSSI + + |