view plugin/LADSPAPluginInstance.cpp @ 117:c30728d5625c sv1-v0.9rc1

* Make vertical scale alignment modes work in note layer as well as time-value layer, and several significant fixes to it * Make it possible to draw notes properly on the note layer * Show units (and frequencies etc in note layer's case) in the time-value and note layer description boxes * Minor fix to item edit dialog layout * Some minor menu rearrangement * Comment out a lot of debug output * Add SV website and reference URLs to Help menu, and add code to (attempt to) open them in the user's preferred browser
author Chris Cannam
date Fri, 12 May 2006 14:40:43 +0000
parents c983dda79f72
children 702fc936e6a6
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */

/*
    Sonic Visualiser
    An audio file viewer and annotation editor.
    Centre for Digital Music, Queen Mary, University of London.
    
    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.
*/

/*
   This is a modified version of a source file from the 
   Rosegarden MIDI and audio sequencer and notation editor.
   This file copyright 2000-2006 Chris Cannam and Richard Bown.
*/

#include <iostream>
#include <cassert>

#include "LADSPAPluginInstance.h"
#include "LADSPAPluginFactory.h"

//#define DEBUG_LADSPA 1


LADSPAPluginInstance::LADSPAPluginInstance(RealTimePluginFactory *factory,
					   int clientId,
					   QString identifier,
                                           int position,
					   unsigned long sampleRate,
					   size_t blockSize,
					   int idealChannelCount,
                                           const LADSPA_Descriptor* descriptor) :
    RealTimePluginInstance(factory, identifier),
    m_client(clientId),
    m_position(position),
    m_instanceCount(0),
    m_descriptor(descriptor),
    m_blockSize(blockSize),
    m_sampleRate(sampleRate),
    m_latencyPort(0),
    m_run(false),
    m_bypassed(false)
{
    init(idealChannelCount);

    m_inputBuffers  = new sample_t*[m_instanceCount * m_audioPortsIn.size()];
    m_outputBuffers = new sample_t*[m_instanceCount * m_audioPortsOut.size()];

    for (size_t i = 0; i < m_instanceCount * m_audioPortsIn.size(); ++i) {
	m_inputBuffers[i] = new sample_t[blockSize];
    }
    for (size_t i = 0; i < m_instanceCount * m_audioPortsOut.size(); ++i) {
	m_outputBuffers[i] = new sample_t[blockSize];
    }

    m_ownBuffers = true;

    instantiate(sampleRate);
    if (isOK()) {
	connectPorts();
	activate();
    }
}

std::string
LADSPAPluginInstance::getName() const
{
    return m_descriptor->Label;
}

std::string 
LADSPAPluginInstance::getDescription() const
{
    return m_descriptor->Name;
}

std::string
LADSPAPluginInstance::getMaker() const
{
    return m_descriptor->Maker;
}

int
LADSPAPluginInstance::getPluginVersion() const
{
    return 1;
}

std::string
LADSPAPluginInstance::getCopyright() const
{
    return m_descriptor->Copyright;
}

LADSPAPluginInstance::ParameterList
LADSPAPluginInstance::getParameterDescriptors() const
{
    ParameterList list;
    LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
    
    for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
        
        ParameterDescriptor pd;
        unsigned int pn = m_controlPortsIn[i].first;

        pd.name = m_descriptor->PortNames[pn];
        pd.description = pd.name;
        pd.minValue = f->getPortMinimum(m_descriptor, pn);
        pd.maxValue = f->getPortMaximum(m_descriptor, pn);
        pd.defaultValue = f->getPortDefault(m_descriptor, pn);

        float q = f->getPortQuantization(m_descriptor, pn);
        if (q == 0.0) {
            pd.isQuantized = false;
        } else {
            pd.isQuantized = true;
            pd.quantizeStep = q;
        }

        list.push_back(pd);
    }

    return list;
}

float
LADSPAPluginInstance::getParameter(std::string name) const
{
    for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
        if (name == m_descriptor->PortNames[m_controlPortsIn[i].first]) {
            return getParameterValue(i);
        }
    }

    return 0.0;
}

void
LADSPAPluginInstance::setParameter(std::string name, float value)
{
    for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
        if (name == m_descriptor->PortNames[m_controlPortsIn[i].first]) {
            setParameterValue(i, value);
            break;
        }
    }
}    

