/* This file is part of Ingen. * Copyright (C) 2007 Dave Robillard * * Ingen 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. * * Ingen is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "LADSPANode.h" #include #include #include #include #include "AudioBuffer.h" #include "InputPort.h" #include "OutputPort.h" #include "Plugin.h" namespace Ingen { /** Partially construct a LADSPANode. * * Object is not usable until instantiate() is called with success. * (It _will_ crash!) */ LADSPANode::LADSPANode(const Plugin* plugin, const string& path, size_t poly, Patch* parent, const LADSPA_Descriptor* descriptor, SampleRate srate, size_t buffer_size) : NodeBase(plugin, path, poly, parent, srate, buffer_size), _descriptor(descriptor), _instances(NULL) { assert(_descriptor != NULL); } /** Instantiate self from LADSPA plugin descriptor. * * Implemented as a seperate function (rather than in the constructor) to * allow graceful error-catching of broken plugins. * * Returns whether or not plugin was successfully instantiated. If return * value is false, this object may not be used. */ bool LADSPANode::instantiate() { // Note that a DSSI plugin might tack more on to the end of this if (!_ports) _ports = new Raul::Array(_descriptor->PortCount); _instances = new LADSPA_Handle[_poly]; size_t port_buffer_size = 0; for (size_t i=0; i < _poly; ++i) { _instances[i] = _descriptor->instantiate(_descriptor, _srate); if (_instances[i] == NULL) { cerr << "Failed to instantiate plugin!" << endl; return false; } } string port_name; string port_path; Port* port = NULL; for (size_t j=0; j < _descriptor->PortCount; ++j) { cerr << "Name before: " << _descriptor->PortNames[j] << endl; port_name = Path::nameify(_descriptor->PortNames[j]); cerr << "Name after: " << port_name << endl; string::size_type slash_index; // Name mangling, to guarantee port names are unique for (size_t k=0; k < _descriptor->PortCount; ++k) { assert(_descriptor->PortNames[k] != NULL); if (k != j && port_name == _descriptor->PortNames[k]) { // clash if (LADSPA_IS_PORT_CONTROL(_descriptor->PortDescriptors[j])) port_name += "_(CR)"; else port_name += "_(AR)"; } // Replace all slashes with "-" (so they don't screw up paths) while ((slash_index = port_name.find("/")) != string::npos) port_name[slash_index] = '-'; } port_path = path() + "/" + port_name; if (LADSPA_IS_PORT_CONTROL(_descriptor->PortDescriptors[j])) port_buffer_size = 1; else if (LADSPA_IS_PORT_AUDIO(_descriptor->PortDescriptors[j])) port_buffer_size = _buffer_size; assert (LADSPA_IS_PORT_INPUT(_descriptor->PortDescriptors[j]) || LADSPA_IS_PORT_OUTPUT(_descriptor->PortDescriptors[j])); if (LADSPA_IS_PORT_INPUT(_descriptor->PortDescriptors[j])) { port = new InputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); _ports->at(j) = port; } else if (LADSPA_IS_PORT_OUTPUT(_descriptor->PortDescriptors[j])) { port = new OutputPort(this, port_name, j, _poly, DataType::FLOAT, port_buffer_size); _ports->at(j) = port; } assert(port); assert(_ports->at(j) == port); Sample default_val, min, max; get_port_limits(j, default_val, min, max); // Set default value if (port->buffer_size() == 1) { for (size_t i=0; i < _poly; ++i) ((AudioBuffer*)port->buffer(i))->set(default_val, 0); } if (port->is_input() && port->buffer_size() == 1) { port->set_metadata("ingen:minimum", min); port->set_metadata("ingen:maximum", max); } } return true; } LADSPANode::~LADSPANode() { for (size_t i=0; i < _poly; ++i) _descriptor->cleanup(_instances[i]); delete[] _instances; } void LADSPANode::activate() { NodeBase::activate(); for (size_t i=0; i < _poly; ++i) { for (unsigned long j=0; j < _descriptor->PortCount; ++j) { set_port_buffer(i, j, _ports->at(j)->buffer(i)); /* if (port->type() == DataType::FLOAT && port->buffer_size() == 1) port->set_value(0.0f, 0); // FIXME else if (port->type() == DataType::FLOAT && port->buffer_size() > 1) port->set_value(0.0f, 0);*/ } if (_descriptor->activate != NULL) _descriptor->activate(_instances[i]); } } void LADSPANode::deactivate() { NodeBase::deactivate(); for (size_t i=0; i < _poly; ++i) if (_descriptor->deactivate != NULL) _descriptor->deactivate(_instances[i]); } void LADSPANode::process(SampleCount nframes, FrameTime start, FrameTime end) { NodeBase::pre_process(nframes, start, end); for (size_t i=0; i < _poly; ++i) _descriptor->run(_instances[i], nframes); NodeBase::post_process(nframes, start, end); } void LADSPANode::set_port_buffer(size_t voice, size_t port_num, Buffer* buf) { assert(voice < _poly); AudioBuffer* audio_buffer = dynamic_cast(buf); assert(audio_buffer); if (port_num < _descriptor->PortCount) _descriptor->connect_port(_instances[voice], port_num, audio_buffer->data()); } #if 0 // Based on code stolen from jack-rack void LADSPANode::get_port_vals(ulong port_index, PortInfo* info) { LADSPA_Data upper = 0.0f; LADSPA_Data lower = 0.0f; LADSPA_Data normal = 0.0f; LADSPA_PortRangeHintDescriptor hint_descriptor = _descriptor->PortRangeHints[port_index].HintDescriptor; /* set upper and lower, possibly adjusted to the sample rate */ if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { upper = _descriptor->PortRangeHints[port_index].UpperBound * _srate; lower = _descriptor->PortRangeHints[port_index].LowerBound * _srate; } else { upper = _descriptor->PortRangeHints[port_index].UpperBound; lower = _descriptor->PortRangeHints[port_index].LowerBound; } if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { /* FLT_EPSILON is defined as the different between 1.0 and the minimum * float greater than 1.0. So, if lower is < FLT_EPSILON, it will be 1.0 * and the logarithmic control will have a base of 1 and thus not change */ if (lower < FLT_EPSILON) lower = FLT_EPSILON; } if (LADSPA_IS_HINT_HAS_DEFAULT(hint_descriptor)) { if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) { normal = lower; } else if (LADSPA_IS_HINT_DEFAULT_LOW(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { normal = exp(log(lower) * 0.75 + log(upper) * 0.25); } else { normal = lower * 0.75 + upper * 0.25; } } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { normal = exp(log(lower) * 0.5 + log(upper) * 0.5); } else { normal = lower * 0.5 + upper * 0.5; } } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { normal = exp(log(lower) * 0.25 + log(upper) * 0.75); } else { normal = lower * 0.25 + upper * 0.75; } } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) { normal = upper; } else if (LADSPA_IS_HINT_DEFAULT_0(hint_descriptor)) { normal = 0.0; } else if (LADSPA_IS_HINT_DEFAULT_1(hint_descriptor)) { normal = 1.0; } else if (LADSPA_IS_HINT_DEFAULT_100(hint_descriptor)) { normal = 100.0; } else if (LADSPA_IS_HINT_DEFAULT_440(hint_descriptor)) { normal = 440.0; } } else { // No default hint if (LADSPA_IS_HINT_BOUNDED_BELOW(hint_descriptor)) { normal = lower; } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) { normal = upper; } } info->min_val(lower); info->default_val(normal); info->max_val(upper); } #endif void LADSPANode::get_port_limits(unsigned long port_index, Sample& normal, Sample& lower, Sample& upper) { LADSPA_PortRangeHintDescriptor hint_descriptor = _descriptor->PortRangeHints[port_index].HintDescriptor; /* set upper and lower, possibly adjusted to the sample rate */ if (LADSPA_IS_HINT_SAMPLE_RATE(hint_descriptor)) { upper = _descriptor->PortRangeHints[port_index].UpperBound * _srate; lower = _descriptor->PortRangeHints[port_index].LowerBound * _srate; } else { upper = _descriptor->PortRangeHints[port_index].UpperBound; lower = _descriptor->PortRangeHints[port_index].LowerBound; } if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { /* FLT_EPSILON is defined as the different between 1.0 and the minimum * float greater than 1.0. So, if lower is < FLT_EPSILON, it will be 1.0 * and the logarithmic control will have a base of 1 and thus not change */ if (lower < FLT_EPSILON) lower = FLT_EPSILON; } if (LADSPA_IS_HINT_HAS_DEFAULT(hint_descriptor)) { if (LADSPA_IS_HINT_DEFAULT_MINIMUM(hint_descriptor)) { normal = lower; } else if (LADSPA_IS_HINT_DEFAULT_LOW(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { normal = exp(log(lower) * 0.75 + log(upper) * 0.25); } else { normal = lower * 0.75 + upper * 0.25; } } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { normal = exp(log(lower) * 0.5 + log(upper) * 0.5); } else { normal = lower * 0.5 + upper * 0.5; } } else if (LADSPA_IS_HINT_DEFAULT_HIGH(hint_descriptor)) { if (LADSPA_IS_HINT_LOGARITHMIC(hint_descriptor)) { normal = exp(log(lower) * 0.25 + log(upper) * 0.75); } else { normal = lower * 0.25 + upper * 0.75; } } else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(hint_descriptor)) { normal = upper; } else if (LADSPA_IS_HINT_DEFAULT_0(hint_descriptor)) { normal = 0.0; } else if (LADSPA_IS_HINT_DEFAULT_1(hint_descriptor)) { normal = 1.0; } else if (LADSPA_IS_HINT_DEFAULT_100(hint_descriptor)) { normal = 100.0; } else if (LADSPA_IS_HINT_DEFAULT_440(hint_descriptor)) { normal = 440.0; } } else { // No default hint if (LADSPA_IS_HINT_BOUNDED_BELOW(hint_descriptor)) { normal = lower; } else if (LADSPA_IS_HINT_BOUNDED_ABOVE(hint_descriptor)) { normal = upper; } } } } // namespace Ingen