You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
436 lines
12 KiB
436 lines
12 KiB
15 years ago
|
// -*- c-indentation-style:"stroustrup" c-basic-offset: 4 -*-
|
||
|
/*
|
||
|
Rosegarden
|
||
|
A sequencer and musical notation editor.
|
||
|
|
||
|
This program is Copyright 2000-2008
|
||
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
||
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
||
|
Richard Bown <bownie@bownie.com>
|
||
|
|
||
|
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 "LADSPAPluginInstance.h"
|
||
|
#include "LADSPAPluginFactory.h"
|
||
|
|
||
|
#ifdef HAVE_LADSPA
|
||
|
|
||
|
//#define DEBUG_LADSPA 1
|
||
|
|
||
|
namespace Rosegarden
|
||
|
{
|
||
|
|
||
|
|
||
|
LADSPAPluginInstance::LADSPAPluginInstance(PluginFactory *factory,
|
||
|
InstrumentId instrument,
|
||
|
QString identifier,
|
||
|
int position,
|
||
|
unsigned long sampleRate,
|
||
|
size_t blockSize,
|
||
|
int idealChannelCount,
|
||
|
const LADSPA_Descriptor* descriptor) :
|
||
|
RunnablePluginInstance(factory, identifier),
|
||
|
m_instrument(instrument),
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LADSPAPluginInstance::LADSPAPluginInstance(PluginFactory *factory,
|
||
|
InstrumentId instrument,
|
||
|
QString identifier,
|
||
|
int position,
|
||
|
unsigned long sampleRate,
|
||
|
size_t blockSize,
|
||
|
sample_t **inputBuffers,
|
||
|
sample_t **outputBuffers,
|
||
|
const LADSPA_Descriptor* descriptor) :
|
||
|
RunnablePluginInstance(factory, identifier),
|
||
|
m_instrument(instrument),
|
||
|
m_position(position),
|
||
|
m_instanceCount(0),
|
||
|
m_descriptor(descriptor),
|
||
|
m_blockSize(blockSize),
|
||
|
m_inputBuffers(inputBuffers),
|
||
|
m_outputBuffers(outputBuffers),
|
||
|
m_ownBuffers(false),
|
||
|
m_sampleRate(sampleRate),
|
||
|
m_latencyPort(0),
|
||
|
m_run(false),
|
||
|
m_bypassed(false)
|
||
|
{
|
||
|
init();
|
||
|
|
||
|
instantiate(sampleRate);
|
||
|
if (isOK()) {
|
||
|
connectPorts();
|
||
|
activate();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
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) {
|
||
|
for (int i = 0; i < getAudioInputCount(); ++i) {
|
||
|
for (int j = 0; j < m_blockSize; ++j) {
|
||
|
m_inputBuffers[i][j] = 0.f;
|
||
|
}
|
||
|
}
|
||
|
run(RealTime::zeroTime);
|
||
|
}
|
||
|
return *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 (int 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));
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
for (unsigned int i = 0; i < m_controlPortsOut.size(); ++i) {
|
||
|
m_descriptor->connect_port(*hi,
|
||
|
m_controlPortsOut[i].first,
|
||
|
m_controlPortsOut[i].second);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
LADSPAPluginInstance::setPortValue(unsigned int portNumber, float value)
|
||
|
{
|
||
|
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, portNumber)) {
|
||
|
value = f->getPortMinimum(m_descriptor, portNumber);
|
||
|
}
|
||
|
if (value > f->getPortMaximum(m_descriptor, portNumber)) {
|
||
|
value = f->getPortMaximum(m_descriptor, portNumber);
|
||
|
}
|
||
|
}
|
||
|
(*m_controlPortsIn[i].second) = value;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float
|
||
|
LADSPAPluginInstance::getPortValue(unsigned int portNumber)
|
||
|
{
|
||
|
for (unsigned int i = 0; i < m_controlPortsIn.size(); ++i) {
|
||
|
if (m_controlPortsIn[i].first == portNumber) {
|
||
|
return (*m_controlPortsIn[i].second);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0.0;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
LADSPAPluginInstance::run(const 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();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif // HAVE_LADSPA
|
||
|
|
||
|
|