void
LADSPAPluginInstance::init(int idealChannelCount)
{
#ifdef DEBUG_LADSPA
    std::cerr << "LADSPAPluginInstance::init(" << idealChannelCount << "): plugin has "
	      << m_descriptor->PortCount << " ports" << std::endl;
#endif

    // Discover ports numbers and identities
    //
    for (unsigned long i = 0; i < m_descriptor->PortCount; ++i)
    {
        if (LADSPA_IS_PORT_AUDIO(m_descriptor->PortDescriptors[i]))
        {
            if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[i])) {
#ifdef DEBUG_LADSPA
		std::cerr << "LADSPAPluginInstance::init: port " << i << " is audio in" << std::endl;
#endif
                m_audioPortsIn.push_back(i);
	    } else {
#ifdef DEBUG_LADSPA
		std::cerr << "LADSPAPluginInstance::init: port " << i << " is audio out" << std::endl;
#endif
                m_audioPortsOut.push_back(i);
	    }
        }
        else
        if (LADSPA_IS_PORT_CONTROL(m_descriptor->PortDescriptors[i]))
        {
	    if (LADSPA_IS_PORT_INPUT(m_descriptor->PortDescriptors[i])) {
#ifdef DEBUG_LADSPA
		std::cerr << "LADSPAPluginInstance::init: port " << i << " is control in" << std::endl;
#endif
		LADSPA_Data *data = new LADSPA_Data(0.0);
		m_controlPortsIn.push_back(
                    std::pair<unsigned long, LADSPA_Data*>(i, data));
	    } else {
#ifdef DEBUG_LADSPA
		std::cerr << "LADSPAPluginInstance::init: port " << i << " is control out" << std::endl;
#endif
		LADSPA_Data *data = new LADSPA_Data(0.0);
		m_controlPortsOut.push_back(
                    std::pair<unsigned long, LADSPA_Data*>(i, data));
		if (!strcmp(m_descriptor->PortNames[i], "latency") ||
		    !strcmp(m_descriptor->PortNames[i], "_latency")) {
#ifdef DEBUG_LADSPA
		    std::cerr << "Wooo! We have a latency port!" << std::endl;
#endif
		    m_latencyPort = data;
		}
	    }
        }
#ifdef DEBUG_LADSPA
        else
            std::cerr << "LADSPAPluginInstance::init - "
                      << "unrecognised port type" << std::endl;
#endif
    }

    m_instanceCount = 1;

    if (idealChannelCount > 0) {
	if (m_audioPortsIn.size() == 1) {
	    // mono plugin: duplicate it if need be
	    m_instanceCount = idealChannelCount;
	}
    }
}

size_t
LADSPAPluginInstance::getLatency()
{
    if (m_latencyPort) {
	if (!m_run) run(Vamp::RealTime::zeroTime);
	if (*m_latencyPort > 0) return (size_t)*m_latencyPort;
    }
    return 0;
}

void
LADSPAPluginInstance::silence()
{
    if (isOK()) {
	deactivate();
	activate();
    }
}

void
LADSPAPluginInstance::setIdealChannelCount(size_t channels)
{
    if (m_audioPortsIn.size() != 1 || channels == m_instanceCount) {
	silence();
	return;
    }

    if (isOK()) {
	deactivate();
    }

    //!!! don't we need to reallocate inputBuffers and outputBuffers?

    cleanup();
    m_instanceCount = channels;
    instantiate(m_sampleRate);
    if (isOK()) {
	connectPorts();
	activate();
    }
}


LADSPAPluginInstance::~LADSPAPluginInstance()
{
#ifdef DEBUG_LADSPA
    std::cerr << "LADSPAPluginInstance::~LADSPAPluginInstance" << std::endl;
#endif

    if (m_instanceHandles.size() != 0) { // "isOK()"
	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_audioPortsOut.size(); ++i) {
	    delete[] m_outputBuffers[i];
	}

	delete[] m_inputBuffers;
	delete[] m_outputBuffers;
    }

    m_audioPortsIn.clear();
    m_audioPortsOut.clear();
}


void
LADSPAPluginInstance::instantiate(unsigned long sampleRate)
{
#ifdef DEBUG_LADSPA
    std::cout << "LADSPAPluginInstance::instantiate - plugin unique id = "
              << m_descriptor->UniqueID << std::endl;
#endif
    if (!m_descriptor) return;

    if (!m_descriptor->instantiate) {
	std::cerr << "Bad plugin: plugin id " << m_descriptor->UniqueID
		  << ":" << m_descriptor->Label
		  << " has no instantiate method!" << std::endl;
	return;
    }

    for (size_t i = 0; i < m_instanceCount; ++i) {
	m_instanceHandles.push_back
	    (m_descriptor->instantiate(m_descriptor, sampleRate));
    }
}

