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@202: This file copyright 2000-2006 Chris Cannam, Richard Bown, and QMUL. Chris@0: */ Chris@0: Chris@0: #include Chris@0: #include Chris@0: Chris@0: #include "LADSPAPluginInstance.h" Chris@0: #include "LADSPAPluginFactory.h" Chris@0: Chris@166: #ifdef HAVE_LRDF Chris@166: #include "lrdf.h" Chris@166: #endif // HAVE_LRDF Chris@166: Chris@117: //#define DEBUG_LADSPA 1 Chris@0: Chris@259: #include Chris@259: Chris@0: Chris@0: LADSPAPluginInstance::LADSPAPluginInstance(RealTimePluginFactory *factory, Chris@1429: int clientId, Chris@1429: QString identifier, Chris@0: int position, Chris@1429: sv_samplerate_t sampleRate, Chris@1429: int blockSize, Chris@1429: int idealChannelCount, Chris@0: const LADSPA_Descriptor* descriptor) : Chris@0: RealTimePluginInstance(factory, identifier), Chris@0: m_client(clientId), Chris@0: m_position(position), Chris@0: m_instanceCount(0), Chris@0: m_descriptor(descriptor), Chris@0: m_blockSize(blockSize), Chris@0: m_sampleRate(sampleRate), Chris@1582: m_latencyPort(nullptr), Chris@0: m_run(false), Chris@0: m_bypassed(false) Chris@0: { Chris@0: init(idealChannelCount); Chris@0: Chris@176: if (m_audioPortsIn.size() == 0) { Chris@1582: m_inputBuffers = nullptr; Chris@176: } else { Chris@176: m_inputBuffers = new sample_t*[m_instanceCount * m_audioPortsIn.size()]; Chris@176: } Chris@176: Chris@176: if (m_audioPortsOut.size() == 0) { Chris@1582: m_outputBuffers = nullptr; Chris@176: } else { Chris@176: m_outputBuffers = new sample_t*[m_instanceCount * m_audioPortsOut.size()]; Chris@176: } Chris@0: Chris@0: for (size_t i = 0; i < m_instanceCount * m_audioPortsIn.size(); ++i) { Chris@1429: m_inputBuffers[i] = new sample_t[blockSize]; Chris@0: } Chris@0: for (size_t i = 0; i < m_instanceCount * m_audioPortsOut.size(); ++i) { Chris@1429: m_outputBuffers[i] = new sample_t[blockSize]; Chris@0: } Chris@0: Chris@0: m_ownBuffers = true; Chris@0: Chris@0: instantiate(sampleRate); Chris@0: if (isOK()) { Chris@1429: connectPorts(); Chris@1429: activate(); Chris@0: } Chris@0: } Chris@0: Chris@51: std::string Chris@239: LADSPAPluginInstance::getIdentifier() const Chris@239: { Chris@239: return m_descriptor->Label; Chris@239: } Chris@239: Chris@239: std::string Chris@51: LADSPAPluginInstance::getName() const Chris@0: { Chris@239: return m_descriptor->Name; Chris@0: } Chris@0: Chris@51: std::string Chris@51: LADSPAPluginInstance::getDescription() const Chris@51: { Chris@239: return ""; Chris@51: } Chris@51: Chris@51: std::string Chris@51: LADSPAPluginInstance::getMaker() const Chris@51: { Chris@51: return m_descriptor->Maker; Chris@51: } Chris@51: Chris@51: int Chris@51: LADSPAPluginInstance::getPluginVersion() const Chris@51: { Chris@473: return -1; Chris@51: } Chris@51: Chris@51: std::string Chris@51: LADSPAPluginInstance::getCopyright() const Chris@51: { Chris@51: return m_descriptor->Copyright; Chris@51: } Chris@51: Chris@51: LADSPAPluginInstance::ParameterList Chris@51: LADSPAPluginInstance::getParameterDescriptors() const Chris@51: { Chris@51: ParameterList list; Chris@51: LADSPAPluginFactory *f = dynamic_cast(m_factory); Chris@973: if (!f) return list; 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->PortNames[pn]; Chris@239: pd.name = pd.identifier; Chris@239: pd.description = ""; Chris@51: pd.minValue = f->getPortMinimum(m_descriptor, pn); Chris@51: pd.maxValue = f->getPortMaximum(m_descriptor, pn); Chris@51: pd.defaultValue = f->getPortDefault(m_descriptor, pn); Chris@57: Chris@57: float q = f->getPortQuantization(m_descriptor, 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@166: bool haveLabels = false; Chris@166: Chris@166: #ifdef HAVE_LRDF Chris@166: if (pd.isQuantized && pd.quantizeStep == 1.0) { Chris@166: Chris@166: lrdf_defaults *defaults = Chris@166: lrdf_get_scale_values(m_descriptor->UniqueID, pn); Chris@166: Chris@166: if (defaults) { Chris@166: if (defaults->count > 0) { Chris@166: std::map values; Chris@1039: int v = 0; Chris@166: for (size_t i = 0; i < defaults->count; ++i) { Chris@1039: v = int(lrintf(fabsf(defaults->items[i].value))); Chris@166: values[v] = defaults->items[i].label; Chris@166: } Chris@1039: for (int i = 0; i <= v; ++i) { Chris@166: pd.valueNames.push_back(values[i]); Chris@166: } Chris@166: haveLabels = true; Chris@166: } Chris@166: lrdf_free_setting_values(defaults); Chris@166: } Chris@166: } Chris@166: #endif Chris@166: Chris@166: if (haveLabels) { Chris@239: pd.name = QString(pd.name.c_str()) Chris@166: .replace(QRegExp("\\([^\\(\\)]+=[^\\(\\)]+\\)$"), "") Chris@166: .toStdString(); Chris@166: } else { Chris@166: static QRegExp unitRE("[\\[\\(]([A-Za-z0-9/]+)[\\)\\]]$"); Chris@166: if (unitRE.indexIn(pd.name.c_str()) >= 0) { Chris@166: pd.unit = unitRE.cap(1).toStdString(); Chris@239: pd.name = QString(pd.name.c_str()) Chris@166: .replace(unitRE, "").toStdString(); Chris@166: } Chris@166: } Chris@166: Chris@51: list.push_back(pd); Chris@51: } Chris@51: Chris@51: return list; Chris@51: } Chris@51: Chris@51: float Chris@239: LADSPAPluginInstance::getParameter(std::string id) const Chris@51: { Chris@51: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { Chris@239: if (id == m_descriptor->PortNames[m_controlPortsIn[i].first]) { Chris@51: return getParameterValue(i); Chris@51: } Chris@51: } Chris@51: Chris@51: return 0.0; Chris@51: } Chris@51: Chris@51: void Chris@239: LADSPAPluginInstance::setParameter(std::string id, float value) Chris@51: { Chris@51: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { Chris@239: if (id == m_descriptor->PortNames[m_controlPortsIn[i].first]) { Chris@242: #ifdef DEBUG_LADSPA Chris@690: SVDEBUG << "LADSPAPluginInstance::setParameter: Found id " Chris@687: << id << " at control port " << i << endl; Chris@242: #endif Chris@51: setParameterValue(i, value); Chris@51: break; Chris@51: } Chris@51: } Chris@51: } Chris@0: Chris@0: void Chris@0: LADSPAPluginInstance::init(int idealChannelCount) Chris@0: { Chris@0: #ifdef DEBUG_LADSPA Chris@690: SVDEBUG << "LADSPAPluginInstance::init(" << idealChannelCount << "): plugin has " Chris@1429: << m_descriptor->PortCount << " ports" << endl; Chris@0: #endif Chris@0: Chris@0: // Discover ports numbers and identities Chris@0: // Chris@1039: for (int i = 0; i < (int)m_descriptor->PortCount; ++i) { Chris@242: Chris@242: if (LADSPA_IS_PORT_AUDIO(m_descriptor->PortDescriptors[i])) { Chris@242: Chris@0: if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[i])) { Chris@0: #ifdef DEBUG_LADSPA Chris@1429: SVDEBUG << "LADSPAPluginInstance::init: port " << i << " is audio in" << endl; Chris@0: #endif Chris@0: m_audioPortsIn.push_back(i); Chris@1429: } else { Chris@0: #ifdef DEBUG_LADSPA Chris@1429: SVDEBUG << "LADSPAPluginInstance::init: port " << i << " is audio out" << endl; Chris@0: #endif Chris@0: m_audioPortsOut.push_back(i); Chris@1429: } Chris@242: Chris@242: } else if (LADSPA_IS_PORT_CONTROL(m_descriptor->PortDescriptors[i])) { Chris@242: Chris@1429: if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[i])) { Chris@242: Chris@0: #ifdef DEBUG_LADSPA Chris@1429: SVDEBUG << "LADSPAPluginInstance::init: port " << i << " is control in" << endl; Chris@0: #endif Chris@1429: LADSPA_Data *data = new LADSPA_Data(0.0); Chris@1429: m_controlPortsIn.push_back( Chris@0: std::pair(i, data)); Chris@242: Chris@1429: } else { Chris@242: Chris@0: #ifdef DEBUG_LADSPA Chris@1429: SVDEBUG << "LADSPAPluginInstance::init: port " << i << " is control out" << endl; Chris@0: #endif Chris@1429: LADSPA_Data *data = new LADSPA_Data(0.0); Chris@1429: m_controlPortsOut.push_back( Chris@0: std::pair(i, data)); Chris@1429: if (!strcmp(m_descriptor->PortNames[i], "latency") || Chris@1429: !strcmp(m_descriptor->PortNames[i], "_latency")) { Chris@0: #ifdef DEBUG_LADSPA Chris@1429: cerr << "Wooo! We have a latency port!" << endl; Chris@0: #endif Chris@1429: m_latencyPort = data; Chris@1429: } Chris@242: Chris@1429: } Chris@0: } Chris@0: #ifdef DEBUG_LADSPA Chris@0: else Chris@690: SVDEBUG << "LADSPAPluginInstance::init - " Chris@687: << "unrecognised port type" << endl; Chris@0: #endif Chris@0: } Chris@0: Chris@0: m_instanceCount = 1; Chris@0: Chris@0: if (idealChannelCount > 0) { Chris@1429: if (m_audioPortsIn.size() == 1) { Chris@1429: // mono plugin: duplicate it if need be Chris@1429: m_instanceCount = idealChannelCount; Chris@1429: } Chris@0: } Chris@0: } Chris@0: Chris@1040: sv_frame_t Chris@0: LADSPAPluginInstance::getLatency() Chris@0: { Chris@0: if (m_latencyPort) { Chris@1429: if (!m_run) { Chris@1040: for (int i = 0; i < getAudioInputCount(); ++i) { Chris@1040: for (int 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@1429: if (*m_latencyPort > 0) return (sv_frame_t)*m_latencyPort; Chris@0: } Chris@0: return 0; Chris@0: } Chris@0: Chris@0: void Chris@0: LADSPAPluginInstance::silence() Chris@0: { Chris@0: if (isOK()) { Chris@1429: deactivate(); Chris@1429: activate(); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@1040: LADSPAPluginInstance::setIdealChannelCount(int channels) Chris@0: { Chris@0: if (m_audioPortsIn.size() != 1 || channels == m_instanceCount) { Chris@1429: silence(); Chris@1429: return; Chris@0: } Chris@0: Chris@0: if (isOK()) { Chris@1429: deactivate(); Chris@0: } Chris@0: Chris@0: //!!! don't we need to reallocate inputBuffers and outputBuffers? Chris@0: Chris@0: cleanup(); Chris@0: m_instanceCount = channels; Chris@0: instantiate(m_sampleRate); Chris@0: if (isOK()) { Chris@1429: connectPorts(); Chris@1429: activate(); Chris@0: } Chris@0: } Chris@0: Chris@0: Chris@0: LADSPAPluginInstance::~LADSPAPluginInstance() Chris@0: { Chris@0: #ifdef DEBUG_LADSPA Chris@690: SVDEBUG << "LADSPAPluginInstance::~LADSPAPluginInstance" << endl; Chris@0: #endif Chris@0: Chris@0: if (m_instanceHandles.size() != 0) { // "isOK()" Chris@1429: 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@1429: for (size_t i = 0; i < m_instanceCount * m_audioPortsIn.size(); ++i) { Chris@1429: delete[] m_inputBuffers[i]; Chris@1429: } Chris@1429: for (size_t i = 0; i < m_instanceCount * m_audioPortsOut.size(); ++i) { Chris@1429: delete[] m_outputBuffers[i]; Chris@1429: } Chris@0: Chris@1429: delete[] m_inputBuffers; Chris@1429: 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@1040: LADSPAPluginInstance::instantiate(sv_samplerate_t sampleRate) Chris@0: { Chris@724: if (!m_descriptor) return; Chris@724: Chris@0: #ifdef DEBUG_LADSPA Chris@843: cout << "LADSPAPluginInstance::instantiate - plugin unique id = " Chris@843: << m_descriptor->UniqueID << endl; Chris@0: #endif Chris@0: Chris@0: if (!m_descriptor->instantiate) { Chris@1429: cerr << "Bad plugin: plugin id " << m_descriptor->UniqueID Chris@1429: << ":" << m_descriptor->Label Chris@1429: << " has no instantiate method!" << endl; Chris@1429: return; Chris@0: } Chris@0: Chris@1040: unsigned long pluginRate = (unsigned long)(sampleRate); Chris@1040: if (sampleRate != sv_samplerate_t(pluginRate)) { Chris@1040: cerr << "LADSPAPluginInstance: WARNING: Non-integer sample rate " Chris@1040: << sampleRate << " presented, rounding to " << pluginRate Chris@1040: << endl; Chris@1040: } Chris@1040: Chris@1040: for (int i = 0; i < m_instanceCount; ++i) { Chris@1429: m_instanceHandles.push_back Chris@1429: (m_descriptor->instantiate(m_descriptor, pluginRate)); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: LADSPAPluginInstance::activate() Chris@0: { Chris@0: if (!m_descriptor || !m_descriptor->activate) return; Chris@0: Chris@0: for (std::vector::iterator hi = m_instanceHandles.begin(); Chris@1429: hi != m_instanceHandles.end(); ++hi) { Chris@1429: m_descriptor->activate(*hi); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: LADSPAPluginInstance::connectPorts() Chris@0: { Chris@0: if (!m_descriptor || !m_descriptor->connect_port) return; Chris@0: Chris@0: assert(sizeof(LADSPA_Data) == sizeof(float)); Chris@0: assert(sizeof(sample_t) == sizeof(float)); Chris@0: Chris@57: LADSPAPluginFactory *f = dynamic_cast(m_factory); Chris@0: int inbuf = 0, outbuf = 0; Chris@0: Chris@0: for (std::vector::iterator hi = m_instanceHandles.begin(); Chris@1429: hi != m_instanceHandles.end(); ++hi) { Chris@0: Chris@1429: for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) { Chris@1429: m_descriptor->connect_port(*hi, Chris@1429: m_audioPortsIn[i], Chris@1429: (LADSPA_Data *)m_inputBuffers[inbuf]); Chris@1429: ++inbuf; Chris@1429: } Chris@0: Chris@1429: for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) { Chris@1429: m_descriptor->connect_port(*hi, Chris@1429: m_audioPortsOut[i], Chris@1429: (LADSPA_Data *)m_outputBuffers[outbuf]); Chris@1429: ++outbuf; Chris@1429: } Chris@0: Chris@1429: // If there is more than one instance, they all share the same Chris@1429: // control port ins (and outs, for the moment, because we Chris@1429: // don't actually do anything with the outs anyway -- but they Chris@1429: // do have to be connected as the plugin can't know if they're Chris@1429: // not and will write to them anyway). Chris@0: Chris@1429: for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) { Chris@1429: m_descriptor->connect_port(*hi, Chris@1429: m_controlPortsIn[i].first, Chris@1429: m_controlPortsIn[i].second); Chris@57: if (f) { Chris@57: float defaultValue = f->getPortDefault Chris@57: (m_descriptor, m_controlPortsIn[i].first); Chris@57: *m_controlPortsIn[i].second = defaultValue; Chris@57: } Chris@1429: } Chris@0: Chris@1429: for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) { Chris@1429: m_descriptor->connect_port(*hi, Chris@1429: m_controlPortsOut[i].first, Chris@1429: m_controlPortsOut[i].second); Chris@1429: } Chris@0: } Chris@0: } Chris@0: Chris@1039: int Chris@0: LADSPAPluginInstance::getParameterCount() const Chris@0: { Chris@1039: return (int)m_controlPortsIn.size(); Chris@0: } Chris@0: Chris@0: void Chris@1039: LADSPAPluginInstance::setParameterValue(int parameter, float value) Chris@0: { Chris@1039: if (!in_range_for(m_controlPortsIn, parameter)) 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@1429: if (value < f->getPortMinimum(m_descriptor, portNumber)) { Chris@1429: value = f->getPortMinimum(m_descriptor, portNumber); Chris@1429: } Chris@1429: if (value > f->getPortMaximum(m_descriptor, portNumber)) { Chris@1429: value = f->getPortMaximum(m_descriptor, portNumber); Chris@1429: } Chris@0: } Chris@0: Chris@0: (*m_controlPortsIn[parameter].second) = value; Chris@0: } Chris@0: Chris@0: float Chris@1040: LADSPAPluginInstance::getControlOutputValue(int output) const Chris@60: { Chris@1039: if (!in_range_for(m_controlPortsOut, output)) return 0.0; Chris@60: return (*m_controlPortsOut[output].second); Chris@60: } Chris@60: Chris@60: float Chris@1039: LADSPAPluginInstance::getParameterValue(int parameter) const Chris@0: { Chris@1039: if (!in_range_for(m_controlPortsIn, parameter)) return 0.0; Chris@0: return (*m_controlPortsIn[parameter].second); Chris@0: } Chris@0: Chris@0: float Chris@1039: LADSPAPluginInstance::getParameterDefault(int parameter) const Chris@0: { Chris@1039: if (!in_range_for(m_controlPortsIn, parameter)) return 0.0; Chris@0: Chris@0: LADSPAPluginFactory *f = dynamic_cast(m_factory); Chris@0: if (f) { Chris@1429: return f->getPortDefault(m_descriptor, m_controlPortsIn[parameter].first); Chris@0: } else { Chris@1429: return 0.0f; Chris@0: } Chris@0: } Chris@0: Chris@356: int Chris@1039: LADSPAPluginInstance::getParameterDisplayHint(int parameter) const Chris@356: { Chris@1039: if (!in_range_for(m_controlPortsIn, parameter)) return 0.0; Chris@356: Chris@356: LADSPAPluginFactory *f = dynamic_cast(m_factory); Chris@356: if (f) { Chris@1429: return f->getPortDisplayHint(m_descriptor, m_controlPortsIn[parameter].first); Chris@356: } else { Chris@1429: return PortHint::NoHint; Chris@356: } Chris@356: } Chris@356: Chris@0: void Chris@1040: LADSPAPluginInstance::run(const RealTime &, int count) Chris@0: { Chris@0: if (!m_descriptor || !m_descriptor->run) return; Chris@0: Chris@385: if (count == 0) count = m_blockSize; Chris@385: Chris@0: for (std::vector::iterator hi = m_instanceHandles.begin(); Chris@1429: hi != m_instanceHandles.end(); ++hi) { Chris@242: Chris@385: m_descriptor->run(*hi, count); Chris@0: } Chris@0: Chris@0: m_run = true; Chris@0: } Chris@0: Chris@0: void Chris@0: LADSPAPluginInstance::deactivate() Chris@0: { Chris@0: if (!m_descriptor || !m_descriptor->deactivate) return; Chris@0: Chris@0: for (std::vector::iterator hi = m_instanceHandles.begin(); Chris@1429: hi != m_instanceHandles.end(); ++hi) { Chris@0: m_descriptor->deactivate(*hi); Chris@0: } Chris@0: } Chris@0: Chris@0: void Chris@0: LADSPAPluginInstance::cleanup() Chris@0: { Chris@0: if (!m_descriptor) return; Chris@0: Chris@0: if (!m_descriptor->cleanup) { Chris@1429: cerr << "Bad plugin: plugin id " << m_descriptor->UniqueID Chris@1429: << ":" << m_descriptor->Label Chris@1429: << " has no cleanup method!" << endl; Chris@1429: return; Chris@0: } Chris@0: Chris@0: for (std::vector::iterator hi = m_instanceHandles.begin(); Chris@1429: hi != m_instanceHandles.end(); ++hi) { Chris@1429: m_descriptor->cleanup(*hi); Chris@0: } Chris@0: Chris@0: m_instanceHandles.clear(); Chris@0: } Chris@0: Chris@0: