X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplugin_insert.cc;h=4ad3123e077215854e05a1d9eb7e01f38bbf0f2a;hb=6dfb11c2d08201f1a27818955707590b762f5a40;hp=b7c338aa205f11b4c91ab5c394b43e7da493bf6c;hpb=e8ee8593c7b5c3d801d63cbd955e9b6c1c35bdcd;p=ardour.git diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index b7c338aa20..4ad3123e07 100644 --- a/libs/ardour/plugin_insert.cc +++ b/libs/ardour/plugin_insert.cc @@ -35,8 +35,6 @@ #include "ardour/ladspa_plugin.h" #include "ardour/plugin.h" #include "ardour/plugin_insert.h" -#include "ardour/port.h" -#include "ardour/route.h" #ifdef LV2_SUPPORT #include "ardour/lv2_plugin.h" @@ -54,7 +52,6 @@ #include "ardour/audio_unit.h" #endif -#include "ardour/audioengine.h" #include "ardour/session.h" #include "ardour/types.h" @@ -138,15 +135,17 @@ PluginInsert::output_streams() const { assert (!_plugins.empty()); - if (_plugins.front()->reconfigurable_io()) { + PluginInfoPtr info = _plugins.front()->get_info(); + + if (info->reconfigurable_io()) { ChanCount out = _plugins.front()->output_streams (); - DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, reconfigur(able) output streams = %1\n", out)); + // DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, reconfigur(able) output streams = %1\n", out)); return out; } else { - ChanCount out = _plugins.front()->get_info()->n_outputs; - DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, static output streams = %1 for %2 plugins\n", out, _plugins.size())); + ChanCount out = info->n_outputs; + // DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, static output streams = %1 for %2 plugins\n", out, _plugins.size())); out.set_audio (out.n_audio() * _plugins.size()); - out.set_midi (out.n_midi() * _plugins.size()); + out.set_midi (out.n_midi() * _plugins.size() + midi_bypass.n_midi()); return out; } } @@ -158,11 +157,13 @@ PluginInsert::input_streams() const ChanCount in; - if (_plugins.front()->reconfigurable_io()) { + PluginInfoPtr info = _plugins.front()->get_info(); + + if (info->reconfigurable_io()) { assert (_plugins.size() == 1); in = _plugins.front()->input_streams(); } else { - in = _plugins[0]->get_info()->n_inputs; + in = info->n_inputs; } DEBUG_TRACE (DEBUG::Processors, string_compose ("Plugin insert, input streams = %1, match using %2\n", in, _match.method)); @@ -239,7 +240,7 @@ PluginInsert::create_automatable_parameters () set a = _plugins.front()->automatable (); - Plugin::ParameterDescriptor desc; + ParameterDescriptor desc; for (set::iterator i = a.begin(); i != a.end(); ++i) { if (i->type() == PluginAutomation) { @@ -261,21 +262,24 @@ PluginInsert::create_automatable_parameters () } void -PluginInsert::parameter_changed (Evoral::Parameter which, float val) +PluginInsert::parameter_changed (uint32_t which, float val) { - if (which.type() != PluginAutomation) - return; - - Plugins::iterator i = _plugins.begin(); - - /* don't set the first plugin, just all the slaves */ + boost::shared_ptr ac = automation_control (Evoral::Parameter (PluginAutomation, 0, which)); - if (i != _plugins.end()) { - ++i; - for (; i != _plugins.end(); ++i) { - (*i)->set_parameter (which, val); - } - } + if (ac) { + ac->set_value (val); + + 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); + } + } + } } int @@ -340,21 +344,17 @@ PluginInsert::connect_and_run (BufferSet& bufs, pframes_t nframes, framecnt_t of /* copy the first stream's buffer contents to the others */ /* XXX: audio only */ - Sample const * mono = bufs.get_audio (in_map.get (DataType::AUDIO, 0, &valid)).data (offset); - for (uint32_t i = in_streams.n_audio(); i < natural_input_streams().n_audio(); ++i) { - memcpy (bufs.get_audio (in_map.get (DataType::AUDIO, i, &valid)).data (offset), mono, sizeof (Sample) * nframes); - } - } - - if (_match.method == Hide) { - /* Silence the hidden input buffers */ - for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { - for (uint32_t i = in_streams.get(*t); i < (in_streams.get(*t) + _match.hide.get(*t)); ++i) { - bufs.get(*t, i).silence (nframes); + 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) { + bufs.get_audio(in_map.get (DataType::AUDIO, i, &valid)).read_from(bufs.get_audio(first_idx), nframes, offset, offset); } } } + bufs.set_count(ChanCount::max(bufs.count(), in_streams)); + bufs.set_count(ChanCount::max(bufs.count(), out_streams)); + /* Note that we've already required that plugins be able to handle in-place processing. */ @@ -450,56 +450,48 @@ PluginInsert::silence (framecnt_t nframes) } for (Plugins::iterator i = _plugins.begin(); i != _plugins.end(); ++i) { - (*i)->connect_and_run (_session.get_silent_buffers ((*i)->get_info()->n_inputs), in_map, out_map, nframes, 0); + (*i)->connect_and_run (_session.get_scratch_buffers ((*i)->get_info()->n_inputs, true), in_map, out_map, nframes, 0); } } void -PluginInsert::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_frame*/, pframes_t nframes, bool) +PluginInsert::run (BufferSet& bufs, framepos_t start_frame, framepos_t /*end_frame*/, pframes_t nframes, bool) { if (_pending_active) { /* run as normal if we are active or moving from inactive to active */ - if (_session.transport_rolling()) { - automation_run (bufs, nframes); + if (_session.transport_rolling() || _session.bounce_processing()) { + automation_run (bufs, start_frame, nframes); } else { connect_and_run (bufs, nframes, 0, false); } } else { + uint32_t in = input_streams ().n_audio (); + uint32_t out = output_streams().n_audio (); - if (has_no_audio_inputs()) { + if (has_no_audio_inputs() || in == 0) { /* silence all (audio) outputs. Should really declick * at the transitions of "active" */ - uint32_t out = output_streams().n_audio (); - for (uint32_t n = 0; n < out; ++n) { bufs.get_audio (n).silence (nframes); } - bufs.count().set_audio (out); - - } else { - - /* does this need to be done with MIDI? it appears not */ + } else if (out > in) { - uint32_t in = input_streams ().n_audio (); - uint32_t out = output_streams().n_audio (); + /* not active, but something has make up for any channel count increase */ - 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.get_audio (n).data(), bufs.get_audio(in - 1).data(), sizeof (Sample) * nframes); - } + // 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); } - - bufs.count().set_audio (out); } + + bufs.count().set_audio (out); } _active = _pending_active; @@ -508,7 +500,6 @@ PluginInsert::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end * all buffers appropriately. */ - bufs.is_silent (false); } void @@ -547,14 +538,14 @@ PluginInsert::get_parameter (Evoral::Parameter param) } void -PluginInsert::automation_run (BufferSet& bufs, pframes_t nframes) +PluginInsert::automation_run (BufferSet& bufs, framepos_t start, pframes_t nframes) { Evoral::ControlEvent next_event (0, 0.0f); - framepos_t now = _session.transport_frame (); + framepos_t now = start; framepos_t end = now + nframes; framecnt_t offset = 0; - Glib::Mutex::Lock lm (control_lock(), Glib::TRY_LOCK); + Glib::Threads::Mutex::Lock lm (control_lock(), Glib::Threads::TRY_LOCK); if (!lm.locked()) { connect_and_run (bufs, nframes, offset, false); @@ -654,6 +645,8 @@ bool PluginInsert::configure_io (ChanCount in, ChanCount out) { Match old_match = _match; + ChanCount old_in = input_streams (); + ChanCount old_out = output_streams (); /* set the matching method and number of plugins that we will use to meet this configuration */ _match = private_can_support_io_configuration (in, out); @@ -661,9 +654,12 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) return false; } - /* a signal needs emitting if we start or stop splitting */ - if (old_match.method != _match.method && (old_match.method == Split || _match.method == Split)) { - SplittingChanged (); /* EMIT SIGNAL */ + if ( (old_match.method != _match.method && (old_match.method == Split || _match.method == Split)) + || old_in != in + || old_out != out + ) + { + PluginIoReConfigure (); /* EMIT SIGNAL */ } /* configure plugins */ @@ -706,7 +702,7 @@ PluginInsert::configure_io (ChanCount in, ChanCount out) * @return true if the given IO configuration can be supported. */ bool -PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) const +PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) { return private_can_support_io_configuration (in, out).method != Impossible; } @@ -716,9 +712,17 @@ PluginInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) * it can be. */ PluginInsert::Match -PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCount& out) const +PluginInsert::private_can_support_io_configuration (ChanCount const & inx, ChanCount& out) { - if (_plugins.front()->reconfigurable_io()) { + if (_plugins.empty()) { + return Match(); + } + + PluginInfoPtr info = _plugins.front()->get_info(); + ChanCount in; in += inx; + midi_bypass.reset(); + + if (info->reconfigurable_io()) { /* Plugin has flexible I/O, so delegate to it */ bool const r = _plugins.front()->can_support_io_configuration (in, out); if (!r) { @@ -728,8 +732,17 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo return Match (Delegate, 1); } - ChanCount inputs = _plugins[0]->get_info()->n_inputs; - ChanCount outputs = _plugins[0]->get_info()->n_outputs; + ChanCount inputs = info->n_inputs; + ChanCount outputs = info->n_outputs; + + 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); + } bool no_inputs = true; for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { @@ -741,13 +754,13 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo if (no_inputs) { /* no inputs so we can take any input configuration since we throw it away */ - out = outputs; + out = outputs + midi_bypass; return Match (NoInputs, 1); } /* Plugin inputs match requested inputs exactly */ if (inputs == in) { - out = outputs; + out = outputs + midi_bypass; return Match (ExactMatch, 1); } @@ -789,6 +802,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { out.set (*t, outputs.get(*t) * f); } + out += midi_bypass; return Match (Replicate, f); } @@ -812,7 +826,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo } if (can_split) { - out = outputs; + out = outputs + midi_bypass; return Match (Split, 1); } @@ -836,10 +850,11 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo } if (could_hide && !cannot_hide) { - out = outputs; + out = outputs + midi_bypass; return Match (Hide, 1, hide_channels); } + midi_bypass.reset(); return Match (Impossible, 0); } @@ -882,7 +897,12 @@ PluginInsert::set_control_ids (const XMLNode& node, int version) if ((prop = (*iter)->property (X_("parameter"))) != 0) { uint32_t p = atoi (prop->value()); + + /* this may create the new controllable */ + boost::shared_ptr c = control (Evoral::Parameter (PluginAutomation, 0, p)); + +#ifndef NO_PLUGIN_STATE if (!c) { continue; } @@ -890,6 +910,7 @@ PluginInsert::set_control_ids (const XMLNode& node, int version) if (ac) { ac->set_state (**iter, version); } +#endif } } } @@ -955,6 +976,22 @@ PluginInsert::set_state(const XMLNode& node, int version) boost::shared_ptr plugin = find_plugin (_session, prop->value(), type); + /* treat linux and windows 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) { + 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 + if (plugin == 0) { error << string_compose( _("Found a reference to a plugin (\"%1\") that is unknown.\n" @@ -1102,7 +1139,7 @@ PluginInsert::set_parameter_state_2X (const XMLNode& node, int version) float min_y = c->alist()->get_min_y (); float max_y = c->alist()->get_max_y (); - Plugin::ParameterDescriptor desc; + ParameterDescriptor desc; _plugins.front()->get_parameter_descriptor (port_id, desc); if (min_y == FLT_MIN) { @@ -1157,11 +1194,19 @@ PluginInsert::PluginControl::PluginControl (PluginInsert* p, const Evoral::Param : AutomationControl (p->session(), param, list, p->describe_parameter(param)) , _plugin (p) { - Plugin::ParameterDescriptor desc; - p->plugin(0)->get_parameter_descriptor (param.id(), desc); + ParameterDescriptor desc; + boost::shared_ptr plugin = p->plugin (0); + + alist()->reset_default (plugin->default_value (param.id())); + + plugin->get_parameter_descriptor (param.id(), desc); _logarithmic = desc.logarithmic; _sr_dependent = desc.sr_dependent; _toggled = desc.toggled; + + if (desc.toggled) { + set_flags(Controllable::Toggle); + } } /** @param val `user' value */ @@ -1170,33 +1215,26 @@ PluginInsert::PluginControl::set_value (double user_val) { /* FIXME: probably should be taking out some lock here.. */ - double const plugin_val = user_to_plugin (user_val); - for (Plugins::iterator i = _plugin->_plugins.begin(); i != _plugin->_plugins.end(); ++i) { - (*i)->set_parameter (_list->parameter().id(), plugin_val); + (*i)->set_parameter (_list->parameter().id(), user_val); } boost::shared_ptr iasp = _plugin->_impulseAnalysisPlugin.lock(); if (iasp) { - iasp->set_parameter (_list->parameter().id(), plugin_val); + iasp->set_parameter (_list->parameter().id(), user_val); } AutomationControl::set_value (user_val); } double -PluginInsert::PluginControl::user_to_plugin (double val) const -{ - /* no known transformations at this time */ - return val; -} - -double -PluginInsert::PluginControl::user_to_ui (double val) const +PluginInsert::PluginControl::internal_to_interface (double val) const { + val = Controllable::internal_to_interface(val); + if (_logarithmic) { if (val > 0) { - val = log (val); + val = pow (val, 1/1.5); } else { val = 0; } @@ -1206,26 +1244,18 @@ PluginInsert::PluginControl::user_to_ui (double val) const } double -PluginInsert::PluginControl::ui_to_user (double val) const +PluginInsert::PluginControl::interface_to_internal (double val) const { if (_logarithmic) { - val = exp (val); + if (val <= 0) { + val= 0; + } else { + val = pow (val, 1.5); + } } - return val; -} - -/** Convert plugin values to UI values. See pbd/controllable.h */ -double -PluginInsert::PluginControl::plugin_to_ui (double val) const -{ - return user_to_ui (plugin_to_user (val)); -} - -double -PluginInsert::PluginControl::plugin_to_user (double val) const -{ - /* no known transformations at this time */ + val = Controllable::interface_to_internal(val); + return val; } @@ -1246,8 +1276,7 @@ double PluginInsert::PluginControl::get_value () const { /* FIXME: probably should be taking out some lock here.. */ - - return plugin_to_user (_plugin->get_parameter (_list->parameter())); + return _plugin->get_parameter (_list->parameter()); } boost::shared_ptr @@ -1281,6 +1310,16 @@ void PluginInsert::add_plugin (boost::shared_ptr plugin) { plugin->set_insert_info (this); + + if (_plugins.empty()) { + /* first (and probably only) plugin instance - connect to relevant signals + */ + + plugin->ParameterChanged.connect_same_thread (*this, boost::bind (&PluginInsert::parameter_changed, this, _1, _2)); + 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)); + } + _plugins.push_back (plugin); } @@ -1291,3 +1330,37 @@ PluginInsert::realtime_handle_transport_stopped () (*i)->realtime_handle_transport_stopped (); } } + +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 (); + } +} + +void +PluginInsert::start_touch (uint32_t param_id) +{ + boost::shared_ptr 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 ac = automation_control (Evoral::Parameter (PluginAutomation, 0, param_id)); + if (ac) { + ac->stop_touch (true, session().audible_frame()); + } +}