along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- $Id$
*/
#include <string>
#include <ardour/route.h>
#include <ardour/ladspa_plugin.h>
+#ifdef HAVE_SLV2
+#include <ardour/lv2_plugin.h>
+#endif
+
#ifdef VST_SUPPORT
#include <ardour/vst_plugin.h>
#endif
using namespace ARDOUR;
using namespace PBD;
-Insert::Insert(Session& s, Placement p)
- : Redirect (s, s.next_insert_name(), p)
-{
-}
-
-Insert::Insert(Session& s, Placement p, int imin, int imax, int omin, int omax)
- : Redirect (s, s.next_insert_name(), p, imin, imax, omin, omax)
+Insert::Insert(Session& s, string name, Placement p)
+ : Redirect (s, name, p)
{
}
-Insert::Insert(Session& s, string name, Placement p)
- : Redirect (s, name, p)
+Insert::Insert(Session& s, string name, Placement p, int imin, int imax, int omin, int omax)
+ : Redirect (s, name, p, imin, imax, omin, omax)
{
}
init ();
- {
+ if (_plugins[0]->fixed_io()) {
Glib::Mutex::Lock em (_session.engine().process_lock());
IO::MoreOutputs (output_streams ());
}
_plugins[0]->ParameterChanged.connect (mem_fun (*this, &PluginInsert::parameter_changed));
- {
+ if (_plugins[0]->fixed_io()) {
Glib::Mutex::Lock em (_session.engine().process_lock());
IO::MoreOutputs (output_streams());
}
void
PluginInsert::automation_list_creation_callback (uint32_t which, AutomationList& alist)
{
- alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
+ alist.automation_state_changed.connect (sigc::bind (mem_fun (*this, &PluginInsert::auto_state_changed), (which)));
}
void
uint32_t
PluginInsert::output_streams() const
{
- return _plugins[0]->get_info()->n_outputs * _plugins.size();
+ int32_t out = _plugins[0]->get_info()->n_outputs;
+
+ if (out < 0) {
+ return _plugins[0]->output_streams ();
+ } else {
+ return out * _plugins.size();
+ }
}
uint32_t
PluginInsert::input_streams() const
{
- return _plugins[0]->get_info()->n_inputs * _plugins.size();
+ int32_t in = _plugins[0]->get_info()->n_inputs;
+ if (in < 0) {
+ return _plugins[0]->input_streams ();
+ } else {
+ return in * _plugins.size();
+ }
}
uint32_t
uint32_t in = _plugins[0]->get_info()->n_inputs;
uint32_t out = _plugins[0]->get_info()->n_outputs;
- if (out > in) {
-
- /* not active, but something has make up for any channel count increase */
+ if (in < 0 || out < 0) {
- for (uint32_t n = out - in; n < out; ++n) {
- memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
+ } else {
+
+ if (out > in) {
+
+ /* not active, but something has make up for any channel count increase */
+
+ for (uint32_t n = out - in; n < out; ++n) {
+ memcpy (bufs[n], bufs[in - 1], sizeof (Sample) * nframes);
+ }
}
}
}
while (nframes) {
- nframes_t cnt = min (((nframes_t) floor (next_event.when) - now), nframes);
+ nframes_t cnt = min (((nframes_t) ceil (next_event.when) - now), nframes);
connect_and_run (bufs, nbufs, cnt, offset, true, now);
switch (al.automation_state()) {
case Write:
- case Touch:
al.set_automation_state (Off);
break;
+ case Touch:
+ al.set_automation_state (Play);
+ break;
default:
break;
}
PluginInsert::plugin_factory (boost::shared_ptr<Plugin> other)
{
boost::shared_ptr<LadspaPlugin> lp;
+#ifdef HAVE_SLV2
+ boost::shared_ptr<LV2Plugin> lv2p;
+#endif
#ifdef VST_SUPPORT
boost::shared_ptr<VSTPlugin> vp;
#endif
if ((lp = boost::dynamic_pointer_cast<LadspaPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new LadspaPlugin (*lp));
+#ifdef HAVE_SLV2
+ } else if ((lv2p = boost::dynamic_pointer_cast<LV2Plugin> (other)) != 0) {
+ return boost::shared_ptr<Plugin> (new LV2Plugin (*lv2p));
+#endif
#ifdef VST_SUPPORT
} else if ((vp = boost::dynamic_pointer_cast<VSTPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new VSTPlugin (*vp));
int32_t
PluginInsert::compute_output_streams (int32_t cnt) const
{
- return _plugins[0]->get_info()->n_outputs * cnt;
+ int32_t outputs;
+
+ if ((outputs = _plugins[0]->get_info()->n_outputs) < 0) {
+ // have to ask the plugin itself, because it has flexible I/O
+ return _plugins[0]->compute_output_streams (cnt);
+ }
+
+ return outputs * cnt;
}
int32_t
int32_t outputs = _plugins[0]->get_info()->n_outputs;
int32_t inputs = _plugins[0]->get_info()->n_inputs;
+ if (outputs < 0 || inputs < 0) {
+ /* have to ask the plugin because its got reconfigurable I/O
+ */
+ return _plugins[0]->can_support_input_configuration (in);
+ }
+
if (inputs == 0) {
/* instrument plugin, always legal, but it throws
node->add_child_nocopy (Redirect::state (full));
node->add_property ("type", _plugins[0]->state_node_name());
- snprintf(buf, sizeof(buf), "%s", _plugins[0]->name());
- node->add_property("id", string(buf));
- if (_plugins[0]->state_node_name() == "ladspa") {
- char buf[32];
- snprintf (buf, sizeof (buf), "%ld", _plugins[0]->get_info()->unique_id);
- node->add_property("unique-id", string(buf));
- }
+ 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());
+ /* add controllables */
+
+ XMLNode* control_node = new XMLNode (X_("controls"));
+
+ for (uint32_t x = 0; x < _plugins[0]->parameter_count(); ++x) {
+ Controllable* c = _plugins[0]->get_nth_control (x, true);
+ if (c) {
+ XMLNode& controllable_state (c->get_state());
+ controllable_state.add_property ("parameter", to_string (x, std::dec));
+ control_node->add_child_nocopy (controllable_state);
+ }
+ }
+ node->add_child_nocopy (*control_node);
+
/* add port automation state */
XMLNode *autonode = new XMLNode(port_automation_node_name);
set<uint32_t> automatable = _plugins[0]->automatable();
XMLNodeIterator niter;
XMLPropertyList plist;
const XMLProperty *prop;
- long unique = 0;
ARDOUR::PluginType type;
if ((prop = node.property ("type")) == 0) {
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;
} else if (prop->value() == X_("vst")) {
type = ARDOUR::VST;
+ } else if (prop->value() == X_("audiounit")) {
+ type = ARDOUR::AudioUnit;
} else {
error << string_compose (_("unknown plugin type %1 in plugin insert state"),
prop->value())
}
prop = node.property ("unique-id");
- if (prop != 0) {
- unique = atol(prop->value().c_str());
- }
+ if (prop == 0) {
+#ifdef VST_SUPPORT
+ /* older sessions contain VST plugins with only an "id" field.
+ */
+
+ if (type == ARDOUR::VST) {
+ if (prop = node.property ("id")) {
+ }
+ }
+#endif
+ /* recheck */
- if ((prop = node.property ("id")) == 0) {
- error << _("XML node describing insert is missing the `id' field") << endmsg;
- return -1;
+ if (prop == 0) {
+ error << _("Plugin has no unique ID field") << endmsg;
+ return -1;
+ }
}
boost::shared_ptr<Plugin> plugin;
- if (unique != 0) {
- plugin = find_plugin (_session, "", unique, type);
- } else {
- plugin = find_plugin (_session, prop->value(), 0, type);
- }
+ plugin = find_plugin (_session, prop->value(), type);
if (plugin == 0) {
error << string_compose(_("Found a reference to a plugin (\"%1\") that is unknown.\n"
}
}
+ if (niter == nlist.end()) {
+ error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
+ return -1;
+ }
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == Redirect::state_node_name) {
Redirect::set_state (**niter);
return -1;
}
- if (niter == nlist.end()) {
- error << string_compose(_("XML node describing a plugin insert is missing the `%1' information"), plugin->state_node_name()) << endmsg;
- return -1;
- }
+ /* look for controllables node */
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+
+ if ((*niter)->name() != X_("controls")) {
+ continue;
+ }
+
+ XMLNodeList grandchildren ((*niter)->children());
+ XMLProperty* prop;
+ XMLNodeIterator gciter;
+ uint32_t param;
+
+ for (gciter = grandchildren.begin(); gciter != grandchildren.end(); ++gciter) {
+ if ((prop = (*gciter)->property (X_("parameter"))) != 0) {
+ param = atoi (prop->value());
+ /* force creation of controllable for this parameter */
+ _plugins[0]->make_nth_control (param, **gciter);
+ }
+ }
+
+ break;
+ }
+
/* look for port automation node */
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
***************************************************************/
PortInsert::PortInsert (Session& s, Placement p)
- : Insert (s, p, 1, -1, 1, -1)
+ : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
{
init ();
RedirectCreated (this); /* EMIT SIGNAL */
}
PortInsert::PortInsert (const PortInsert& other)
- : Insert (other._session, other.placement(), 1, -1, 1, -1)
+ : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
{
init ();
RedirectCreated (this); /* EMIT SIGNAL */
PortInsert::PortInsert (Session& s, const XMLNode& node)
: Insert (s, "will change", PreFader)
{
+ bitslot = 0xffffffff;
if (set_state (node)) {
throw failed_constructor();
}
PortInsert::state (bool full)
{
XMLNode *node = new XMLNode("Insert");
-
+ char buf[32];
node->add_child_nocopy (Redirect::state(full));
- node->add_property("type", "port");
+ node->add_property ("type", "port");
+ snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
+ node->add_property ("bitslot", buf);
return *node;
}
return -1;
}
+ if ((prop = node.property ("bitslot")) == 0) {
+ bitslot = _session.next_insert_id();
+ } else {
+ uint32_t old_bitslot = bitslot;
+ sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
+
+ if (old_bitslot != bitslot) {
+ _session.mark_insert_id (bitslot);
+ }
+ }
+
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == Redirect::state_node_name) {
Redirect::set_state (**niter);