X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fplugin_insert.cc;h=ae018fb2a3c53544c5e20034e4b13455b87d16ef;hb=af0c42ec4f9d46907299f704d0c70e25e0af6b96;hp=728e6b8645907e8b50e837770821b4975dd15a46;hpb=5558b3cf06b98060438d1e68c8d5d2f4a9c2f8f6;p=ardour.git diff --git a/libs/ardour/plugin_insert.cc b/libs/ardour/plugin_insert.cc index 728e6b8645..ae018fb2a3 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)); @@ -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(); + boost::shared_ptr ac = automation_control (Evoral::Parameter (PluginAutomation, 0, which)); - /* 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); - } - } + 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,9 +344,11 @@ 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); + 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); + } } } @@ -441,7 +447,7 @@ 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); } } @@ -458,39 +464,31 @@ PluginInsert::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end } } 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 */ - - uint32_t in = input_streams ().n_audio (); - uint32_t out = output_streams().n_audio (); + } else if (out > in) { - if (out > in) { + /* not active, but something has make up for any channel count increase */ - /* 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; @@ -499,7 +497,6 @@ PluginInsert::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end * all buffers appropriately. */ - bufs.set_is_silent (false); } void @@ -545,7 +542,7 @@ PluginInsert::automation_run (BufferSet& bufs, pframes_t nframes) 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); @@ -645,6 +642,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); @@ -652,9 +651,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 */ @@ -697,7 +699,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; } @@ -707,9 +709,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) { @@ -719,8 +729,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) { @@ -732,13 +751,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); } @@ -780,6 +799,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); } @@ -803,7 +823,7 @@ PluginInsert::private_can_support_io_configuration (ChanCount const & in, ChanCo } if (can_split) { - out = outputs; + out = outputs + midi_bypass; return Match (Split, 1); } @@ -827,10 +847,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); } @@ -873,7 +894,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; } @@ -881,6 +907,7 @@ PluginInsert::set_control_ids (const XMLNode& node, int version) if (ac) { ac->set_state (**iter, version); } +#endif } } } @@ -1149,10 +1176,18 @@ PluginInsert::PluginControl::PluginControl (PluginInsert* p, const Evoral::Param , _plugin (p) { Plugin::ParameterDescriptor desc; - p->plugin(0)->get_parameter_descriptor (param.id(), 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 */ @@ -1161,35 +1196,39 @@ 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 { if (_logarithmic) { + /* some plugins have a log-scale range "0.." + * ideally we'd map the range down to infinity somehow :) + * + * one solution could be to use + * val = exp(lower + log(range) * value); + * (log(val) - lower) / range) + * This approach would require access to the actual range (ie + * Plugin::ParameterDescriptor) and also require handling + * of unbound ranges.. + * + * currently an arbitrarly low number is assumed to represnt + * log(0) as hot-fix solution. + */ if (val > 0) { val = log (val); } else { - val = 0; + val = -8; // ~ -70dB = 20 * log10(exp(-8)) } } @@ -1197,29 +1236,20 @@ 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 <= -8) { + /* see note in PluginInsert::PluginControl::internal_to_interface() */ + val= 0; + } else { + val = exp (val); + } } 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 */ - return val; -} - XMLNode& PluginInsert::PluginControl::get_state () { @@ -1237,8 +1267,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 @@ -1272,6 +1301,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); } @@ -1298,3 +1337,21 @@ PluginInsert::monitoring_changed () (*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()); + } +}