X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=44d79587405749badf5e689a954e16d3c91a23f8;hb=5956e864e7ceb1285e43f376796aaec5230d16e9;hp=fa564968edc3df5dc93c52ef146152cacea2aba2;hpb=0a52b325f4e1eaf39be65a24f9a594ffe1f66e79;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index fa564968ed..44d7958740 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -46,6 +46,7 @@ #include "ardour/capturing_processor.h" #include "ardour/debug.h" #include "ardour/delivery.h" +#include "ardour/event_type_map.h" #include "ardour/gain_control.h" #include "ardour/internal_return.h" #include "ardour/internal_send.h" @@ -74,7 +75,7 @@ #include "ardour/utils.h" #include "ardour/vca.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -117,6 +118,11 @@ Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType processor_max_streams.reset(); } +boost::weak_ptr +Route::weakroute () { + return boost::weak_ptr (shared_from_this ()); +} + int Route::init () { @@ -229,10 +235,6 @@ Route::init () _monitor_control->activate (); } - if (is_master() || is_monitor() || is_auditioner()) { - _mute_master->set_solo_ignore (true); - } - /* now that we have _meter, its safe to connect to this */ { @@ -626,6 +628,9 @@ void Route::set_listen (bool yn) { if (_monitor_send) { + if (_monitor_send->active() == yn) { + return; + } if (yn) { _monitor_send->activate (); } else { @@ -835,6 +840,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version) if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "lv2" || prop->value() == "windows-vst" || + prop->value() == "mac-vst" || prop->value() == "lxvst" || prop->value() == "audiounit") { @@ -899,6 +905,13 @@ int Route::add_processors (const ProcessorList& others, boost::shared_ptr before, ProcessorStreams* err) { ProcessorList::iterator loc; + boost::shared_ptr fanout; + + if (g_atomic_int_get (&_pending_process_reorder)) { + /* we need to flush any pending re-order changes */ + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); + apply_processor_changes_rt (); + } if (before) { loc = find(_processors.begin(), _processors.end(), before); @@ -957,7 +970,8 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr if (flags != None) { boost::optional rv = PluginSetup (shared_from_this (), pi, flags); /* EMIT SIGNAL */ - switch (rv.get_value_or (0)) { + int mode = rv.get_value_or (0); + switch (mode & 3) { case 1: to_skip.push_back (*i); // don't add this one; break; @@ -968,6 +982,9 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr default: break; } + if ((mode & 5) == 4) { + fanout = pi; + } } } @@ -1018,8 +1035,12 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr } } + if (pi && pi->has_sidechain ()) { + pi->sidechain_input ()->changed.connect_same_thread (*this, boost::bind (&Route::sidechain_change_handler, this, _1, _2)); + } + if ((*i)->active()) { - // why? emit ActiveChanged() ?? + // emit ActiveChanged() and latency_changed() if needed (*i)->activate (); } @@ -1050,6 +1071,11 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ set_processor_positions (); + if (fanout && fanout->configured () + && fanout->output_streams().n_audio() > 2 + && boost::dynamic_pointer_cast (the_instrument ()) == fanout) { + fan_out (); /* EMIT SIGNAL */ + } return 0; } @@ -1653,13 +1679,21 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err) if (is_monitor()) { // restriction for Monitor Section Processors if (in.n_audio() != out.n_audio() || out.n_midi() > 0) { - /* do not allow to add/remove channels (for now) - * The Monitor follows the master-bus and has no panner (unpan) - * but do allow processors with midi-in to be added (e.g VSTs with control that - * will remain unconnected) + /* Note: The Monitor follows the master-bus and has no panner. + * + * The general idea is to only allow plugins that retain the channel-count + * and plugins with MIDI in (e.g VSTs with control that will remain unconnected). + * Then again 5.1 in, monitor stereo is a valid use-case. + * + * and worse: we only refuse adding plugins *here*. + * + * 1) stereo-master, stereo-mon, add a stereo-plugin, OK + * 2) change master-bus, add a channel + * 2a) monitor-secion follows + * 3) monitor processors fail to re-reconfigure (stereo plugin) + * 4) re-load session, monitor-processor remains unconfigured, crash. */ - DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration not allowed.\n"); - return list > (); + DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration change.\n"); } if (boost::dynamic_pointer_cast (*p)) { // internal sends make no sense, only feedback @@ -1952,6 +1986,35 @@ Route::apply_processor_order (const ProcessorList& new_order) maybe_note_meter_position (); } +void +Route::move_instrument_down (bool postfader) +{ + Glib::Threads::RWLock::ReaderLock lm (_processor_lock); + ProcessorList new_order; + boost::shared_ptr instrument; + for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr pi = boost::dynamic_pointer_cast(*i); + if (pi && pi->plugin ()->get_info ()->is_instrument ()) { + instrument = *i; + } else if (instrument && *i == _amp) { + if (postfader) { + new_order.push_back (*i); + new_order.push_back (instrument); + } else { + new_order.push_back (instrument); + new_order.push_back (*i); + } + } else { + new_order.push_back (*i); + } + } + if (!instrument) { + return; + } + lm.release (); + reorder_processors (new_order, 0); +} + int Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err) { @@ -2225,7 +2288,6 @@ Route::state(bool full_state) { 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)); } @@ -2352,10 +2414,6 @@ Route::set_state (const XMLNode& node, int version) _strict_io = string_is_affirmative (prop->value()); } - if (!can_solo()) { - _mute_master->set_solo_ignore (true); - } - if (is_monitor()) { /* monitor bus does not get a panner, but if (re)created via XML, it will already have one by the time we @@ -2394,22 +2452,6 @@ Route::set_state (const XMLNode& node, int version) } else { warning << string_compose (_("Pannable state found for route (%1) without a panner!"), name()) << endmsg; } - } else if (child->name() == Controllable::xml_node_name) { - if ((prop = child->property (X_("name"))) == 0) { - continue; - } - - if (prop->value() == _gain_control->name()) { - _gain_control->set_state (*child, version); - } else if (prop->value() == _solo_control->name()) { - _solo_control->set_state (*child, version); - } else if (prop->value() == _solo_safe_control->name()) { - _solo_safe_control->set_state (*child, version); - } else if (prop->value() == _solo_isolate_control->name()) { - _solo_isolate_control->set_state (*child, version); - } else if (prop->value() == _solo_control->name()) { - _mute_control->set_state (*child, version); - } } else if (child->name() == Slavable::xml_node_name) { Slavable::set_state (*child, version); } @@ -2467,13 +2509,32 @@ Route::set_state (const XMLNode& node, int version) XMLNode *cmt = *(child->children().begin()); _comment = cmt->content(); - } else if (child->name() == Controllable::xml_node_name && (prop = child->property("name")) != 0) { - if (prop->value() == "solo") { + } else if (child->name() == Controllable::xml_node_name) { + if ((prop = child->property (X_("name"))) == 0) { + continue; + } + + if (prop->value() == _gain_control->name()) { + _gain_control->set_state (*child, version); + } else if (prop->value() == _solo_control->name()) { _solo_control->set_state (*child, version); - } else if (prop->value() == "mute") { + } else if (prop->value() == _solo_safe_control->name()) { + _solo_safe_control->set_state (*child, version); + } else if (prop->value() == _solo_isolate_control->name()) { + _solo_isolate_control->set_state (*child, version); + } else if (prop->value() == _mute_control->name()) { _mute_control->set_state (*child, version); + } else if (prop->value() == _phase_control->name()) { + _phase_control->set_state (*child, version); + } else { + Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value()); + if (p.type () >= MidiCCAutomation && p.type () < MidiSystemExclusiveAutomation) { + boost::shared_ptr ac = automation_control (p, true); + if (ac) { + ac->set_state (*child, version); + } + } } - } else if (child->name() == MuteMaster::xml_node_name) { _mute_master->set_state (*child, version); @@ -2507,10 +2568,6 @@ Route::set_state_2X (const XMLNode& node, int version) Stripable::set_state (node, version); - if (is_master() || is_monitor() || is_auditioner()) { - _mute_master->set_solo_ignore (true); - } - if ((prop = node.property (X_("denormal-protection"))) != 0) { set_denormal_protection (string_is_affirmative (prop->value())); } @@ -2767,6 +2824,7 @@ Route::set_processor_state (const XMLNode& node) } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || prop->value() == "lv2" || prop->value() == "windows-vst" || + prop->value() == "mac-vst" || prop->value() == "lxvst" || prop->value() == "luaproc" || prop->value() == "audiounit") { @@ -2828,6 +2886,7 @@ Route::set_processor_state (const XMLNode& node) } { + Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); Glib::Threads::RWLock::WriterLock lm (_processor_lock); /* re-assign _processors w/o process-lock. * if there's an IO-processor present in _processors but @@ -2835,7 +2894,6 @@ Route::set_processor_state (const XMLNode& node) * a process lock. */ _processors = new_order; - Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ()); if (must_configure) { configure_processors_unlocked (0, &lm); @@ -2994,8 +3052,7 @@ Route::add_aux_send (boost::shared_ptr route, boost::shared_ptrprocess_lock ()); - boost::shared_ptr sendpan (new Pannable (_session)); - listener.reset (new InternalSend (_session, sendpan, _mute_master, boost::dynamic_pointer_cast(shared_from_this()), route, Delivery::Aux)); + listener.reset (new InternalSend (_session, _pannable, _mute_master, boost::dynamic_pointer_cast(shared_from_this()), route, Delivery::Aux)); } add_processor (listener, before); @@ -3173,6 +3230,11 @@ Route::direct_feeds_according_to_reality (boost::shared_ptr other, bool* if (iop != 0) { boost::shared_ptr iop_out = iop->output(); + if (other.get() == this && iop_out && iop->input() && iop_out->connected_to (iop->input())) { + // TODO this needs a delaylines in the Insert to align connections (!) + DEBUG_TRACE (DEBUG::Graph, string_compose ("\tIOP %1 does feed its own return (%2)\n", iop->name(), other->name())); + continue; + } if ((iop_out && other->all_inputs().fed_by (iop_out)) || iop->feeds (other)) { DEBUG_TRACE (DEBUG::Graph, string_compose ("\tIOP %1 does feed %2\n", iop->name(), other->name())); if (via_send_only) { @@ -3327,46 +3389,56 @@ Route::output_change_handler (IOChange change, void * /*src*/) io_changed (); /* EMIT SIGNAL */ } - if (_solo_control->soloed_by_others_downstream()) { - int sbod = 0; - /* checking all all downstream routes for - * explicit of implict solo is a rather drastic measure, - * ideally the input_change_handler() of the other route - * would propagate the change to us. + if ((change.type & IOChange::ConnectionsChanged)) { + + /* do this ONLY if connections have changed. Configuration + * changes do not, by themselves alter solo upstream or + * downstream status. */ - boost::shared_ptr routes = _session.get_routes (); - if (_output->connected()) { - for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { - if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) { - continue; - } - bool sends_only; - bool does_feed = direct_feeds_according_to_reality (*i, &sends_only); - if (does_feed && !sends_only) { - if ((*i)->soloed()) { - ++sbod; - break; + + if (_solo_control->soloed_by_others_downstream()) { + int sbod = 0; + /* checking all all downstream routes for + * explicit of implict solo is a rather drastic measure, + * ideally the input_change_handler() of the other route + * would propagate the change to us. + */ + boost::shared_ptr routes = _session.get_routes (); + if (_output->connected()) { + for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) { + continue; + } + bool sends_only; + bool does_feed = direct_feeds_according_to_reality (*i, &sends_only); + if (does_feed && !sends_only) { + if ((*i)->soloed()) { + ++sbod; + break; + } } } } - } - int delta = sbod - _solo_control->soloed_by_others_downstream(); - if (delta <= 0) { - // do not allow new connections to change implicit solo (no propagation) - _solo_control->mod_solo_by_others_downstream (delta); - // Session::route_solo_changed() does not propagate indirect solo-changes - // propagate upstream to tracks - for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { - if ((*i).get() == this || !can_solo()) { - continue; - } - bool sends_only; - bool does_feed = (*i)->feeds (shared_from_this(), &sends_only); - if (delta != 0 && does_feed && !sends_only) { - (*i)->solo_control()->mod_solo_by_others_downstream (delta); + + int delta = sbod - _solo_control->soloed_by_others_downstream(); + if (delta <= 0) { + // do not allow new connections to change implicit solo (no propagation) + _solo_control->mod_solo_by_others_downstream (delta); + // Session::route_solo_changed() does not propagate indirect solo-changes + // propagate upstream to tracks + boost::shared_ptr shared_this = shared_from_this(); + for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + if ((*i).get() == this || !can_solo()) { + continue; + } + bool sends_only; + bool does_feed = (*i)->feeds (shared_this, &sends_only); + if (delta != 0 && does_feed && !sends_only) { + (*i)->solo_control()->mod_solo_by_others_downstream (delta); + } } - } + } } } } @@ -3391,6 +3463,22 @@ Route::pans_required () const return max (n_inputs ().n_audio(), processor_max_streams.n_audio()); } +void +Route::flush_processor_buffers_locked (framecnt_t nframes) +{ + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr d = boost::dynamic_pointer_cast (*i); + if (d) { + d->flush_buffers (nframes); + } else { + boost::shared_ptr p = boost::dynamic_pointer_cast (*i); + if (p) { + p->flush_buffers (nframes); + } + } + } +} + int Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing) { @@ -3436,12 +3524,8 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, _trim->apply_gain_automation (false); passthru (bufs, start_frame, end_frame, nframes, 0); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - boost::shared_ptr d = boost::dynamic_pointer_cast (*i); - if (d) { - d->flush_buffers (nframes); - } - } + flush_processor_buffers_locked (nframes); + return 0; } @@ -3480,12 +3564,8 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in passthru (bufs, start_frame, end_frame, nframes, declick); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - boost::shared_ptr d = boost::dynamic_pointer_cast (*i); - if (d) { - d->flush_buffers (nframes); - } - } + flush_processor_buffers_locked (nframes); + return 0; } @@ -3493,6 +3573,7 @@ int Route::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*end_frame*/, bool& /* need_butler */) { silence (nframes); + flush_processor_buffers_locked (nframes); return 0; } @@ -4496,10 +4577,17 @@ Route::setup_invisible_processors () new_processors.insert (amp, _monitor_control); } + /* TRIM CONTROL */ + + if (_trim && _trim->active()) { + assert (!_trim->display_to_user ()); + new_processors.push_front (_trim); + } + /* INTERNAL RETURN */ - /* doing this here means that any monitor control will come just after - the return. + /* doing this here means that any monitor control will come after + the return and trim. */ if (_intreturn) { @@ -4507,10 +4595,6 @@ Route::setup_invisible_processors () new_processors.push_front (_intreturn); } - if (_trim && _trim->active()) { - assert (!_trim->display_to_user ()); - new_processors.push_front (_trim); - } /* EXPORT PROCESSOR */ if (_capturing_processor) { @@ -5250,17 +5334,11 @@ Route::muted_by_others_soloing () const return false; } - return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated(); + return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated(); } void Route::clear_all_solo_state () { - double v = _solo_safe_control->get_value (); - _solo_control->clear_all_solo_state (); - - if (v != 0.0) { - _solo_safe_control->set_value (v, Controllable::NoGroup); - } }