void
LADSPAPluginInstance::activate()
{
    if (!m_descriptor || !m_descriptor->activate) return;

    for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
	 hi != m_instanceHandles.end(); ++hi) {
	m_descriptor->activate(*hi);
    }
}

void
LADSPAPluginInstance::connectPorts()
{
    if (!m_descriptor || !m_descriptor->connect_port) return;

    assert(sizeof(LADSPA_Data) == sizeof(float));
    assert(sizeof(sample_t) == sizeof(float));

    LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
    int inbuf = 0, outbuf = 0;

    for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
	 hi != m_instanceHandles.end(); ++hi) {

	for (unsigned int i = 0; i < m_audioPortsIn.size(); ++i) {
	    m_descriptor->connect_port(*hi,
				       m_audioPortsIn[i],
				       (LADSPA_Data *)m_inputBuffers[inbuf]);
	    ++inbuf;
	}

	for (unsigned int i = 0; i < m_audioPortsOut.size(); ++i) {
	    m_descriptor->connect_port(*hi,
				       m_audioPortsOut[i],
				       (LADSPA_Data *)m_outputBuffers[outbuf]);
	    ++outbuf;
	}

	// If there is more than one instance, they all share the same
	// control port ins (and outs, for the moment, because we
	// don't actually do anything with the outs anyway -- but they
	// do have to be connected as the plugin can't know if they're
	// not and will write to them anyway).

	for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
	    m_descriptor->connect_port(*hi,
				       m_controlPortsIn[i].first,
				       m_controlPortsIn[i].second);
            if (f) {
                float defaultValue = f->getPortDefault
                    (m_descriptor, m_controlPortsIn[i].first);
                *m_controlPortsIn[i].second = defaultValue;
            }
	}

	for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) {
	    m_descriptor->connect_port(*hi,
				       m_controlPortsOut[i].first,
				       m_controlPortsOut[i].second);
	}
    }
}

unsigned int
LADSPAPluginInstance::getParameterCount() const
{
    return m_controlPortsIn.size();
}

void
LADSPAPluginInstance::setParameterValue(unsigned int parameter, float value)
{
    if (parameter >= m_controlPortsIn.size()) return;

    unsigned int portNumber = m_controlPortsIn[parameter].first;

    LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
    if (f) {
	if (value < f->getPortMinimum(m_descriptor, portNumber)) {
	    value = f->getPortMinimum(m_descriptor, portNumber);
	}
	if (value > f->getPortMaximum(m_descriptor, portNumber)) {
	    value = f->getPortMaximum(m_descriptor, portNumber);
	}
    }

    (*m_controlPortsIn[parameter].second) = value;
}

float
LADSPAPluginInstance::getControlOutputValue(size_t output) const
{
    if (output > m_controlPortsOut.size()) return 0.0;
    return (*m_controlPortsOut[output].second);
}

float
LADSPAPluginInstance::getParameterValue(unsigned int parameter) const
{
    if (parameter >= m_controlPortsIn.size()) return 0.0;
    return (*m_controlPortsIn[parameter].second);
}

float
LADSPAPluginInstance::getParameterDefault(unsigned int parameter) const
{
    if (parameter >= m_controlPortsIn.size()) return 0.0;

    LADSPAPluginFactory *f = dynamic_cast<LADSPAPluginFactory *>(m_factory);
    if (f) {
	return f->getPortDefault(m_descriptor, m_controlPortsIn[parameter].first);
    } else {
	return 0.0f;
    }
}

void
LADSPAPluginInstance::run(const Vamp::RealTime &)
{
    if (!m_descriptor || !m_descriptor->run) return;

    for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
	 hi != m_instanceHandles.end(); ++hi) {
        m_descriptor->run(*hi, m_blockSize);
    }

    m_run = true;
}

void
LADSPAPluginInstance::deactivate()
{
    if (!m_descriptor || !m_descriptor->deactivate) return;

    for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
	 hi != m_instanceHandles.end(); ++hi) {
        m_descriptor->deactivate(*hi);
    }
}

void
LADSPAPluginInstance::cleanup()
{
    if (!m_descriptor) return;

    if (!m_descriptor->cleanup) {
	std::cerr << "Bad plugin: plugin id " << m_descriptor->UniqueID
		  << ":" << m_descriptor->Label
		  << " has no cleanup method!" << std::endl;
	return;
    }

    for (std::vector<LADSPA_Handle>::iterator hi = m_instanceHandles.begin();
	 hi != m_instanceHandles.end(); ++hi) {
	m_descriptor->cleanup(*hi);
    }

    m_instanceHandles.clear();
}