2008-06-02 21:41:35 +00:00
|
|
|
/*
|
2009-10-14 16:10:01 +00:00
|
|
|
Copyright (C) 2000 Paul Davis
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
This program 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 more 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
2009-07-13 00:26:28 +00:00
|
|
|
#ifdef WAF_BUILD
|
|
|
|
|
#include "libardour-config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
#include <string>
|
|
|
|
|
|
2009-02-25 18:26:51 +00:00
|
|
|
#include "pbd/failed_constructor.h"
|
|
|
|
|
#include "pbd/xml++.h"
|
2010-11-28 18:31:18 +00:00
|
|
|
#include "pbd/convert.h"
|
2009-02-25 18:26:51 +00:00
|
|
|
|
|
|
|
|
#include "ardour/audio_buffer.h"
|
|
|
|
|
#include "ardour/automation_list.h"
|
|
|
|
|
#include "ardour/buffer_set.h"
|
2011-10-18 15:08:42 +00:00
|
|
|
#include "ardour/debug.h"
|
2009-02-25 18:26:51 +00:00
|
|
|
#include "ardour/event_type_map.h"
|
|
|
|
|
#include "ardour/ladspa_plugin.h"
|
|
|
|
|
#include "ardour/plugin.h"
|
|
|
|
|
#include "ardour/plugin_insert.h"
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-05-14 17:59:16 +00:00
|
|
|
#ifdef LV2_SUPPORT
|
2009-02-25 18:26:51 +00:00
|
|
|
#include "ardour/lv2_plugin.h"
|
2008-06-02 21:41:35 +00:00
|
|
|
#endif
|
|
|
|
|
|
2011-11-21 17:42:29 +00:00
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
|
|
|
|
#include "ardour/windows_vst_plugin.h"
|
2008-06-02 21:41:35 +00:00
|
|
|
#endif
|
|
|
|
|
|
2011-09-20 20:29:47 +00:00
|
|
|
#ifdef LXVST_SUPPORT
|
|
|
|
|
#include "ardour/lxvst_plugin.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-10-18 15:08:42 +00:00
|
|
|
#ifdef AUDIOUNIT_SUPPORT
|
2009-02-25 18:26:51 +00:00
|
|
|
#include "ardour/audio_unit.h"
|
2008-06-02 21:41:35 +00:00
|
|
|
#endif
|
|
|
|
|
|
2009-02-25 18:26:51 +00:00
|
|
|
#include "ardour/session.h"
|
|
|
|
|
#include "ardour/types.h"
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
using namespace ARDOUR;
|
|
|
|
|
using namespace PBD;
|
|
|
|
|
|
|
|
|
|
const string PluginInsert::port_automation_node_name = "PortAutomation";
|
|
|
|
|
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
PluginInsert::PluginInsert (Session& s, boost::shared_ptr<Plugin> plug)
|
2010-04-01 01:24:13 +00:00
|
|
|
: Processor (s, (plug ? plug->name() : string ("toBeRenamed")))
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
, _signal_analysis_collected_nframes(0)
|
|
|
|
|
, _signal_analysis_collect_nframes_max(0)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
/* the first is the master */
|
|
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
if (plug) {
|
2011-07-01 15:48:24 +00:00
|
|
|
add_plugin (plug);
|
2011-06-09 20:21:46 +00:00
|
|
|
create_automatable_parameters ();
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PluginInsert::set_count (uint32_t num)
|
|
|
|
|
{
|
|
|
|
|
bool require_state = !_plugins.empty();
|
|
|
|
|
|
|
|
|
|
/* this is a bad idea.... we shouldn't do this while active.
|
2009-10-14 16:10:01 +00:00
|
|
|
only a route holding their redirect_lock should be calling this
|
2008-06-02 21:41:35 +00:00
|
|
|
*/
|
|
|
|
|
|
2009-10-14 16:10:01 +00:00
|
|
|
if (num == 0) {
|
2008-06-02 21:41:35 +00:00
|
|
|
return false;
|
|
|
|
|
} else if (num > _plugins.size()) {
|
|
|
|
|
uint32_t diff = num - _plugins.size();
|
|
|
|
|
|
|
|
|
|
for (uint32_t n = 0; n < diff; ++n) {
|
2011-11-23 19:29:48 +00:00
|
|
|
boost::shared_ptr<Plugin> p = plugin_factory (_plugins[0]);
|
|
|
|
|
add_plugin (p);
|
|
|
|
|
if (active ()) {
|
|
|
|
|
p->activate ();
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
if (require_state) {
|
|
|
|
|
/* XXX do something */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if (num < _plugins.size()) {
|
|
|
|
|
uint32_t diff = _plugins.size() - num;
|
|
|
|
|
for (uint32_t n= 0; n < diff; ++n) {
|
|
|
|
|
_plugins.pop_back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PluginInsert::~PluginInsert ()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2010-08-09 22:23:23 +00:00
|
|
|
PluginInsert::control_list_automation_state_changed (Evoral::Parameter which, AutoState s)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
if (which.type() != PluginAutomation)
|
|
|
|
|
return;
|
|
|
|
|
|
2008-09-19 00:47:49 +00:00
|
|
|
boost::shared_ptr<AutomationControl> c
|
2010-02-05 20:03:57 +00:00
|
|
|
= boost::dynamic_pointer_cast<AutomationControl>(control (which));
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2010-08-09 22:23:23 +00:00
|
|
|
if (c && s != Off) {
|
2008-06-02 21:41:35 +00:00
|
|
|
_plugins[0]->set_parameter (which.id(), c->list()->eval (_session.transport_frame()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ChanCount
|
|
|
|
|
PluginInsert::output_streams() const
|
|
|
|
|
{
|
2011-11-01 21:48:45 +00:00
|
|
|
assert (!_plugins.empty());
|
2011-10-18 15:08:42 +00:00
|
|
|
|
2012-05-07 22:00:42 +00:00
|
|
|
PluginInfoPtr info = _plugins.front()->get_info();
|
|
|
|
|
|
|
|
|
|
if (info->reconfigurable_io()) {
|
2011-11-01 21:48:45 +00:00
|
|
|
ChanCount out = _plugins.front()->output_streams ();
|
2012-01-09 16:43:09 +00:00
|
|
|
// DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, reconfigur(able) output streams = %1\n", out));
|
2011-11-01 21:48:45 +00:00
|
|
|
return out;
|
2008-09-10 15:03:30 +00:00
|
|
|
} else {
|
2012-05-07 22:00:42 +00:00
|
|
|
ChanCount out = info->n_outputs;
|
2012-01-09 16:43:09 +00:00
|
|
|
// DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, static output streams = %1 for %2 plugins\n", out, _plugins.size()));
|
2008-09-10 15:03:30 +00:00
|
|
|
out.set_audio (out.n_audio() * _plugins.size());
|
2013-08-02 03:39:00 +02:00
|
|
|
out.set_midi (out.n_midi() * _plugins.size() + midi_bypass.n_midi());
|
2008-09-10 15:03:30 +00:00
|
|
|
return out;
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ChanCount
|
|
|
|
|
PluginInsert::input_streams() const
|
|
|
|
|
{
|
2011-11-01 21:48:45 +00:00
|
|
|
assert (!_plugins.empty());
|
|
|
|
|
|
|
|
|
|
ChanCount in;
|
|
|
|
|
|
2012-05-07 22:00:42 +00:00
|
|
|
PluginInfoPtr info = _plugins.front()->get_info();
|
|
|
|
|
|
|
|
|
|
if (info->reconfigurable_io()) {
|
2011-11-01 21:48:45 +00:00
|
|
|
assert (_plugins.size() == 1);
|
|
|
|
|
in = _plugins.front()->input_streams();
|
|
|
|
|
} else {
|
2012-05-07 22:00:42 +00:00
|
|
|
in = info->n_inputs;
|
2011-11-01 21:48:45 +00:00
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2011-11-01 21:48:45 +00:00
|
|
|
DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, input streams = %1, match using %2\n", in, _match.method));
|
2011-10-18 15:08:42 +00:00
|
|
|
|
2011-09-26 18:07:02 +00:00
|
|
|
if (_match.method == Split) {
|
2011-01-31 15:28:15 +00:00
|
|
|
|
|
|
|
|
/* we are splitting 1 processor input to multiple plugin inputs,
|
|
|
|
|
so we have a maximum of 1 stream of each type.
|
|
|
|
|
*/
|
|
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
|
|
|
|
if (in.get (*t) > 1) {
|
|
|
|
|
in.set (*t, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return in;
|
|
|
|
|
|
2011-09-26 18:07:02 +00:00
|
|
|
} else if (_match.method == Hide) {
|
|
|
|
|
|
|
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
|
|
|
|
in.set (*t, in.get (*t) - _match.hide.get (*t));
|
|
|
|
|
}
|
|
|
|
|
return in;
|
|
|
|
|
|
2008-09-10 15:03:30 +00:00
|
|
|
} else {
|
2011-09-26 18:04:02 +00:00
|
|
|
|
2011-09-26 18:07:02 +00:00
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
|
|
|
|
in.set (*t, in.get (*t) * _plugins.size ());
|
|
|
|
|
}
|
2011-11-01 21:48:45 +00:00
|
|
|
|
2008-09-10 15:03:30 +00:00
|
|
|
return in;
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ChanCount
|
|
|
|
|
PluginInsert::natural_output_streams() const
|
|
|
|
|
{
|
|
|
|
|
return _plugins[0]->get_info()->n_outputs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ChanCount
|
|
|
|
|
PluginInsert::natural_input_streams() const
|
|
|
|
|
{
|
|
|
|
|
return _plugins[0]->get_info()->n_inputs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
2011-07-08 21:58:34 +00:00
|
|
|
PluginInsert::has_no_inputs() const
|
|
|
|
|
{
|
|
|
|
|
return _plugins[0]->get_info()->n_inputs == ChanCount::ZERO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PluginInsert::has_no_audio_inputs() const
|
|
|
|
|
{
|
|
|
|
|
return _plugins[0]->get_info()->n_inputs.n_audio() == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PluginInsert::is_midi_instrument() const
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
/* XXX more finesse is possible here. VST plugins have a
|
|
|
|
|
a specific "instrument" flag, for example.
|
|
|
|
|
*/
|
2011-07-08 21:58:34 +00:00
|
|
|
PluginInfoPtr pi = _plugins[0]->get_info();
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-07-08 21:58:34 +00:00
|
|
|
return pi->n_inputs.n_midi() != 0 &&
|
|
|
|
|
pi->n_outputs.n_audio() > 0;
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2011-06-09 20:21:46 +00:00
|
|
|
PluginInsert::create_automatable_parameters ()
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2011-06-09 20:21:46 +00:00
|
|
|
assert (!_plugins.empty());
|
|
|
|
|
|
2008-09-29 22:47:40 +00:00
|
|
|
set<Evoral::Parameter> a = _plugins.front()->automatable ();
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2008-09-29 22:47:40 +00:00
|
|
|
for (set<Evoral::Parameter>::iterator i = a.begin(); i != a.end(); ++i) {
|
2008-06-02 21:41:35 +00:00
|
|
|
if (i->type() == PluginAutomation) {
|
2009-12-30 19:33:29 +00:00
|
|
|
|
2008-09-29 22:47:40 +00:00
|
|
|
Evoral::Parameter param(*i);
|
2009-12-30 19:33:29 +00:00
|
|
|
|
2014-11-03 18:40:17 -05:00
|
|
|
ParameterDescriptor desc;
|
2009-12-30 19:33:29 +00:00
|
|
|
_plugins.front()->get_parameter_descriptor(i->id(), desc);
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2009-12-30 19:33:29 +00:00
|
|
|
can_automate (param);
|
2014-12-01 14:28:03 -05:00
|
|
|
boost::shared_ptr<AutomationList> list(new AutomationList(param, desc));
|
2014-11-01 23:29:10 -04:00
|
|
|
add_control (boost::shared_ptr<AutomationControl> (new PluginControl(this, param, desc, list)));
|
|
|
|
|
} else if (i->type() == PluginPropertyAutomation) {
|
|
|
|
|
Evoral::Parameter param(*i);
|
|
|
|
|
const ParameterDescriptor& desc = _plugins.front()->get_property_descriptor(param.id());
|
2014-11-07 17:21:43 -05:00
|
|
|
if (desc.datatype != Variant::NOTHING) {
|
2014-11-01 23:29:10 -04:00
|
|
|
boost::shared_ptr<AutomationList> list;
|
|
|
|
|
if (Variant::type_is_numeric(desc.datatype)) {
|
2014-12-01 14:28:03 -05:00
|
|
|
list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc));
|
2014-11-01 23:29:10 -04:00
|
|
|
}
|
|
|
|
|
add_control (boost::shared_ptr<AutomationControl> (new PluginPropertyControl(this, param, desc, list)));
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2012-07-11 03:48:14 +00:00
|
|
|
PluginInsert::parameter_changed (uint32_t which, float val)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2012-07-11 03:48:14 +00:00
|
|
|
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, which));
|
2012-07-11 00:23:55 +00:00
|
|
|
|
|
|
|
|
if (ac) {
|
2012-07-13 21:05:45 +00:00
|
|
|
ac->set_value (val);
|
2012-07-11 03:48:14 +00:00
|
|
|
|
|
|
|
|
Plugins::iterator i = _plugins.begin();
|
|
|
|
|
|
|
|
|
|
/* don't set the first plugin, just all the slaves */
|
|
|
|
|
|
|
|
|
|
if (i != _plugins.end()) {
|
|
|
|
|
++i;
|
|
|
|
|
for (; i != _plugins.end(); ++i) {
|
|
|
|
|
(*i)->set_parameter (which, val);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2010-08-16 19:58:34 +00:00
|
|
|
int
|
2010-12-03 22:26:29 +00:00
|
|
|
PluginInsert::set_block_size (pframes_t nframes)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2011-04-02 19:52:21 +00:00
|
|
|
int ret = 0;
|
2009-05-04 15:50:51 +00:00
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
2010-08-16 19:58:34 +00:00
|
|
|
if ((*i)->set_block_size (nframes) != 0) {
|
2011-04-02 19:52:21 +00:00
|
|
|
ret = -1;
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
return ret;
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::activate ()
|
|
|
|
|
{
|
2009-05-04 15:50:51 +00:00
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
2008-06-02 21:41:35 +00:00
|
|
|
(*i)->activate ();
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2010-08-07 23:31:33 +00:00
|
|
|
Processor::activate ();
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::deactivate ()
|
|
|
|
|
{
|
2009-08-02 00:34:49 +00:00
|
|
|
Processor::deactivate ();
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2009-05-04 15:50:51 +00:00
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
2008-06-02 21:41:35 +00:00
|
|
|
(*i)->deactivate ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-16 19:58:34 +00:00
|
|
|
void
|
|
|
|
|
PluginInsert::flush ()
|
|
|
|
|
{
|
2011-04-02 19:52:21 +00:00
|
|
|
for (vector<boost::shared_ptr<Plugin> >::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
|
|
|
|
(*i)->flush ();
|
|
|
|
|
}
|
2010-08-16 19:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
void
|
2010-12-03 22:26:29 +00:00
|
|
|
PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t offset, bool with_auto, framepos_t now)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2008-10-20 18:57:34 +00:00
|
|
|
// Calculate if, and how many frames we need to collect for analysis
|
2010-12-03 22:26:29 +00:00
|
|
|
framecnt_t collect_signal_nframes = (_signal_analysis_collect_nframes_max -
|
|
|
|
|
_signal_analysis_collected_nframes);
|
2008-10-20 18:57:34 +00:00
|
|
|
if (nframes < collect_signal_nframes) { // we might not get all frames now
|
|
|
|
|
collect_signal_nframes = nframes;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-26 18:07:02 +00:00
|
|
|
ChanCount const in_streams = input_streams ();
|
|
|
|
|
ChanCount const out_streams = output_streams ();
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-09-26 18:07:02 +00:00
|
|
|
ChanMapping in_map (in_streams);
|
|
|
|
|
ChanMapping out_map (out_streams);
|
2011-10-21 04:51:04 +00:00
|
|
|
bool valid;
|
2011-09-26 18:07:02 +00:00
|
|
|
if (_match.method == Split) {
|
2011-01-31 15:28:15 +00:00
|
|
|
/* fix the input mapping so that we have maps for each of the plugin's inputs */
|
|
|
|
|
in_map = ChanMapping (natural_input_streams ());
|
|
|
|
|
|
|
|
|
|
/* copy the first stream's buffer contents to the others */
|
|
|
|
|
/* XXX: audio only */
|
2012-04-10 20:45:39 +00:00
|
|
|
uint32_t first_idx = in_map.get (DataType::AUDIO, 0, &valid);
|
|
|
|
|
if (valid) {
|
|
|
|
|
for (uint32_t i = in_streams.n_audio(); i < natural_input_streams().n_audio(); ++i) {
|
2013-12-29 21:48:14 +01:00
|
|
|
bufs.get_audio(in_map.get (DataType::AUDIO, i, &valid)).read_from(bufs.get_audio(first_idx), nframes, offset, offset);
|
2012-04-10 20:45:39 +00:00
|
|
|
}
|
2011-01-31 15:28:15 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-06 23:34:04 +02:00
|
|
|
bufs.set_count(ChanCount::max(bufs.count(), in_streams));
|
|
|
|
|
bufs.set_count(ChanCount::max(bufs.count(), out_streams));
|
|
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
/* Note that we've already required that plugins
|
|
|
|
|
be able to handle in-place processing.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (with_auto) {
|
|
|
|
|
|
|
|
|
|
uint32_t n = 0;
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2010-02-05 20:03:57 +00:00
|
|
|
for (Controls::iterator li = controls().begin(); li != controls().end(); ++li, ++n) {
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2008-09-19 00:47:49 +00:00
|
|
|
boost::shared_ptr<AutomationControl> c
|
|
|
|
|
= boost::dynamic_pointer_cast<AutomationControl>(li->second);
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2014-11-01 23:29:10 -04:00
|
|
|
if (c->list() && c->automation_playback()) {
|
2008-06-02 21:41:35 +00:00
|
|
|
bool valid;
|
|
|
|
|
|
2009-10-14 16:10:01 +00:00
|
|
|
const float val = c->list()->rt_safe_eval (now, valid);
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
if (valid) {
|
|
|
|
|
c->set_value(val);
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-14 16:10:01 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-20 18:57:34 +00:00
|
|
|
if (collect_signal_nframes > 0) {
|
|
|
|
|
// collect input
|
|
|
|
|
//std::cerr << "collect input, bufs " << bufs.count().n_audio() << " count, " << bufs.available().n_audio() << " available" << std::endl;
|
|
|
|
|
//std::cerr << " streams " << input_streams().n_audio() << std::endl;
|
|
|
|
|
//std::cerr << "filling buffer with " << collect_signal_nframes << " frames at " << _signal_analysis_collected_nframes << std::endl;
|
2009-05-08 05:20:23 +00:00
|
|
|
|
|
|
|
|
_signal_analysis_inputs.set_count(input_streams());
|
|
|
|
|
|
2008-10-20 18:57:34 +00:00
|
|
|
for (uint32_t i = 0; i < input_streams().n_audio(); ++i) {
|
2009-05-04 15:50:51 +00:00
|
|
|
_signal_analysis_inputs.get_audio(i).read_from(
|
2008-10-20 18:57:34 +00:00
|
|
|
bufs.get_audio(i),
|
|
|
|
|
collect_signal_nframes,
|
|
|
|
|
_signal_analysis_collected_nframes); // offset is for target buffer
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2008-10-20 18:57:34 +00:00
|
|
|
}
|
|
|
|
|
|
2009-05-04 15:50:51 +00:00
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
(*i)->connect_and_run(bufs, in_map, out_map, nframes, offset);
|
2009-05-04 15:50:51 +00:00
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
in_map.offset_to(*t, natural_input_streams().get(*t));
|
|
|
|
|
out_map.offset_to(*t, natural_output_streams().get(*t));
|
2009-05-04 15:50:51 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2008-10-20 18:57:34 +00:00
|
|
|
if (collect_signal_nframes > 0) {
|
|
|
|
|
// collect output
|
|
|
|
|
//std::cerr << " output, bufs " << bufs.count().n_audio() << " count, " << bufs.available().n_audio() << " available" << std::endl;
|
|
|
|
|
//std::cerr << " streams " << output_streams().n_audio() << std::endl;
|
2009-05-08 05:20:23 +00:00
|
|
|
|
|
|
|
|
_signal_analysis_outputs.set_count(output_streams());
|
|
|
|
|
|
2008-10-20 18:57:34 +00:00
|
|
|
for (uint32_t i = 0; i < output_streams().n_audio(); ++i) {
|
2009-05-04 15:50:51 +00:00
|
|
|
_signal_analysis_outputs.get_audio(i).read_from(
|
2009-10-14 16:10:01 +00:00
|
|
|
bufs.get_audio(i),
|
|
|
|
|
collect_signal_nframes,
|
2008-10-20 18:57:34 +00:00
|
|
|
_signal_analysis_collected_nframes); // offset is for target buffer
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_signal_analysis_collected_nframes += collect_signal_nframes;
|
|
|
|
|
assert(_signal_analysis_collected_nframes <= _signal_analysis_collect_nframes_max);
|
|
|
|
|
|
|
|
|
|
if (_signal_analysis_collected_nframes == _signal_analysis_collect_nframes_max) {
|
|
|
|
|
_signal_analysis_collect_nframes_max = 0;
|
|
|
|
|
_signal_analysis_collected_nframes = 0;
|
|
|
|
|
|
2009-10-14 16:10:01 +00:00
|
|
|
AnalysisDataGathered(&_signal_analysis_inputs,
|
2009-05-04 15:50:51 +00:00
|
|
|
&_signal_analysis_outputs);
|
2008-10-20 18:57:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
/* leave remaining channel buffers alone */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2010-12-03 22:26:29 +00:00
|
|
|
PluginInsert::silence (framecnt_t nframes)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2011-01-31 15:28:15 +00:00
|
|
|
if (!active ()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2009-05-04 15:50:51 +00:00
|
|
|
ChanMapping in_map(input_streams());
|
|
|
|
|
ChanMapping out_map(output_streams());
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-09-26 18:07:02 +00:00
|
|
|
if (_match.method == Split) {
|
2011-01-31 15:28:15 +00:00
|
|
|
/* fix the input mapping so that we have maps for each of the plugin's inputs */
|
|
|
|
|
in_map = ChanMapping (natural_input_streams ());
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2011-01-31 15:28:15 +00:00
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
2013-08-01 00:35:24 +02:00
|
|
|
(*i)->connect_and_run (_session.get_scratch_buffers ((*i)->get_info()->n_inputs, true), in_map, out_map, nframes, 0);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
void
|
2014-05-26 06:17:49 +02:00
|
|
|
PluginInsert::run (BufferSet& bufs, framepos_t start_frame, framepos_t /*end_frame*/, pframes_t nframes, bool)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2010-09-09 14:40:46 +00:00
|
|
|
if (_pending_active) {
|
|
|
|
|
/* run as normal if we are active or moving from inactive to active */
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2014-05-26 06:17:49 +02:00
|
|
|
if (_session.transport_rolling() || _session.bounce_processing()) {
|
|
|
|
|
automation_run (bufs, start_frame, nframes);
|
2008-06-02 21:41:35 +00:00
|
|
|
} else {
|
2009-04-30 17:26:13 +00:00
|
|
|
connect_and_run (bufs, nframes, 0, false);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2009-07-21 14:39:21 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
} else {
|
2014-01-26 00:46:39 +01:00
|
|
|
uint32_t in = input_streams ().n_audio ();
|
|
|
|
|
uint32_t out = output_streams().n_audio ();
|
|
|
|
|
|
|
|
|
|
if (has_no_audio_inputs() || in == 0) {
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-05-12 00:16:16 +00:00
|
|
|
/* silence all (audio) outputs. Should really declick
|
|
|
|
|
* at the transitions of "active"
|
|
|
|
|
*/
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-05-12 00:16:16 +00:00
|
|
|
for (uint32_t n = 0; n < out; ++n) {
|
|
|
|
|
bufs.get_audio (n).silence (nframes);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-26 00:46:39 +01:00
|
|
|
} else if (out > in) {
|
2011-06-01 16:50:12 +00:00
|
|
|
|
2014-01-26 00:46:39 +01:00
|
|
|
/* not active, but something has make up for any channel count increase */
|
2011-06-01 16:50:12 +00:00
|
|
|
|
2014-01-26 00:46:39 +01:00
|
|
|
// TODO: option round-robin (n % in) or silence additional buffers ??
|
|
|
|
|
// for now , simply replicate last buffer
|
|
|
|
|
for (uint32_t n = in; n < out; ++n) {
|
|
|
|
|
bufs.get_audio(n).read_from(bufs.get_audio(in - 1), nframes);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-26 00:46:39 +01:00
|
|
|
|
|
|
|
|
bufs.count().set_audio (out);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2009-07-21 14:39:21 +00:00
|
|
|
|
|
|
|
|
_active = _pending_active;
|
2011-11-01 21:28:16 +00:00
|
|
|
|
|
|
|
|
/* we have no idea whether the plugin generated silence or not, so mark
|
|
|
|
|
* all buffers appropriately.
|
|
|
|
|
*/
|
|
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2008-09-29 22:47:40 +00:00
|
|
|
PluginInsert::set_parameter (Evoral::Parameter param, float val)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2010-08-23 16:31:34 +00:00
|
|
|
if (param.type() != PluginAutomation) {
|
2008-06-02 21:41:35 +00:00
|
|
|
return;
|
2011-04-02 19:52:21 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
/* the others will be set from the event triggered by this */
|
|
|
|
|
|
|
|
|
|
_plugins[0]->set_parameter (param.id(), val);
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2008-09-28 21:20:43 +00:00
|
|
|
boost::shared_ptr<AutomationControl> ac
|
2010-02-05 20:03:57 +00:00
|
|
|
= boost::dynamic_pointer_cast<AutomationControl>(control(param));
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2008-09-28 21:20:43 +00:00
|
|
|
if (ac) {
|
|
|
|
|
ac->set_value(val);
|
|
|
|
|
} else {
|
|
|
|
|
warning << "set_parameter called for nonexistant parameter "
|
2008-09-29 22:47:40 +00:00
|
|
|
<< EventTypeMap::instance().to_symbol(param) << endmsg;
|
2008-09-28 21:20:43 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
_session.set_dirty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float
|
2008-09-29 22:47:40 +00:00
|
|
|
PluginInsert::get_parameter (Evoral::Parameter param)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2010-02-03 00:52:45 +00:00
|
|
|
if (param.type() != PluginAutomation) {
|
2008-06-02 21:41:35 +00:00
|
|
|
return 0.0;
|
2010-02-03 00:52:45 +00:00
|
|
|
} else {
|
|
|
|
|
assert (!_plugins.empty ());
|
|
|
|
|
return _plugins[0]->get_parameter (param.id());
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2014-05-26 06:17:49 +02:00
|
|
|
PluginInsert::automation_run (BufferSet& bufs, framepos_t start, pframes_t nframes)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2008-09-29 22:47:40 +00:00
|
|
|
Evoral::ControlEvent next_event (0, 0.0f);
|
2014-05-26 06:17:49 +02:00
|
|
|
framepos_t now = start;
|
2010-12-03 22:26:29 +00:00
|
|
|
framepos_t end = now + nframes;
|
|
|
|
|
framecnt_t offset = 0;
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2012-07-25 17:48:55 +00:00
|
|
|
Glib::Threads::Mutex::Lock lm (control_lock(), Glib::Threads::TRY_LOCK);
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
if (!lm.locked()) {
|
|
|
|
|
connect_and_run (bufs, nframes, offset, false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2010-08-16 19:58:34 +00:00
|
|
|
if (!find_next_event (now, end, next_event) || requires_fixed_sized_buffers()) {
|
2009-10-14 16:10:01 +00:00
|
|
|
|
|
|
|
|
/* no events have a time within the relevant range */
|
|
|
|
|
|
|
|
|
|
connect_and_run (bufs, nframes, offset, true, now);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (nframes) {
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2010-12-03 22:26:29 +00:00
|
|
|
framecnt_t cnt = min (((framecnt_t) ceil (next_event.when) - now), (framecnt_t) nframes);
|
2009-10-14 16:10:01 +00:00
|
|
|
|
|
|
|
|
connect_and_run (bufs, cnt, offset, true, now);
|
|
|
|
|
|
|
|
|
|
nframes -= cnt;
|
|
|
|
|
offset += cnt;
|
2008-06-02 21:41:35 +00:00
|
|
|
now += cnt;
|
|
|
|
|
|
2010-02-05 20:03:57 +00:00
|
|
|
if (!find_next_event (now, end, next_event)) {
|
2008-06-02 21:41:35 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* cleanup anything that is left to do */
|
|
|
|
|
|
|
|
|
|
if (nframes) {
|
|
|
|
|
connect_and_run (bufs, nframes, offset, true, now);
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
float
|
2008-09-19 06:30:49 +00:00
|
|
|
PluginInsert::default_parameter_value (const Evoral::Parameter& param)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
if (param.type() != PluginAutomation)
|
|
|
|
|
return 1.0;
|
|
|
|
|
|
|
|
|
|
if (_plugins.empty()) {
|
|
|
|
|
fatal << _("programming error: ") << X_("PluginInsert::default_parameter_value() called with no plugin")
|
|
|
|
|
<< endmsg;
|
2014-11-14 10:47:43 +01:00
|
|
|
abort(); /*NOTREACHED*/
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _plugins[0]->default_value (param.id());
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-04 20:22:50 +02:00
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PluginInsert::can_reset_all_parameters ()
|
|
|
|
|
{
|
|
|
|
|
bool all = true;
|
|
|
|
|
uint32_t params = 0;
|
|
|
|
|
for (uint32_t par = 0; par < _plugins[0]->parameter_count(); ++par) {
|
|
|
|
|
bool ok=false;
|
|
|
|
|
const uint32_t cid = _plugins[0]->nth_parameter (par, ok);
|
|
|
|
|
|
|
|
|
|
if (!ok || !_plugins[0]->parameter_is_input(cid)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter(PluginAutomation, 0, cid));
|
|
|
|
|
if (!ac) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++params;
|
|
|
|
|
if (ac->automation_state() & Play) {
|
|
|
|
|
all = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return all && (params > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PluginInsert::reset_parameters_to_default ()
|
|
|
|
|
{
|
|
|
|
|
bool all = true;
|
|
|
|
|
|
|
|
|
|
for (uint32_t par = 0; par < _plugins[0]->parameter_count(); ++par) {
|
|
|
|
|
bool ok=false;
|
|
|
|
|
const uint32_t cid = _plugins[0]->nth_parameter (par, ok);
|
|
|
|
|
|
|
|
|
|
if (!ok || !_plugins[0]->parameter_is_input(cid)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const float dflt = _plugins[0]->default_value (cid);
|
|
|
|
|
const float curr = _plugins[0]->get_parameter (cid);
|
|
|
|
|
|
|
|
|
|
if (dflt == curr) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter(PluginAutomation, 0, cid));
|
|
|
|
|
if (!ac) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ac->automation_state() & Play) {
|
|
|
|
|
all = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ac->set_value (dflt);
|
|
|
|
|
}
|
|
|
|
|
return all;
|
|
|
|
|
}
|
|
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
boost::shared_ptr<Plugin>
|
|
|
|
|
PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<LadspaPlugin> lp;
|
2011-05-14 17:59:16 +00:00
|
|
|
#ifdef LV2_SUPPORT
|
2008-06-02 21:41:35 +00:00
|
|
|
boost::shared_ptr<LV2Plugin> lv2p;
|
|
|
|
|
#endif
|
2011-11-21 17:42:29 +00:00
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
|
|
|
|
boost::shared_ptr<WindowsVSTPlugin> vp;
|
2008-06-02 21:41:35 +00:00
|
|
|
#endif
|
2011-09-20 20:29:47 +00:00
|
|
|
#ifdef LXVST_SUPPORT
|
|
|
|
|
boost::shared_ptr<LXVSTPlugin> lxvp;
|
|
|
|
|
#endif
|
2011-10-18 15:08:42 +00:00
|
|
|
#ifdef AUDIOUNIT_SUPPORT
|
2008-06-02 21:41:35 +00:00
|
|
|
boost::shared_ptr<AUPlugin> ap;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
|
|
|
|
|
return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
|
2011-05-14 17:59:16 +00:00
|
|
|
#ifdef LV2_SUPPORT
|
2008-06-02 21:41:35 +00:00
|
|
|
} else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
|
|
|
|
|
return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
|
|
|
|
|
#endif
|
2011-11-21 17:42:29 +00:00
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
|
|
|
|
} else if ((vp = boost::dynamic_pointer_cast<WindowsVSTPlugin> (other)) != 0) {
|
|
|
|
|
return boost::shared_ptr<Plugin> (new WindowsVSTPlugin (*vp));
|
2008-06-02 21:41:35 +00:00
|
|
|
#endif
|
2011-09-20 20:29:47 +00:00
|
|
|
#ifdef LXVST_SUPPORT
|
|
|
|
|
} else if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (other)) != 0) {
|
|
|
|
|
return boost::shared_ptr<Plugin> (new LXVSTPlugin (*lxvp));
|
|
|
|
|
#endif
|
2011-10-18 15:08:42 +00:00
|
|
|
#ifdef AUDIOUNIT_SUPPORT
|
2008-06-02 21:41:35 +00:00
|
|
|
} else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
|
|
|
|
|
return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fatal << string_compose (_("programming error: %1"),
|
|
|
|
|
X_("unknown plugin type in PluginInsert::plugin_factory"))
|
|
|
|
|
<< endmsg;
|
2014-11-14 10:47:43 +01:00
|
|
|
abort(); /*NOTREACHED*/
|
2008-06-02 21:41:35 +00:00
|
|
|
return boost::shared_ptr<Plugin> ((Plugin*) 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
PluginInsert::configure_io (ChanCount in, ChanCount out)
|
|
|
|
|
{
|
2011-09-26 18:07:02 +00:00
|
|
|
Match old_match = _match;
|
2014-01-01 15:34:06 +01:00
|
|
|
ChanCount old_in = input_streams ();
|
|
|
|
|
ChanCount old_out = output_streams ();
|
2011-09-26 18:04:02 +00:00
|
|
|
|
|
|
|
|
/* set the matching method and number of plugins that we will use to meet this configuration */
|
2011-09-26 18:07:02 +00:00
|
|
|
_match = private_can_support_io_configuration (in, out);
|
|
|
|
|
if (set_count (_match.plugins) == false) {
|
2008-09-10 15:03:30 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-01 15:34:06 +01:00
|
|
|
if ( (old_match.method != _match.method && (old_match.method == Split || _match.method == Split))
|
|
|
|
|
|| old_in != in
|
|
|
|
|
|| old_out != out
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
PluginIoReConfigure (); /* EMIT SIGNAL */
|
2011-09-26 18:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* configure plugins */
|
2011-09-26 18:07:02 +00:00
|
|
|
switch (_match.method) {
|
2011-09-26 18:04:02 +00:00
|
|
|
case Split:
|
2011-09-26 18:07:02 +00:00
|
|
|
case Hide:
|
2011-09-26 18:04:02 +00:00
|
|
|
if (_plugins.front()->configure_io (_plugins.front()->get_info()->n_inputs, out)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2011-01-31 15:28:15 +00:00
|
|
|
if (_plugins.front()->configure_io (in, out) == false) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-09-26 18:04:02 +00:00
|
|
|
break;
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2008-09-10 15:03:30 +00:00
|
|
|
|
2008-10-20 18:57:34 +00:00
|
|
|
// we don't know the analysis window size, so we must work with the
|
|
|
|
|
// current buffer size here. each request for data fills in these
|
2009-10-14 16:10:01 +00:00
|
|
|
// buffers and the analyser makes sure it gets enough data for the
|
2008-10-20 18:57:34 +00:00
|
|
|
// analysis window
|
2009-05-04 15:50:51 +00:00
|
|
|
session().ensure_buffer_set (_signal_analysis_inputs, in);
|
2009-05-08 05:20:23 +00:00
|
|
|
//_signal_analysis_inputs.set_count (in);
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2009-05-04 15:50:51 +00:00
|
|
|
session().ensure_buffer_set (_signal_analysis_outputs, out);
|
2009-05-08 05:20:23 +00:00
|
|
|
//_signal_analysis_outputs.set_count (out);
|
|
|
|
|
|
2009-05-16 13:37:48 +00:00
|
|
|
// std::cerr << "set counts to i" << in.n_audio() << "/o" << out.n_audio() << std::endl;
|
2008-10-20 18:57:34 +00:00
|
|
|
|
2008-09-10 15:03:30 +00:00
|
|
|
return Processor::configure_io (in, out);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2011-09-26 18:04:02 +00:00
|
|
|
/** Decide whether this PluginInsert can support a given IO configuration.
|
|
|
|
|
* To do this, we run through a set of possible solutions in rough order of
|
|
|
|
|
* preference.
|
|
|
|
|
*
|
|
|
|
|
* @param in Required input channel count.
|
|
|
|
|
* @param out Filled in with the output channel count if we return true.
|
|
|
|
|
* @return true if the given IO configuration can be supported.
|
|
|
|
|
*/
|
2008-06-02 21:41:35 +00:00
|
|
|
bool
|
2013-08-02 03:39:00 +02:00
|
|
|
PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2011-09-26 18:07:02 +00:00
|
|
|
return private_can_support_io_configuration (in, out).method != Impossible;
|
2011-09-26 18:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** A private version of can_support_io_configuration which returns the method
|
|
|
|
|
* by which the configuration can be matched, rather than just whether or not
|
|
|
|
|
* it can be.
|
|
|
|
|
*/
|
2011-09-26 18:07:02 +00:00
|
|
|
PluginInsert::Match
|
2013-08-02 03:39:00 +02:00
|
|
|
PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanCount& out)
|
2011-09-26 18:04:02 +00:00
|
|
|
{
|
2014-01-17 19:34:51 -05:00
|
|
|
if (_plugins.empty()) {
|
|
|
|
|
return Match();
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-07 22:00:42 +00:00
|
|
|
PluginInfoPtr info = _plugins.front()->get_info();
|
2013-08-02 03:39:00 +02:00
|
|
|
ChanCount in; in += inx;
|
|
|
|
|
midi_bypass.reset();
|
2012-05-07 22:00:42 +00:00
|
|
|
|
|
|
|
|
if (info->reconfigurable_io()) {
|
2011-09-26 18:04:02 +00:00
|
|
|
/* Plugin has flexible I/O, so delegate to it */
|
|
|
|
|
bool const r = _plugins.front()->can_support_io_configuration (in, out);
|
|
|
|
|
if (!r) {
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (Impossible, 0);
|
2011-09-26 18:04:02 +00:00
|
|
|
}
|
|
|
|
|
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (Delegate, 1);
|
2008-09-10 15:03:30 +00:00
|
|
|
}
|
|
|
|
|
|
2012-05-07 22:00:42 +00:00
|
|
|
ChanCount inputs = info->n_inputs;
|
|
|
|
|
ChanCount outputs = info->n_outputs;
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2013-08-02 03:39:00 +02:00
|
|
|
if (in.get(DataType::MIDI) == 1 && outputs.get(DataType::MIDI) == 0) {
|
|
|
|
|
DEBUG_TRACE ( DEBUG::Processors, string_compose ("bypassing midi-data around %1\n", name()));
|
|
|
|
|
midi_bypass.set(DataType::MIDI, 1);
|
|
|
|
|
}
|
|
|
|
|
if (in.get(DataType::MIDI) == 1 && inputs.get(DataType::MIDI) == 0) {
|
|
|
|
|
DEBUG_TRACE ( DEBUG::Processors, string_compose ("hiding midi-port from plugin %1\n", name()));
|
|
|
|
|
in.set(DataType::MIDI, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
bool no_inputs = true;
|
2011-02-24 16:22:42 +00:00
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
2011-04-02 19:52:21 +00:00
|
|
|
if (inputs.get (*t) != 0) {
|
|
|
|
|
no_inputs = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (no_inputs) {
|
|
|
|
|
/* no inputs so we can take any input configuration since we throw it away */
|
2013-08-02 03:39:00 +02:00
|
|
|
out = outputs + midi_bypass;
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (NoInputs, 1);
|
2011-04-02 19:52:21 +00:00
|
|
|
}
|
2011-02-24 16:22:42 +00:00
|
|
|
|
2011-09-26 18:04:02 +00:00
|
|
|
/* Plugin inputs match requested inputs exactly */
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
if (inputs == in) {
|
2013-08-02 03:39:00 +02:00
|
|
|
out = outputs + midi_bypass;
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (ExactMatch, 1);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2011-09-26 18:04:02 +00:00
|
|
|
/* We may be able to run more than one copy of the plugin within this insert
|
|
|
|
|
to cope with the insert having more inputs than the plugin.
|
|
|
|
|
We allow replication only for plugins with either zero or 1 inputs and outputs
|
|
|
|
|
for every valid data type.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-02-07 17:14:40 +00:00
|
|
|
uint32_t f = 0;
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
bool can_replicate = true;
|
2008-06-02 21:41:35 +00:00
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
2011-02-24 16:22:42 +00:00
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
uint32_t nin = inputs.get (*t);
|
2011-02-24 16:22:42 +00:00
|
|
|
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
// No inputs of this type
|
2011-02-24 16:22:42 +00:00
|
|
|
if (nin == 0 && in.get(*t) == 0) {
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
continue;
|
2011-04-02 19:52:21 +00:00
|
|
|
}
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
if (nin != 1 || outputs.get (*t) != 1) {
|
|
|
|
|
can_replicate = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-02-07 17:14:40 +00:00
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
// Potential factor not set yet
|
|
|
|
|
if (f == 0) {
|
|
|
|
|
f = in.get(*t) / nin;
|
|
|
|
|
}
|
2011-02-07 17:14:40 +00:00
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
// Factor for this type does not match another type, can not replicate
|
|
|
|
|
if (f != (in.get(*t) / nin)) {
|
|
|
|
|
can_replicate = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
if (can_replicate) {
|
2008-06-02 21:41:35 +00:00
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
The great audio processing overhaul.
The vast majority of Route signal processing is now simply in the list of
processors. There are definitely regressions here, but there's also
a lot of things fixed. It's far too much work to let diverge anymore
regardless, so here it is.
The basic model is: A route has a fixed set of input channels (matching
its JACK input ports and diskstream). The first processor takes this
as input. The next processor is configured using the first processor's
output as input, and is allowed to choose whatever output it wants
given that input... and so on, and so on. Finally, the last processor's
requested output is used to set up the panner and create whatever Jack
ports are needed to output the data.
All 'special' internal processors (meter, fader, amp, insert, send) are
currently transparent: they read any input, and return the same set
of channels back (unmodified, except for amp).
User visible changes:
* LV2 Instrument support (tracks with both MIDI and audio channels)
* MIDI in/out plugin support
* Generic plugin replication (for MIDI plugins, MIDI/audio plugins)
* Movable meter point
Known Bugs:
* Things seem to get weird on loaded sessions
* Output delivery is sketchy
* 2.0 session loading was probably already broken...
but it's definitely broken now :)
Please test this and file bugs if you have any time...
git-svn-id: svn://localhost/ardour2/branches/3.0@5055 d708f5d6-7413-0410-9779-e7cbd77b26cf
2009-05-07 06:30:50 +00:00
|
|
|
out.set (*t, outputs.get(*t) * f);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2013-08-02 03:39:00 +02:00
|
|
|
out += midi_bypass;
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (Replicate, f);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2011-01-31 15:28:15 +00:00
|
|
|
|
|
|
|
|
/* If the processor has exactly one input of a given type, and
|
|
|
|
|
the plugin has more, we can feed the single processor input
|
|
|
|
|
to some or all of the plugin inputs. This is rather
|
|
|
|
|
special-case-y, but the 1-to-many case is by far the
|
|
|
|
|
simplest. How do I split thy 2 processor inputs to 3
|
|
|
|
|
plugin inputs? Let me count the ways ...
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
bool can_split = true;
|
|
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
|
|
|
|
|
|
|
|
|
bool const can_split_type = (in.get (*t) == 1 && inputs.get (*t) > 1);
|
|
|
|
|
bool const nothing_to_do_for_type = (in.get (*t) == 0 && inputs.get (*t) == 0);
|
|
|
|
|
|
|
|
|
|
if (!can_split_type && !nothing_to_do_for_type) {
|
|
|
|
|
can_split = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (can_split) {
|
2013-08-02 03:39:00 +02:00
|
|
|
out = outputs + midi_bypass;
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (Split, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the plugin has more inputs than we want, we can `hide' some of them
|
|
|
|
|
by feeding them silence.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-10-19 14:26:16 +00:00
|
|
|
bool could_hide = false;
|
|
|
|
|
bool cannot_hide = false;
|
2011-09-26 18:07:02 +00:00
|
|
|
ChanCount hide_channels;
|
|
|
|
|
|
|
|
|
|
for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
|
|
|
|
|
if (inputs.get(*t) > in.get(*t)) {
|
2011-10-19 14:26:16 +00:00
|
|
|
/* there is potential to hide, since the plugin has more inputs of type t than the insert */
|
2011-09-26 18:07:02 +00:00
|
|
|
hide_channels.set (*t, inputs.get(*t) - in.get(*t));
|
2011-10-19 14:26:16 +00:00
|
|
|
could_hide = true;
|
|
|
|
|
} else if (inputs.get(*t) < in.get(*t)) {
|
|
|
|
|
/* we definitely cannot hide, since the plugin has fewer inputs of type t than the insert */
|
|
|
|
|
cannot_hide = true;
|
2011-09-26 18:07:02 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-19 14:26:16 +00:00
|
|
|
if (could_hide && !cannot_hide) {
|
2013-08-02 03:39:00 +02:00
|
|
|
out = outputs + midi_bypass;
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (Hide, 1, hide_channels);
|
2011-01-31 15:28:15 +00:00
|
|
|
}
|
|
|
|
|
|
2013-08-02 03:39:00 +02:00
|
|
|
midi_bypass.reset();
|
2011-09-26 18:07:02 +00:00
|
|
|
return Match (Impossible, 0);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XMLNode&
|
2011-09-26 18:04:02 +00:00
|
|
|
PluginInsert::get_state ()
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
return state (true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XMLNode&
|
|
|
|
|
PluginInsert::state (bool full)
|
|
|
|
|
{
|
|
|
|
|
XMLNode& node = Processor::state (full);
|
|
|
|
|
|
2009-02-15 03:21:30 +00:00
|
|
|
node.add_property("type", _plugins[0]->state_node_name());
|
2008-06-02 21:41:35 +00:00
|
|
|
node.add_property("unique-id", _plugins[0]->unique_id());
|
|
|
|
|
node.add_property("count", string_compose("%1", _plugins.size()));
|
|
|
|
|
node.add_child_nocopy (_plugins[0]->get_state());
|
|
|
|
|
|
2010-11-27 17:39:38 +00:00
|
|
|
for (Controls::iterator c = controls().begin(); c != controls().end(); ++c) {
|
2011-04-02 19:52:21 +00:00
|
|
|
boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> ((*c).second);
|
|
|
|
|
if (ac) {
|
|
|
|
|
node.add_child_nocopy (ac->get_state());
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-11-27 17:39:38 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-28 18:31:18 +00:00
|
|
|
void
|
|
|
|
|
PluginInsert::set_control_ids (const XMLNode& node, int version)
|
|
|
|
|
{
|
2011-04-02 19:52:21 +00:00
|
|
|
const XMLNodeList& nlist = node.children();
|
|
|
|
|
XMLNodeConstIterator iter;
|
|
|
|
|
set<Evoral::Parameter>::const_iterator p;
|
|
|
|
|
|
|
|
|
|
for (iter = nlist.begin(); iter != nlist.end(); ++iter) {
|
|
|
|
|
if ((*iter)->name() == Controllable::xml_node_name) {
|
|
|
|
|
const XMLProperty* prop;
|
|
|
|
|
|
|
|
|
|
if ((prop = (*iter)->property (X_("parameter"))) != 0) {
|
|
|
|
|
uint32_t p = atoi (prop->value());
|
2013-07-15 22:23:16 -04:00
|
|
|
|
|
|
|
|
/* this may create the new controllable */
|
|
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
boost::shared_ptr<Evoral::Control> c = control (Evoral::Parameter (PluginAutomation, 0, p));
|
2013-07-15 22:23:16 -04:00
|
|
|
|
|
|
|
|
#ifndef NO_PLUGIN_STATE
|
2011-04-02 19:52:21 +00:00
|
|
|
if (!c) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (c);
|
|
|
|
|
if (ac) {
|
|
|
|
|
ac->set_state (**iter, version);
|
|
|
|
|
}
|
2013-07-15 22:23:16 -04:00
|
|
|
#endif
|
2011-04-02 19:52:21 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-11-28 18:31:18 +00:00
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
int
|
2009-10-15 00:57:55 +00:00
|
|
|
PluginInsert::set_state(const XMLNode& node, int version)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
XMLNodeList nlist = node.children();
|
|
|
|
|
XMLNodeIterator niter;
|
|
|
|
|
XMLPropertyList plist;
|
|
|
|
|
const XMLProperty *prop;
|
|
|
|
|
ARDOUR::PluginType type;
|
|
|
|
|
|
|
|
|
|
if ((prop = node.property ("type")) == 0) {
|
2009-10-16 16:44:16 +00:00
|
|
|
error << _("XML node describing plugin is missing the `type' field") << endmsg;
|
2008-06-02 21:41:35 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (prop->value() == X_("ladspa") || prop->value() == X_("Ladspa")) { /* handle old school sessions */
|
|
|
|
|
type = ARDOUR::LADSPA;
|
|
|
|
|
} else if (prop->value() == X_("lv2")) {
|
|
|
|
|
type = ARDOUR::LV2;
|
2011-11-21 17:42:29 +00:00
|
|
|
} else if (prop->value() == X_("windows-vst")) {
|
|
|
|
|
type = ARDOUR::Windows_VST;
|
2011-09-20 20:29:47 +00:00
|
|
|
} else if (prop->value() == X_("lxvst")) {
|
|
|
|
|
type = ARDOUR::LXVST;
|
2009-10-16 16:44:16 +00:00
|
|
|
} else if (prop->value() == X_("audiounit")) {
|
|
|
|
|
type = ARDOUR::AudioUnit;
|
2008-06-02 21:41:35 +00:00
|
|
|
} else {
|
|
|
|
|
error << string_compose (_("unknown plugin type %1 in plugin insert state"),
|
|
|
|
|
prop->value())
|
|
|
|
|
<< endmsg;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
prop = node.property ("unique-id");
|
2009-10-16 16:44:16 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
if (prop == 0) {
|
2011-11-21 17:42:29 +00:00
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
2009-10-16 16:44:16 +00:00
|
|
|
/* older sessions contain VST plugins with only an "id" field.
|
|
|
|
|
*/
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2011-11-21 17:42:29 +00:00
|
|
|
if (type == ARDOUR::Windows_VST) {
|
2009-10-16 16:44:16 +00:00
|
|
|
prop = node.property ("id");
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
#endif
|
2011-09-20 20:29:47 +00:00
|
|
|
|
|
|
|
|
#ifdef LXVST_SUPPORT
|
|
|
|
|
/*There shouldn't be any older sessions with linuxVST support.. but anyway..*/
|
|
|
|
|
|
|
|
|
|
if (type == ARDOUR::LXVST) {
|
|
|
|
|
prop = node.property ("id");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2009-10-16 16:44:16 +00:00
|
|
|
/* recheck */
|
|
|
|
|
|
|
|
|
|
if (prop == 0) {
|
|
|
|
|
error << _("Plugin has no unique ID field") << endmsg;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2011-04-03 01:57:12 +00:00
|
|
|
boost::shared_ptr<Plugin> plugin = find_plugin (_session, prop->value(), type);
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2014-02-28 17:35:43 +01:00
|
|
|
/* treat linux and windows VST plugins equivalent if they have the same uniqueID
|
2014-02-27 00:44:48 +01:00
|
|
|
* allow to move sessions windows <> linux */
|
|
|
|
|
#ifdef LXVST_SUPPORT
|
|
|
|
|
if (plugin == 0 && type == ARDOUR::Windows_VST) {
|
|
|
|
|
type = ARDOUR::LXVST;
|
|
|
|
|
plugin = find_plugin (_session, prop->value(), type);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef WINDOWS_VST_SUPPORT
|
|
|
|
|
if (plugin == 0 && type == ARDOUR::LXVST) {
|
|
|
|
|
type = ARDOUR::Windows_VST;
|
|
|
|
|
plugin = find_plugin (_session, prop->value(), type);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
if (plugin == 0) {
|
2011-04-03 01:57:12 +00:00
|
|
|
error << string_compose(
|
|
|
|
|
_("Found a reference to a plugin (\"%1\") that is unknown.\n"
|
|
|
|
|
"Perhaps it was removed or moved since it was last used."),
|
|
|
|
|
prop->value())
|
2008-06-02 21:41:35 +00:00
|
|
|
<< endmsg;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-09 20:21:46 +00:00
|
|
|
// The name of the PluginInsert comes from the plugin, nothing else
|
|
|
|
|
_name = plugin->get_info()->name;
|
|
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
uint32_t count = 1;
|
2009-10-16 16:44:16 +00:00
|
|
|
|
2011-07-01 15:48:24 +00:00
|
|
|
// Processor::set_state() will set this, but too late
|
|
|
|
|
// for it to be available when setting up plugin
|
|
|
|
|
// state. We can't call Processor::set_state() until
|
|
|
|
|
// the plugins themselves are created and added.
|
|
|
|
|
|
2011-10-18 13:18:47 +00:00
|
|
|
set_id (node);
|
2011-07-01 15:48:24 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
if (_plugins.empty()) {
|
|
|
|
|
/* if we are adding the first plugin, we will need to set
|
|
|
|
|
up automatable controls.
|
|
|
|
|
*/
|
2011-06-09 20:21:46 +00:00
|
|
|
add_plugin (plugin);
|
|
|
|
|
create_automatable_parameters ();
|
|
|
|
|
set_control_ids (node, version);
|
2009-10-16 16:44:16 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
|
|
|
|
if ((prop = node.property ("count")) != 0) {
|
|
|
|
|
sscanf (prop->value().c_str(), "%u", &count);
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-09 20:21:46 +00:00
|
|
|
if (_plugins.size() != count) {
|
|
|
|
|
for (uint32_t n = 1; n < count; ++n) {
|
|
|
|
|
add_plugin (plugin_factory (plugin));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-01 15:48:24 +00:00
|
|
|
Processor::set_state (node, version);
|
|
|
|
|
|
2011-04-04 17:57:18 +00:00
|
|
|
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
|
|
|
|
|
2011-06-09 20:21:46 +00:00
|
|
|
/* find the node with the type-specific node name ("lv2", "ladspa", etc)
|
|
|
|
|
and set all plugins to the same state.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-04-04 17:57:18 +00:00
|
|
|
if ((*niter)->name() == plugin->state_node_name()) {
|
|
|
|
|
|
|
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
|
|
|
|
(*i)->set_state (**niter, version);
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-09 20:21:46 +00:00
|
|
|
break;
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
if (version < 3000) {
|
2010-03-28 19:07:23 +00:00
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
/* Only 2.X sessions need a call to set_parameter_state() - in 3.X and above
|
|
|
|
|
this is all handled by Automatable
|
|
|
|
|
*/
|
2010-08-25 19:27:41 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
|
|
|
|
if ((*niter)->name() == "Redirect") {
|
|
|
|
|
/* XXX do we need to tackle placement? i think not (pd; oct 16 2009) */
|
|
|
|
|
Processor::set_state (**niter, version);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2010-08-25 19:27:41 +00:00
|
|
|
set_parameter_state_2X (node, version);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2011-06-09 20:21:46 +00:00
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
|
|
|
|
if (active()) {
|
|
|
|
|
(*i)->activate ();
|
|
|
|
|
} else {
|
|
|
|
|
(*i)->deactivate ();
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
void
|
|
|
|
|
PluginInsert::set_parameter_state_2X (const XMLNode& node, int version)
|
|
|
|
|
{
|
|
|
|
|
XMLNodeList nlist = node.children();
|
|
|
|
|
XMLNodeIterator niter;
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
/* look for port automation node */
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
if ((*niter)->name() != port_automation_node_name) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
XMLNodeList cnodes;
|
|
|
|
|
XMLProperty *cprop;
|
|
|
|
|
XMLNodeConstIterator iter;
|
|
|
|
|
XMLNode *child;
|
|
|
|
|
const char *port;
|
|
|
|
|
uint32_t port_id;
|
2011-02-01 01:07:38 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
cnodes = (*niter)->children ("port");
|
2011-02-01 01:07:38 +00:00
|
|
|
|
2010-03-28 19:07:23 +00:00
|
|
|
for (iter = cnodes.begin(); iter != cnodes.end(); ++iter){
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
child = *iter;
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
if ((cprop = child->property("number")) != 0) {
|
|
|
|
|
port = cprop->value().c_str();
|
|
|
|
|
} else {
|
|
|
|
|
warning << _("PluginInsert: Auto: no ladspa port number") << endmsg;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
sscanf (port, "%" PRIu32, &port_id);
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
if (port_id >= _plugins[0]->parameter_count()) {
|
|
|
|
|
warning << _("PluginInsert: Auto: port id out of range") << endmsg;
|
|
|
|
|
continue;
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
boost::shared_ptr<AutomationControl> c = boost::dynamic_pointer_cast<AutomationControl>(
|
2010-02-05 20:03:57 +00:00
|
|
|
control(Evoral::Parameter(PluginAutomation, 0, port_id), true));
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2015-06-01 18:17:34 +02:00
|
|
|
if (c && c->alist()) {
|
2009-10-16 16:44:16 +00:00
|
|
|
if (!child->children().empty()) {
|
|
|
|
|
c->alist()->set_state (*child->children().front(), version);
|
2011-02-01 01:07:38 +00:00
|
|
|
|
|
|
|
|
/* In some cases 2.X saves lists with min_yval and max_yval
|
|
|
|
|
being FLT_MIN and FLT_MAX respectively. This causes problems
|
|
|
|
|
in A3 because these min/max values are used to compute
|
|
|
|
|
where GUI control points should be drawn. If we see such
|
|
|
|
|
values, `correct' them to the min/max of the appropriate
|
|
|
|
|
parameter.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
float min_y = c->alist()->get_min_y ();
|
|
|
|
|
float max_y = c->alist()->get_max_y ();
|
|
|
|
|
|
2014-10-31 23:48:27 -04:00
|
|
|
ParameterDescriptor desc;
|
2011-02-01 01:07:38 +00:00
|
|
|
_plugins.front()->get_parameter_descriptor (port_id, desc);
|
|
|
|
|
|
|
|
|
|
if (min_y == FLT_MIN) {
|
|
|
|
|
min_y = desc.lower;
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2011-02-01 01:07:38 +00:00
|
|
|
if (max_y == FLT_MAX) {
|
|
|
|
|
max_y = desc.upper;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c->alist()->set_yrange (min_y, max_y);
|
2009-10-16 16:44:16 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
error << string_compose (_("PluginInsert: automatable control %1 not found - ignored"), port_id) << endmsg;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
/* done */
|
2011-04-02 19:52:21 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
break;
|
2011-04-02 19:52:21 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2009-10-16 16:44:16 +00:00
|
|
|
|
2008-06-02 21:41:35 +00:00
|
|
|
string
|
2008-09-29 22:47:40 +00:00
|
|
|
PluginInsert::describe_parameter (Evoral::Parameter param)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
2014-11-01 23:29:10 -04:00
|
|
|
if (param.type() == PluginAutomation) {
|
|
|
|
|
return _plugins[0]->describe_parameter (param);
|
|
|
|
|
} else if (param.type() == PluginPropertyAutomation) {
|
|
|
|
|
boost::shared_ptr<AutomationControl> c(automation_control(param));
|
|
|
|
|
if (c && !c->desc().label.empty()) {
|
|
|
|
|
return c->desc().label;
|
|
|
|
|
}
|
2011-04-02 19:52:21 +00:00
|
|
|
}
|
2014-11-01 23:29:10 -04:00
|
|
|
return Automatable::describe_parameter(param);
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2010-12-03 22:26:29 +00:00
|
|
|
ARDOUR::framecnt_t
|
2008-06-02 21:41:35 +00:00
|
|
|
PluginInsert::signal_latency() const
|
|
|
|
|
{
|
|
|
|
|
if (_user_latency) {
|
|
|
|
|
return _user_latency;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _plugins[0]->signal_latency ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ARDOUR::PluginType
|
|
|
|
|
PluginInsert::type ()
|
|
|
|
|
{
|
2010-04-15 20:42:05 +00:00
|
|
|
return plugin()->get_info()->type;
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2014-11-01 23:29:10 -04:00
|
|
|
PluginInsert::PluginControl::PluginControl (PluginInsert* p,
|
|
|
|
|
const Evoral::Parameter& param,
|
|
|
|
|
const ParameterDescriptor& desc,
|
|
|
|
|
boost::shared_ptr<AutomationList> list)
|
|
|
|
|
: AutomationControl (p->session(), param, desc, list, p->describe_parameter(param))
|
2008-06-02 21:41:35 +00:00
|
|
|
, _plugin (p)
|
|
|
|
|
{
|
2014-11-01 23:29:10 -04:00
|
|
|
if (alist()) {
|
|
|
|
|
alist()->reset_default (desc.normal);
|
2014-11-29 01:40:23 -05:00
|
|
|
if (desc.toggled) {
|
|
|
|
|
list->set_interpolation(Evoral::ControlList::Discrete);
|
|
|
|
|
}
|
2014-11-01 23:29:10 -04:00
|
|
|
}
|
2014-03-23 18:59:24 +01:00
|
|
|
|
|
|
|
|
if (desc.toggled) {
|
|
|
|
|
set_flags(Controllable::Toggle);
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2011-02-15 01:42:48 +00:00
|
|
|
/** @param val `user' value */
|
2008-06-02 21:41:35 +00:00
|
|
|
void
|
2011-02-15 01:42:48 +00:00
|
|
|
PluginInsert::PluginControl::set_value (double user_val)
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
/* FIXME: probably should be taking out some lock here.. */
|
2009-10-14 16:10:01 +00:00
|
|
|
|
2011-02-15 01:42:48 +00:00
|
|
|
for (Plugins::iterator i = _plugin->_plugins.begin(); i != _plugin->_plugins.end(); ++i) {
|
2012-01-20 18:02:36 +00:00
|
|
|
(*i)->set_parameter (_list->parameter().id(), user_val);
|
2011-02-15 01:42:48 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-02-15 01:42:48 +00:00
|
|
|
boost::shared_ptr<Plugin> iasp = _plugin->_impulseAnalysisPlugin.lock();
|
|
|
|
|
if (iasp) {
|
2012-01-20 18:02:36 +00:00
|
|
|
iasp->set_parameter (_list->parameter().id(), user_val);
|
2011-02-15 01:42:48 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-02-15 01:42:48 +00:00
|
|
|
AutomationControl::set_value (user_val);
|
|
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
|
2011-02-15 01:42:48 +00:00
|
|
|
double
|
2012-01-21 16:38:56 +00:00
|
|
|
PluginInsert::PluginControl::internal_to_interface (double val) const
|
2011-02-15 01:42:48 +00:00
|
|
|
{
|
2014-09-18 16:35:03 -05:00
|
|
|
val = Controllable::internal_to_interface(val);
|
|
|
|
|
|
2014-11-01 23:29:10 -04:00
|
|
|
if (_desc.logarithmic) {
|
2011-02-15 01:42:48 +00:00
|
|
|
if (val > 0) {
|
2014-09-18 16:35:03 -05:00
|
|
|
val = pow (val, 1/1.5);
|
2011-02-15 01:42:48 +00:00
|
|
|
} else {
|
2014-09-18 16:35:03 -05:00
|
|
|
val = 0;
|
2011-02-15 01:42:48 +00:00
|
|
|
}
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2011-02-15 01:42:48 +00:00
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
2012-01-21 16:38:56 +00:00
|
|
|
PluginInsert::PluginControl::interface_to_internal (double val) const
|
2011-02-15 01:42:48 +00:00
|
|
|
{
|
2014-11-01 23:29:10 -04:00
|
|
|
if (_desc.logarithmic) {
|
2014-09-18 16:35:03 -05:00
|
|
|
if (val <= 0) {
|
2014-11-01 23:29:10 -04:00
|
|
|
val = 0;
|
2014-01-06 00:01:24 +01:00
|
|
|
} else {
|
2014-09-18 16:35:03 -05:00
|
|
|
val = pow (val, 1.5);
|
2014-01-06 00:01:24 +01:00
|
|
|
}
|
2011-02-15 01:42:48 +00:00
|
|
|
}
|
|
|
|
|
|
2014-09-18 16:35:03 -05:00
|
|
|
val = Controllable::interface_to_internal(val);
|
|
|
|
|
|
2011-02-15 01:42:48 +00:00
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2010-11-28 18:31:18 +00:00
|
|
|
XMLNode&
|
|
|
|
|
PluginInsert::PluginControl::get_state ()
|
|
|
|
|
{
|
2011-04-02 19:52:21 +00:00
|
|
|
stringstream ss;
|
2010-11-28 18:31:18 +00:00
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
XMLNode& node (AutomationControl::get_state());
|
|
|
|
|
ss << parameter().id();
|
|
|
|
|
node.add_property (X_("parameter"), ss.str());
|
2010-11-28 18:31:18 +00:00
|
|
|
|
2011-04-02 19:52:21 +00:00
|
|
|
return node;
|
2010-11-28 18:31:18 +00:00
|
|
|
}
|
|
|
|
|
|
2011-02-20 17:57:45 +00:00
|
|
|
/** @return `user' val */
|
2010-07-27 14:09:16 +00:00
|
|
|
double
|
2011-02-20 17:57:45 +00:00
|
|
|
PluginInsert::PluginControl::get_value () const
|
2008-06-02 21:41:35 +00:00
|
|
|
{
|
|
|
|
|
/* FIXME: probably should be taking out some lock here.. */
|
2012-01-20 18:02:36 +00:00
|
|
|
return _plugin->get_parameter (_list->parameter());
|
2008-06-02 21:41:35 +00:00
|
|
|
}
|
|
|
|
|
|
2014-11-01 23:29:10 -04:00
|
|
|
PluginInsert::PluginPropertyControl::PluginPropertyControl (PluginInsert* p,
|
|
|
|
|
const Evoral::Parameter& param,
|
|
|
|
|
const ParameterDescriptor& desc,
|
|
|
|
|
boost::shared_ptr<AutomationList> list)
|
|
|
|
|
: AutomationControl (p->session(), param, desc, list)
|
|
|
|
|
, _plugin (p)
|
|
|
|
|
{
|
|
|
|
|
if (alist()) {
|
|
|
|
|
alist()->set_yrange (desc.lower, desc.upper);
|
|
|
|
|
alist()->reset_default (desc.normal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (desc.toggled) {
|
|
|
|
|
set_flags(Controllable::Toggle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::PluginPropertyControl::set_value (double user_val)
|
|
|
|
|
{
|
|
|
|
|
/* Old numeric set_value(), coerce to appropriate datatype if possible.
|
|
|
|
|
This is lossy, but better than nothing until Ardour's automation system
|
|
|
|
|
can handle various datatypes all the way down. */
|
|
|
|
|
const Variant value(_desc.datatype, user_val);
|
2014-11-07 17:21:43 -05:00
|
|
|
if (value.type() == Variant::NOTHING) {
|
2014-11-01 23:29:10 -04:00
|
|
|
error << "set_value(double) called for non-numeric property" << endmsg;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (Plugins::iterator i = _plugin->_plugins.begin(); i != _plugin->_plugins.end(); ++i) {
|
|
|
|
|
(*i)->set_property(_list->parameter().id(), value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_value = value;
|
|
|
|
|
AutomationControl::set_value(user_val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
XMLNode&
|
|
|
|
|
PluginInsert::PluginPropertyControl::get_state ()
|
|
|
|
|
{
|
|
|
|
|
stringstream ss;
|
|
|
|
|
|
|
|
|
|
XMLNode& node (AutomationControl::get_state());
|
|
|
|
|
ss << parameter().id();
|
|
|
|
|
node.add_property (X_("property"), ss.str());
|
|
|
|
|
node.remove_property (X_("value"));
|
|
|
|
|
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double
|
|
|
|
|
PluginInsert::PluginPropertyControl::get_value () const
|
|
|
|
|
{
|
|
|
|
|
return _value.to_double();
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-13 19:45:20 +00:00
|
|
|
boost::shared_ptr<Plugin>
|
|
|
|
|
PluginInsert::get_impulse_analysis_plugin()
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<Plugin> ret;
|
|
|
|
|
if (_impulseAnalysisPlugin.expired()) {
|
|
|
|
|
ret = plugin_factory(_plugins[0]);
|
|
|
|
|
_impulseAnalysisPlugin = ret;
|
|
|
|
|
} else {
|
|
|
|
|
ret = _impulseAnalysisPlugin.lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-04 15:50:51 +00:00
|
|
|
void
|
2010-12-03 22:26:29 +00:00
|
|
|
PluginInsert::collect_signal_for_analysis (framecnt_t nframes)
|
2009-05-04 15:50:51 +00:00
|
|
|
{
|
|
|
|
|
// called from outside the audio thread, so this should be safe
|
2009-05-08 05:20:23 +00:00
|
|
|
// only do audio as analysis is (currently) only for audio plugins
|
2009-10-14 16:10:01 +00:00
|
|
|
_signal_analysis_inputs.ensure_buffers( DataType::AUDIO, input_streams().n_audio(), nframes);
|
|
|
|
|
_signal_analysis_outputs.ensure_buffers( DataType::AUDIO, output_streams().n_audio(), nframes);
|
2009-05-04 15:50:51 +00:00
|
|
|
|
|
|
|
|
_signal_analysis_collected_nframes = 0;
|
2009-10-14 16:10:01 +00:00
|
|
|
_signal_analysis_collect_nframes_max = nframes;
|
2009-05-04 15:50:51 +00:00
|
|
|
}
|
|
|
|
|
|
2011-06-09 20:21:46 +00:00
|
|
|
/** Add a plugin to our list */
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::add_plugin (boost::shared_ptr<Plugin> plugin)
|
|
|
|
|
{
|
2014-11-03 13:40:50 -05:00
|
|
|
plugin->set_insert_id (this->id());
|
2012-07-11 00:23:55 +00:00
|
|
|
|
|
|
|
|
if (_plugins.empty()) {
|
2012-07-11 15:31:02 +00:00
|
|
|
/* first (and probably only) plugin instance - connect to relevant signals
|
|
|
|
|
*/
|
|
|
|
|
|
2012-07-11 00:23:55 +00:00
|
|
|
plugin->ParameterChanged.connect_same_thread (*this, boost::bind (&PluginInsert::parameter_changed, this, _1, _2));
|
2012-07-11 15:31:02 +00:00
|
|
|
plugin->StartTouch.connect_same_thread (*this, boost::bind (&PluginInsert::start_touch, this, _1));
|
|
|
|
|
plugin->EndTouch.connect_same_thread (*this, boost::bind (&PluginInsert::end_touch, this, _1));
|
2012-07-11 00:23:55 +00:00
|
|
|
}
|
|
|
|
|
|
2011-06-09 20:21:46 +00:00
|
|
|
_plugins.push_back (plugin);
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-07 14:44:47 +00:00
|
|
|
void
|
|
|
|
|
PluginInsert::realtime_handle_transport_stopped ()
|
|
|
|
|
{
|
|
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
|
|
|
|
(*i)->realtime_handle_transport_stopped ();
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-12-26 17:01:31 +00:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::realtime_locate ()
|
|
|
|
|
{
|
|
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
|
|
|
|
(*i)->realtime_locate ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::monitoring_changed ()
|
|
|
|
|
{
|
|
|
|
|
for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
|
|
|
|
|
(*i)->monitoring_changed ();
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-07-11 15:31:02 +00:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::start_touch (uint32_t param_id)
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
|
|
|
|
|
if (ac) {
|
|
|
|
|
ac->start_touch (session().audible_frame());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
PluginInsert::end_touch (uint32_t param_id)
|
|
|
|
|
{
|
|
|
|
|
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
|
|
|
|
|
if (ac) {
|
|
|
|
|
ac->stop_touch (true, session().audible_frame());
|
|
|
|
|
}
|
|
|
|
|
}
|