#include "ardour/lxvst_plugin.h"
#endif
+#ifdef MACVST_SUPPORT
+#include "ardour/mac_vst_plugin.h"
+#endif
+
#ifdef AUDIOUNIT_SUPPORT
#include "ardour/audio_unit.h"
#endif
, _strict_io (false)
, _custom_cfg (false)
, _maps_from_state (false)
+ , _latency_changed (false)
, _bypass_port (UINT32_MAX)
{
/* the first is the master */
}
bool
-PluginInsert::needs_midi_input() const
+PluginInsert::is_instrument() const
{
PluginInfoPtr pip = _plugins[0]->get_info();
- if (pip->needs_midi_input ()) {
+ if (pip->is_instrument ()) {
return true;
}
- return pip->n_inputs.n_midi() != 0 && pip->n_outputs.n_audio() != 0;
+ return pip->n_inputs.n_midi () != 0 && pip->n_outputs.n_audio () > 0 && pip->n_inputs.n_audio () == 0;
}
bool
return false;
}
}
- if (!needs_midi_input ()) {
+
+ if (ppc.size () == 1 && ppc.find (0) != ppc.end () && !_plugins[0]->get_info ()->reconfigurable_io ()) {
+ // some midi-sequencer (e.g. QMidiArp) or other midi-out plugin
+ // pretending to be an "Instrument"
+ return false;
+ }
+
+ if (!is_instrument ()) {
return false;
}
return true;
_bypass_port = plugin->designated_bypass_port ();
+ /* special case VST effSetBypass */
+ if (_bypass_port == UINT32_MAX -1) {
+ // emulate VST Bypass
+ Evoral::Parameter param (PluginAutomation, 0, _bypass_port);
+ ParameterDescriptor desc;
+ desc.label = _("Plugin Enable");
+ desc.toggled = true;
+ desc.normal = 1;
+ desc.lower = 0;
+ desc.upper = 1;
+ boost::shared_ptr<AutomationList> list(new AutomationList(param, desc));
+ boost::shared_ptr<AutomationControl> c (new PluginControl(this, param, desc, list));
+ add_control (c);
+ }
+
if (_bypass_port != UINT32_MAX) {
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, _bypass_port));
if (0 == (ac->flags () & Controllable::NotAutomatable)) {
ac->Changed.connect_same_thread (*this, boost::bind (&PluginInsert::enable_changed, this));
}
}
+ plugin->PresetPortSetValue.connect_same_thread (*this, boost::bind (&PluginInsert::preset_load_set_value, this, _1, _2));
}
+
/** Called when something outside of this host has modified a plugin
* parameter. Responsible for propagating the change to two places:
*
}
Processor::activate ();
+ /* when setting state e.g ProcessorBox::paste_processor_state ()
+ * the plugin is not yet owned by a route.
+ * but no matter. Route::add_processors() will call activate () again
+ */
+ if (!owner ()) {
+ return;
+ }
if (_plugin_signal_latency != signal_latency ()) {
_plugin_signal_latency = signal_latency ();
latency_changed ();
activate ();
}
boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, _bypass_port));
- ac->set_value (yn ? 1.0 : 0.0, Controllable::NoGroup);
+ const double val = yn ? 1.0 : 0.0;
+ ac->set_value (val, Controllable::NoGroup);
+
+#ifdef ALLOW_VST_BYPASS_TO_FAIL // yet unused, see also vst_plugin.cc
+ /* special case VST.. bypass may fail */
+ if (_bypass_port == UINT32_MAX - 1) {
+ /* check if bypass worked */
+ if (ac->get_value () != val) {
+ warning << _("PluginInsert: VST Bypass failed, falling back to host bypass.") << endmsg;
+ // set plugin to enabled (not-byassed)
+ ac->set_value (1.0, Controllable::NoGroup);
+ // ..and use host-provided hard-bypass
+ if (yn) {
+ activate ();
+ } else {
+ deactivate ();
+ }
+ return;
+ }
+ }
+#endif
ActiveChanged ();
}
}
BypassableChanged ();
}
+void
+PluginInsert::preset_load_set_value (uint32_t p, float v)
+{
+ boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter(PluginAutomation, 0, p));
+ if (!ac) {
+ return;
+ }
+
+ if (ac->automation_state() & Play) {
+ return;
+ }
+
+ start_touch (p);
+ ac->set_value (v, Controllable::NoGroup);
+ end_touch (p);
+}
+
void
PluginInsert::inplace_silence_unconnected (BufferSet& bufs, const PinMappings& out_map, framecnt_t nframes, framecnt_t offset) const
{
if (_session.transport_rolling() || _session.bounce_processing()) {
automation_run (bufs, start_frame, end_frame, speed, nframes);
} else {
- connect_and_run (bufs, start_frame, end_frame, speed, nframes, 0, false);
+ Glib::Threads::Mutex::Lock lm (control_lock(), Glib::Threads::TRY_LOCK);
+ connect_and_run (bufs, start_frame, end_frame, speed, nframes, 0, lm.locked());
}
} else {
#ifdef LXVST_SUPPORT
boost::shared_ptr<LXVSTPlugin> lxvp;
#endif
+#ifdef MACVST_SUPPORT
+ boost::shared_ptr<MacVSTPlugin> mvp;
+#endif
#ifdef AUDIOUNIT_SUPPORT
boost::shared_ptr<AUPlugin> ap;
#endif
} else if ((lxvp = boost::dynamic_pointer_cast<LXVSTPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new LXVSTPlugin (*lxvp));
#endif
+#ifdef MACVST_SUPPORT
+ } else if ((mvp = boost::dynamic_pointer_cast<MacVSTPlugin> (other)) != 0) {
+ return boost::shared_ptr<Plugin> (new MacVSTPlugin (*mvp));
+#endif
#ifdef AUDIOUNIT_SUPPORT
} else if ((ap = boost::dynamic_pointer_cast<AUPlugin> (other)) != 0) {
return boost::shared_ptr<Plugin> (new AUPlugin (*ap));
&& _in_map.size() == _out_map.size()
&& _in_map.size() == get_count ()
) {
- assert (_maps_from_state == false);
/* If the configuration has not changed, keep the mapping */
mapping_changed = sanitize_maps ();
} else if (_match.custom_cfg && _configured) {
- assert (_maps_from_state == false);
/* don't touch the map in manual mode */
mapping_changed = sanitize_maps ();
} else {
m.strict_io = true;
/* special case MIDI instruments */
- if (needs_midi_input ()) {
+ if (is_instrument ()) {
// output = midi-bypass + at most master-out channels.
ChanCount max_out (DataType::AUDIO, 2); // TODO use master-out
max_out.set (DataType::MIDI, out.get(DataType::MIDI));
type = ARDOUR::Windows_VST;
} else if (prop->value() == X_("lxvst")) {
type = ARDOUR::LXVST;
+ } else if (prop->value() == X_("mac-vst")) {
+ type = ARDOUR::MacVST;
} else if (prop->value() == X_("audiounit")) {
type = ARDOUR::AudioUnit;
} else if (prop->value() == X_("luaproc")) {
if (prop == 0) {
#ifdef WINDOWS_VST_SUPPORT
- /* older sessions contain VST plugins with only an "id" field.
- */
-
+ /* older sessions contain VST plugins with only an "id" field. */
if (type == ARDOUR::Windows_VST) {
prop = node.property ("id");
}
#ifdef LXVST_SUPPORT
/*There shouldn't be any older sessions with linuxVST support.. but anyway..*/
-
if (type == ARDOUR::LXVST) {
prop = node.property ("id");
}
#endif
+
/* recheck */
if (prop == 0) {
boost::shared_ptr<Plugin> plugin = find_plugin (_session, prop->value(), type);
- /* treat linux and windows VST plugins equivalent if they have the same uniqueID
+ /* treat VST plugins equivalent if they have the same uniqueID
* allow to move sessions windows <> linux */
#ifdef LXVST_SUPPORT
- if (plugin == 0 && type == ARDOUR::Windows_VST) {
+ if (plugin == 0 && (type == ARDOUR::Windows_VST || type == ARDOUR::MacVST)) {
type = ARDOUR::LXVST;
plugin = find_plugin (_session, prop->value(), type);
}
#endif
#ifdef WINDOWS_VST_SUPPORT
- if (plugin == 0 && type == ARDOUR::LXVST) {
+ if (plugin == 0 && (type == ARDOUR::LXVST || type == ARDOUR::MacVST)) {
type = ARDOUR::Windows_VST;
plugin = find_plugin (_session, prop->value(), type);
}
#endif
+#ifdef MACVST_SUPPORT
+ if (plugin == 0 && (type == ARDOUR::Windows_VST || type == ARDOUR::LXVST)) {
+ type = ARDOUR::MacVST;
+ plugin = find_plugin (_session, prop->value(), type);
+ }
+#endif
+
if (plugin == 0 && type == ARDOUR::Lua) {
/* unique ID (sha1 of script) was not found,
* load the plugin from the serialized version in the
}
}
+ /* when copying plugin state, notify UI */
+ for (Controls::const_iterator li = controls().begin(); li != controls().end(); ++li) {
+ boost::shared_ptr<PBD::Controllable> c = boost::dynamic_pointer_cast<PBD::Controllable> (li->second);
+ if (c) {
+ c->Changed (false, Controllable::NoGroup); /* EMIT SIGNAL */
+ }
+ }
+
break;
}
}
if (!_sidechain) {
add_sidechain (0);
}
- _sidechain->set_state (**i, version);
+ if (!regenerate_xml_or_string_ids ()) {
+ _sidechain->set_state (**i, version);
+ }
}
}
}
}
+void
+PluginInsert::set_owner (SessionObject* o)
+{
+ Processor::set_owner (o);
+ for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) {
+ (*i)->set_owner (o);
+ }
+}
+
void
PluginInsert::set_state_dir (const std::string& d)
{
assert (out == internal_output_streams ());
}
ret->configure_io (internal_input_streams (), out);
+ ret->set_owner (_owner);
_impulseAnalysisPlugin = ret;
} else {
ret = _impulseAnalysisPlugin.lock();
PluginInsert::add_plugin (boost::shared_ptr<Plugin> plugin)
{
plugin->set_insert_id (this->id());
+ plugin->set_owner (_owner);
if (_plugins.empty()) {
/* first (and probably only) plugin instance - connect to relevant signals */
}
}
}
-#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT)
+#if (defined WINDOWS_VST_SUPPORT || defined LXVST_SUPPORT || defined MACVST_SUPPORT)
boost::shared_ptr<VSTPlugin> vst = boost::dynamic_pointer_cast<VSTPlugin> (plugin);
if (vst) {
vst->set_insert (this, _plugins.size ());
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());
- }
+ boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
+ if (ac) {
+ // ToDo subtract _plugin_signal_latency from audible_frame() when rolling, assert > 0
+ 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());
- }
+ boost::shared_ptr<AutomationControl> ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id));
+ if (ac) {
+ // ToDo subtract _plugin_signal_latency from audible_frame() when rolling, assert > 0
+ ac->stop_touch (true, session().audible_frame());
+ }
}
std::ostream& operator<<(std::ostream& o, const ARDOUR::PluginInsert::Match& m)