X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=569f00fbc770c020e8d2798f0994dbfd3695491f;hb=1c0c9b40b73180537da7630b6a219baf85886da6;hp=b53dedaacf37461a7cd272c036d44bc96753cbe7;hpb=2b7a047e92bc5ebe3287860ff9c9f2fb0acb193c;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index b53dedaacf..569f00fbc7 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -33,7 +33,6 @@ #include "pbd/memento_command.h" #include "pbd/stacktrace.h" #include "pbd/convert.h" -#include "pbd/boost_debug.h" #include "pbd/unwind.h" #include "ardour/amp.h" @@ -41,6 +40,7 @@ #include "ardour/audio_track.h" #include "ardour/audio_port.h" #include "ardour/audioengine.h" +#include "ardour/boost_debug.h" #include "ardour/buffer.h" #include "ardour/buffer_set.h" #include "ardour/capturing_processor.h" @@ -69,6 +69,7 @@ #include "ardour/session.h" #include "ardour/unknown_processor.h" #include "ardour/utils.h" +#include "ardour/vca.h" #include "i18n.h" @@ -78,10 +79,11 @@ using namespace PBD; PBD::Signal0 Route::SyncOrderKeys; PBD::Signal0 Route::RemoteControlIDChange; +PBD::Signal3, boost::shared_ptr, Route::PluginSetupOptions > Route::PluginSetup; /** Base class for all routable/mixable objects (tracks and busses) */ Route::Route (Session& sess, string name, Flag flg, DataType default_type) - : SessionObject (sess, name) + : Stripable (sess, name) , Automatable (sess) , GraphNode (sess._process_graph) , _active (true) @@ -119,6 +121,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , _in_sidechain_setup (false) , _strict_io (false) , _custom_meter_position_noted (false) + , _pinmgr_proxy (0) { processor_max_streams.reset(); } @@ -170,14 +173,9 @@ Route::init () _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1)); -#if 0 // not used - just yet - if (!is_master() && !is_monitor() && !is_auditioner()) { - _delayline.reset (new DelayLine (_session, _name)); - add_processor (_delayline, PreFader); - } -#endif - - /* add amp processor */ + /* add the amp/fader processor. + * it should be the first processor to be added on every route. + */ _gain_control = boost::shared_ptr (new GainControllable (_session, GainAutomation, shared_from_this ())); add_control (_gain_control); @@ -189,6 +187,13 @@ Route::init () _amp->set_display_name (_("Monitor")); } +#if 0 // not used - just yet + if (!is_master() && !is_monitor() && !is_auditioner()) { + _delayline.reset (new DelayLine (_session, _name)); + add_processor (_delayline, PreFader); + } +#endif + /* and input trim */ _trim_control = boost::shared_ptr (new GainControllable (_session, TrimAutomation, shared_from_this ())); @@ -825,7 +830,8 @@ Route::set_listen (bool yn, Controllable::GroupControlDisposition group_override } _mute_master->set_soloed_by_others (false); - listen_changed (group_override); /* EMIT SIGNAL */ + _session.listen_changed (group_override, shared_from_this()); + _solo_control->Changed(); /* EMIT SIGNAL */ } } } @@ -845,7 +851,6 @@ Route::set_solo_safe (bool yn, Controllable::GroupControlDisposition /* group_ov { if (_solo_safe != yn) { _solo_safe = yn; - solo_safe_changed (); /* EMIT SIGNAL */ _solo_safe_control->Changed(); /* EMIT SIGNAL */ } } @@ -888,7 +893,8 @@ Route::clear_all_solo_state () if (emit_changed) { set_mute_master_solo (); - solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */ + _session.solo_changed (false, Controllable::UseGroup, shared_from_this()); + _solo_control->Changed (); /* EMIT SIGNAL */ } } @@ -915,7 +921,7 @@ Route::set_solo (bool yn, Controllable::GroupControlDisposition group_override) if (self_soloed() != yn) { set_self_solo (yn); - solo_changed (true, group_override); /* EMIT SIGNAL */ + _session.solo_changed (true, group_override, shared_from_this()); _solo_control->Changed (); /* EMIT SIGNAL */ } @@ -993,7 +999,8 @@ Route::mod_solo_by_others_upstream (int32_t delta) } set_mute_master_solo (); - solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */ + _session.solo_changed (false, Controllable::UseGroup, shared_from_this()); + _solo_control->Changed (); /* EMIT SIGNAL */ } void @@ -1015,7 +1022,8 @@ Route::mod_solo_by_others_downstream (int32_t delta) DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbD delta %2 = %3\n", name(), delta, _soloed_by_others_downstream)); set_mute_master_solo (); - solo_changed (false, Controllable::UseGroup); /* EMIT SIGNAL */ + _session.solo_changed (false, Controllable::UseGroup, shared_from_this()); + _solo_control->Changed (); /* EMIT SIGNAL */ } void @@ -1045,7 +1053,8 @@ Route::mod_solo_isolated_by_upstream (bool yn) if (solo_isolated() != old) { /* solo isolated status changed */ _mute_master->set_solo_ignore (solo_isolated()); - solo_isolated_changed (); /* EMIT SIGNAL */ + _session.solo_isolated_changed (shared_from_this()); + _solo_isolate_control->Changed(); /* EMIT SIGNAL */ } } @@ -1101,7 +1110,7 @@ Route::set_solo_isolated (bool yn, Controllable::GroupControlDisposition group_o /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */ - solo_isolated_changed (); /* EMIT SIGNAL */ + _session.solo_isolated_changed (shared_from_this()); _solo_isolate_control->Changed(); /* EMIT SIGNAL */ } @@ -1118,7 +1127,7 @@ Route::set_mute_points (MuteMaster::MutePoint mp) mute_points_changed (); /* EMIT SIGNAL */ if (_mute_master->muted_by_self()) { - mute_changed (); /* EMIT SIGNAL */ + _session.mute_changed (); _mute_control->Changed (); /* EMIT SIGNAL */ } } @@ -1138,7 +1147,7 @@ Route::set_mute (bool yn, Controllable::GroupControlDisposition group_override) */ act_on_mute (); /* tell everyone else */ - mute_changed (); /* EMIT SIGNAL */ + _session.mute_changed (); _mute_control->Changed (); /* EMIT SIGNAL */ } } @@ -1256,93 +1265,17 @@ Route::add_processor (boost::shared_ptr processor, boost::shared_ptr< DEBUG_TRACE (DEBUG::Processors, string_compose ( "%1 adding processor %2\n", name(), processor->name())); - if (!AudioEngine::instance()->connected() || !processor) { - return 1; - } + ProcessorList pl; - if (_strict_io) { - boost::shared_ptr pi; - if ((pi = boost::dynamic_pointer_cast(processor)) != 0) { - pi->set_strict_io (true); - } - } + pl.push_back (processor); + int rv = add_processors (pl, before, err); - { - Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); - Glib::Threads::RWLock::WriterLock lm (_processor_lock); - ProcessorState pstate (this); - - boost::shared_ptr pi; - boost::shared_ptr porti; - - if (processor == _amp) { - /* Ensure that only one amp is in the list at any time */ - ProcessorList::iterator check = find (_processors.begin(), _processors.end(), processor); - if (check != _processors.end()) { - if (before == _amp) { - /* Already in position; all is well */ - return 0; - } else { - _processors.erase (check); - } - } - } - - assert (find (_processors.begin(), _processors.end(), processor) == _processors.end ()); - - ProcessorList::iterator loc; - if (before) { - /* inserting before a processor; find it */ - loc = find (_processors.begin(), _processors.end(), before); - if (loc == _processors.end ()) { - /* Not found */ - return 1; - } - } else { - /* inserting at end */ - loc = _processors.end (); - } - - _processors.insert (loc, processor); - processor->set_owner (this); - - // Set up processor list channels. This will set processor->[input|output]_streams(), - // configure redirect ports properly, etc. - - { - if (configure_processors_unlocked (err, &lm)) { - pstate.restore (); - configure_processors_unlocked (0, &lm); // it worked before we tried to add it ... - return -1; - } - } - - if ((pi = boost::dynamic_pointer_cast(processor)) != 0) { - - if (pi->has_no_inputs ()) { - /* generator plugin */ - _have_internal_generator = true; - } - - } - - if (activation_allowed && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user ())) { - processor->activate (); - } - - processor->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false)); - - _output->set_user_latency (0); + if (rv) { + return rv; } - reset_instrument_info (); - processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ - set_processor_positions (); - - boost::shared_ptr send; - if ((send = boost::dynamic_pointer_cast (processor))) { - send->SelfDestruct.connect_same_thread (*this, - boost::bind (&Route::processor_selfdestruct, this, boost::weak_ptr (processor))); + if (activation_allowed && (!_session.get_bypass_all_loaded_plugins () || !processor->display_to_user ())) { + processor->activate (); } return 0; @@ -1444,24 +1377,31 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version) } } + +inline Route::PluginSetupOptions operator|= (Route::PluginSetupOptions& a, const Route::PluginSetupOptions& b) { + return a = static_cast (static_cast (a) | static_cast (b)); +} + +inline Route::PluginSetupOptions operator&= (Route::PluginSetupOptions& a, const Route::PluginSetupOptions& b) { + return a = static_cast (static_cast (a) & static_cast (b)); +} + int Route::add_processors (const ProcessorList& others, boost::shared_ptr before, ProcessorStreams* err) { - /* NOTE: this is intended to be used ONLY when copying - processors from another Route. Hence the subtle - differences between this and ::add_processor() - */ - ProcessorList::iterator loc; if (before) { loc = find(_processors.begin(), _processors.end(), before); + if (loc == _processors.end ()) { + return 1; + } } else { /* nothing specified - at end */ loc = _processors.end (); } - if (!_session.engine().connected()) { + if (!AudioEngine::instance()->connected()) { return 1; } @@ -1469,6 +1409,59 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr return 0; } + ProcessorList to_skip; + + // check if there's an instrument to replace or configure + for (ProcessorList::const_iterator i = others.begin(); i != others.end(); ++i) { + boost::shared_ptr pi; + if ((pi = boost::dynamic_pointer_cast(*i)) == 0) { + continue; + } + if (!pi->plugin ()->get_info ()->is_instrument ()) { + continue; + } + boost::shared_ptr instrument = the_instrument (); + ChanCount in (DataType::MIDI, 1); + ChanCount out (DataType::AUDIO, 2); // XXX route's out?! + + PluginSetupOptions flags = None; + if (instrument) { + flags |= CanReplace; + in = instrument->input_streams (); + out = instrument->output_streams (); + } + if (pi->has_output_presets (in, out)) { + flags |= MultiOut; + } + + pi->set_strict_io (_strict_io); + + PluginSetupOptions mask = None; + if (Config->get_ask_replace_instrument ()) { + mask |= CanReplace; + } + if (Config->get_ask_setup_instrument ()) { + mask |= MultiOut; + } + + flags &= mask; + + if (flags != None) { + boost::optional rv = PluginSetup (shared_from_this (), pi, flags); /* EMIT SIGNAL */ + switch (rv.get_value_or (0)) { + case 1: + to_skip.push_back (*i); // don't add this one; + break; + case 2: + replace_processor (instrument, *i, err); + to_skip.push_back (*i); + break; + default: + break; + } + } + } + { Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); Glib::Threads::RWLock::WriterLock lm (_processor_lock); @@ -1479,6 +1472,10 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr if (*i == _meter) { continue; } + ProcessorList::iterator check = find (to_skip.begin(), to_skip.end(), *i); + if (check != to_skip.end()) { + continue; + } boost::shared_ptr pi; @@ -1486,14 +1483,24 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr pi->set_strict_io (_strict_io); } + if (*i == _amp) { + /* Ensure that only one amp is in the list at any time */ + ProcessorList::iterator check = find (_processors.begin(), _processors.end(), *i); + if (check != _processors.end()) { + if (before == _amp) { + /* Already in position; all is well */ + continue; + } else { + _processors.erase (check); + } + } + } + + assert (find (_processors.begin(), _processors.end(), *i) == _processors.end ()); + _processors.insert (loc, *i); (*i)->set_owner (this); - if ((*i)->active()) { - (*i)->activate (); - } - - /* Think: does this really need to be called for every processor in the loop? */ { if (configure_processors_unlocked (err, &lm)) { pstate.restore (); @@ -1502,7 +1509,17 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr } } + if ((*i)->active()) { + (*i)->activate (); + } + (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false)); + + boost::shared_ptr send; + if ((send = boost::dynamic_pointer_cast (*i))) { + send->SelfDestruct.connect_same_thread (*this, + boost::bind (&Route::processor_selfdestruct, this, boost::weak_ptr (*i))); + } } for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { @@ -2704,7 +2721,7 @@ Route::get_template() XMLNode& Route::state(bool full_state) { - LocaleGuard lg (); + LocaleGuard lg; if (!_session._template_state_dir.empty()) { assert (!full_state); // only for templates foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), _session._template_state_dir)); @@ -2771,26 +2788,29 @@ Route::state(bool full_state) node->add_child_nocopy (_pannable->state (full_state)); } - for (i = _processors.begin(); i != _processors.end(); ++i) { - if (!full_state) { - /* template save: do not include internal sends functioning as - aux sends because the chance of the target ID - in the session where this template is used - is not very likely. - - similarly, do not save listen sends which connect to - the monitor section, because these will always be - added if necessary. - */ - boost::shared_ptr is; + { + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); + for (i = _processors.begin(); i != _processors.end(); ++i) { + if (!full_state) { + /* template save: do not include internal sends functioning as + aux sends because the chance of the target ID + in the session where this template is used + is not very likely. + + similarly, do not save listen sends which connect to + the monitor section, because these will always be + added if necessary. + */ + boost::shared_ptr is; - if ((is = boost::dynamic_pointer_cast (*i)) != 0) { - if (is->role() == Delivery::Listen) { - continue; + if ((is = boost::dynamic_pointer_cast (*i)) != 0) { + if (is->role() == Delivery::Listen) { + continue; + } } } + node->add_child_nocopy((*i)->state (full_state)); } - node->add_child_nocopy((*i)->state (full_state)); } if (_extra_xml) { @@ -3040,7 +3060,7 @@ Route::set_state (const XMLNode& node, int version) int Route::set_state_2X (const XMLNode& node, int version) { - LocaleGuard lg (); + LocaleGuard lg; XMLNodeList nlist; XMLNodeConstIterator niter; XMLNode *child; @@ -3330,7 +3350,7 @@ Route::set_processor_state (const XMLNode& node) for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - XMLProperty const * prop = (*niter)->property ("type"); + XMLProperty* prop = (*niter)->property ("type"); if (prop->value() == "amp") { _amp->set_state (**niter, Stateful::current_state_version); @@ -4627,7 +4647,6 @@ Route::set_phase_invert (uint32_t c, bool yn) { if (_phase_invert[c] != yn) { _phase_invert[c] = yn; - phase_invert_changed (); /* EMIT SIGNAL */ _phase_control->Changed(); /* EMIT SIGNAL */ _session.set_dirty (); } @@ -4638,7 +4657,7 @@ Route::set_phase_invert (boost::dynamic_bitset<> p) { if (_phase_invert != p) { _phase_invert = p; - phase_invert_changed (); /* EMIT SIGNAL */ + _phase_control->Changed (); /* EMIT SIGNAL */ _session.set_dirty (); } } @@ -4716,13 +4735,13 @@ Route::gain_control() const return _gain_control; } -boost::shared_ptr +boost::shared_ptr Route::trim_control() const { return _trim_control; } -boost::shared_ptr +boost::shared_ptr Route::phase_control() const { if (phase_invert().size()) { @@ -5038,12 +5057,13 @@ Route::setup_invisible_processors () /* find the amp */ - ProcessorList::iterator amp = new_processors.begin (); - while (amp != new_processors.end() && *amp != _amp) { - ++amp; - } + ProcessorList::iterator amp = find (new_processors.begin(), new_processors.end(), _amp); - assert (amp != new_processors.end ()); + if (amp == new_processors.end ()) { + error << string_compose (_("Amp/Fader on Route '%1' went AWOL. Re-added."), name()) << endmsg; + new_processors.push_front (_amp); + amp = find (new_processors.begin(), new_processors.end(), _amp); + } /* and the processor after the amp */ @@ -5867,3 +5887,37 @@ Route::master_send_enable_controllable () const return boost::shared_ptr(); #endif } + +bool +Route::slaved_to (boost::shared_ptr vca) const +{ + if (!vca || !_gain_control) { + return false; + } + + return _gain_control->slaved_to (vca->gain_control()); +} + +void +Route::vca_assign (boost::shared_ptr vca) +{ + _gain_control->add_master (vca->gain_control()); + _solo_control->add_master (vca->solo_control()); + _mute_control->add_master (vca->mute_control()); +} + +void +Route::vca_unassign (boost::shared_ptr vca) +{ + if (!vca) { + /* unassign from all */ + _gain_control->clear_masters (); + _solo_control->clear_masters (); + _mute_control->clear_masters (); + } else { + _gain_control->remove_master (vca->gain_control()); + _solo_control->remove_master (vca->solo_control()); + _mute_control->remove_master (vca->mute_control()); + + } +}