X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=4dcdcf1898a621d4a2018c08386e1565a4a82f24;hb=932d6c79d01be93f491415ef1491bca17d92671f;hp=aee3bdf2c34b9ec7fc5a42ab6bd87790acf21bb7;hpb=02583c300f1a909c031b75e9e264696cce0a53e2;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index aee3bdf2c3..4dcdcf1898 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -58,6 +58,7 @@ #include "ardour/session.h" #include "ardour/timestamps.h" #include "ardour/utils.h" +#include "ardour/graph.h" #include "i18n.h" @@ -72,6 +73,7 @@ PBD::Signal0 Route::RemoteControlIDChange; Route::Route (Session& sess, string name, Flag flg, DataType default_type) : SessionObject (sess, name) , AutomatableControls (sess) + , GraphNode( sess.route_graph ) , _active (true) , _initial_delay (0) , _roll_delay (0) @@ -80,7 +82,8 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , _meter_point (MeterPostFader) , _phase_invert (0) , _self_solo (false) - , _soloed_by_others (0) + , _soloed_by_others_upstream (0) + , _soloed_by_others_downstream (0) , _solo_isolated (0) , _denormal_protection (false) , _recordable (true) @@ -89,7 +92,6 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) , _solo_control (new SoloControllable (X_("solo"), *this)) , _mute_control (new MuteControllable (X_("mute"), *this)) , _mute_master (new MuteMaster (sess, name)) - , _mute_points (MuteMaster::AllPoints) , _have_internal_generator (false) , _solo_safe (false) , _default_type (default_type) @@ -121,10 +123,10 @@ Route::init () /* add amp processor */ - _amp.reset (new Amp (_session, _mute_master)); + _amp.reset (new Amp (_session)); add_processor (_amp, PostFader); - /* add standard processors other than amp (added by ::init()) */ + /* add standard processors: meter, main outs, monitor out */ _meter.reset (new PeakMeter (_session)); _meter->set_display_to_user (false); @@ -132,7 +134,7 @@ Route::init () add_processor (_meter, PostFader); _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); - + add_processor (_main_outs, PostFader); if (is_monitor()) { @@ -155,9 +157,15 @@ Route::init () */ _monitor_control.reset (new MonitorProcessor (_session)); add_processor (_monitor_control, i); - } + /* no panning on the monitor main outs */ + _main_outs->panner()->set_bypassed (true); + } + + if (is_master() || is_monitor() || is_hidden()) { + _mute_master->set_solo_ignore (true); + } /* now that we have _meter, its safe to connect to this */ @@ -265,8 +273,8 @@ Route::ensure_track_or_route_name(string name, Session &session) { string newname = name; - while (session.route_by_name (newname) != NULL) { - newname = bump_name_once (newname); + while (!session.io_name_is_legal (newname)) { + newname = bump_name_once (newname, '.'); } return newname; @@ -416,7 +424,7 @@ Route::process_output_buffers (BufferSet& bufs, for (BufferSet::audio_iterator i = bufs.audio_begin(); i != bufs.audio_end(); ++i, ++chn) { Sample* const sp = i->data(); - if (_phase_invert & chn) { + if (_phase_invert & (1<input_streams()) { - cerr << _name << " bufs = " << bufs.count() - << " input for " << (*i)->name() << " = " << (*i)->input_streams() - << endl; - } - assert (bufs.count() == (*i)->input_streams()); + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back()); - bufs.set_count ((*i)->output_streams()); + if (bufs.count() != (*i)->input_streams()) { + cerr << _name << " bufs = " << bufs.count() + << " input for " << (*i)->name() << " = " << (*i)->input_streams() + << endl; } + assert (bufs.count() == (*i)->input_streams()); + + (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back()); + bufs.set_count ((*i)->output_streams()); } } @@ -476,7 +480,7 @@ Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, assert (bufs.available() >= input_streams()); if (_input->n_ports() == ChanCount::ZERO) { - silence (nframes); + silence_unlocked (nframes); } bufs.set_count (input_streams()); @@ -518,14 +522,18 @@ Route::passthru_silence (sframes_t start_frame, sframes_t end_frame, nframes_t n void Route::set_listen (bool yn, void* src) { + if (_solo_safe) { + return; + } + if (_monitor_send) { if (yn != _monitor_send->active()) { if (yn) { - _monitor_send->set_solo_level (1); _monitor_send->activate (); - } else { - _monitor_send->set_solo_level (0); + _mute_master->set_soloed (true); + } else { _monitor_send->deactivate (); + _mute_master->set_soloed (false); } listen_changed (src); /* EMIT SIGNAL */ @@ -572,8 +580,8 @@ Route::set_solo (bool yn, void *src) if (self_soloed() != yn) { set_self_solo (yn); - set_delivery_solo (); - solo_changed (src); /* EMIT SIGNAL */ + set_mute_master_solo (); + solo_changed (true, src); /* EMIT SIGNAL */ _solo_control->Changed (); /* EMIT SIGNAL */ } } @@ -581,42 +589,91 @@ Route::set_solo (bool yn, void *src) void Route::set_self_solo (bool yn) { - _self_solo = yn; + _self_solo = yn; } void -Route::mod_solo_by_others (int32_t delta) +Route::mod_solo_by_others_upstream (int32_t delta) { + if (_solo_safe) { + return; + } + + uint32_t old_sbu = _soloed_by_others_upstream; + if (delta < 0) { - if (_soloed_by_others >= (uint32_t) delta) { - _soloed_by_others += delta; + if (_soloed_by_others_upstream >= (uint32_t) abs (delta)) { + _soloed_by_others_upstream += delta; } else { - _soloed_by_others = 0; + _soloed_by_others_upstream = 0; } } else { - _soloed_by_others += delta; - } + _soloed_by_others_upstream += delta; + } + + DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 SbU delta %2 = %3 old = %4 sbd %5 ss %6 exclusive %7\n", + name(), delta, _soloed_by_others_upstream, old_sbu, + _soloed_by_others_downstream, _self_solo, Config->get_exclusive_solo())); + + /* push the inverse solo change to everything that feeds us. + + This is important for solo-within-group. When we solo 1 track out of N that + feed a bus, that track will cause mod_solo_by_upstream (+1) to be called + on the bus. The bus then needs to call mod_solo_by_downstream (-1) on all + tracks that feed it. This will silence them if they were audible because + of a bus solo, but the newly soloed track will still be audible (because + it is self-soloed). + + but .. do this only when we are being told to solo-by-upstream (i.e delta = +1), + not in reverse. + */ + + if ((_self_solo || _soloed_by_others_downstream) && + ((old_sbu == 0 && _soloed_by_others_upstream > 0) || + (old_sbu > 0 && _soloed_by_others_upstream == 0))) { + + if (delta > 0 || !Config->get_exclusive_solo()) { + DEBUG_TRACE (DEBUG::Solo, "\t ... INVERT push\n"); + for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) { + boost::shared_ptr sr = i->r.lock(); + if (sr) { + sr->mod_solo_by_others_downstream (-delta); + } + } + } + } - set_delivery_solo (); + set_mute_master_solo (); + solo_changed (false, this); } void -Route::set_delivery_solo () +Route::mod_solo_by_others_downstream (int32_t delta) { - /* tell all delivery processors what the solo situation is, so that they keep - delivering even though Session::soloing() is true and they were not - explicitly soloed. - */ + if (_solo_safe) { + return; + } - Glib::RWLock::ReaderLock rm (_processor_lock); - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - boost::shared_ptr d; - - if ((d = boost::dynamic_pointer_cast (*i)) != 0) { - d->set_solo_level (soloed ()); - d->set_solo_isolated (solo_isolated()); + if (delta < 0) { + if (_soloed_by_others_downstream >= (uint32_t) abs (delta)) { + _soloed_by_others_downstream += delta; + } else { + _soloed_by_others_downstream = 0; } + } else { + _soloed_by_others_downstream += 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, this); +} + +void +Route::set_mute_master_solo () +{ + _mute_master->set_soloed (self_soloed() || soloed_by_others_downstream() || soloed_by_others_upstream()); } void @@ -635,32 +692,42 @@ Route::set_solo_isolated (bool yn, void *src) boost::shared_ptr routes = _session.get_routes (); for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) { + + if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_hidden()) { + continue; + } + bool sends_only; - bool does_feed = feeds (*i, &sends_only); + bool does_feed = direct_feeds (*i, &sends_only); // we will recurse anyway, so don't use ::feeds() if (does_feed && !sends_only) { (*i)->set_solo_isolated (yn, (*i)->route_group()); } } - bool changed = false; + /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */ + + bool changed = false; if (yn) { - if (_solo_isolated == 0) { - changed = true; - } + if (_solo_isolated == 0) { + _mute_master->set_solo_ignore (true); + changed = true; + } _solo_isolated++; } else { - changed = (_solo_isolated == 1); if (_solo_isolated > 0) { _solo_isolated--; + if (_solo_isolated == 0) { + _mute_master->set_solo_ignore (false); + changed = true; + } } } - if (changed) { - set_delivery_solo (); - solo_isolated_changed (src); - } + if (changed) { + solo_isolated_changed (src); + } } bool @@ -672,13 +739,12 @@ Route::solo_isolated () const void Route::set_mute_points (MuteMaster::MutePoint mp) { - _mute_points = mp; - mute_points_changed (); /* EMIT SIGNAL */ - - if (_mute_master->muted()) { - _mute_master->mute_at (_mute_points); - mute_changed (this); /* EMIT SIGNAL */ - } + _mute_master->set_mute_points (mp); + mute_points_changed (); /* EMIT SIGNAL */ + + if (_mute_master->muted_by_self()) { + mute_changed (this); /* EMIT SIGNAL */ + } } void @@ -690,20 +756,15 @@ Route::set_mute (bool yn, void *src) } if (muted() != yn) { - if (yn) { - _mute_master->mute_at (_mute_points); - } else { - _mute_master->clear_mute (); - } - + _mute_master->set_muted_by_self (yn); mute_changed (src); /* EMIT SIGNAL */ } } bool -Route::muted() const +Route::muted () const { - return _mute_master->muted (); + return _mute_master->muted_by_self(); } #if 0 @@ -810,12 +871,6 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite if (isend && _session.monitor_out() && (isend->target_id() == _session.monitor_out()->id())) { _monitor_send = isend; - - if (_monitor_send->active()) { - _monitor_send->set_solo_level (1); - } else { - _monitor_send->set_solo_level (0); - } } if (activation_allowed && (processor != _monitor_send)) { @@ -828,187 +883,11 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } -bool -Route::add_processor_from_xml (const XMLNode& node, ProcessorList::iterator iter) -{ - const XMLProperty *prop; - - if (node.name() != "Processor") { - return false; - } - - try { - if ((prop = node.property ("type")) != 0) { - - boost::shared_ptr processor; - - /* meter, amp, monitor and intreturn are all singletons, deal with them first */ - - if (prop->value() == "meter") { - - if (_meter) { - if (_meter->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - PeakMeter* pm = new PeakMeter (_session); - - if (pm->set_state (node, Stateful::loading_state_version)) { - delete pm; - return false; - } - - _meter.reset (pm); - _meter->set_display_to_user (_meter_point == MeterCustom); - - processor = _meter; - - } else if (prop->value() == "monitor") { - - if (_monitor_control) { - if (_monitor_control->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - MonitorProcessor* mp = new MonitorProcessor (_session); - if (mp->set_state (node, Stateful::loading_state_version)) { - delete mp; - return false; - } - - _monitor_control.reset (mp); - processor = _monitor_control; - - } else if (prop->value() == "amp") { - - if (_amp) { - processor = _amp; - if (processor->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - /* no reason to add it */ - return true; - } - } - - Amp* a = new Amp (_session, _mute_master); - if (_amp->set_state (node, Stateful::loading_state_version)) { - delete a; - return false; - } - - _amp.reset (a); - processor = _amp; - - } else if (prop->value() == "intreturn") { - - /* a route only has one internal return. If it exists already - just set its state, and return - */ - - if (_intreturn) { - if (_intreturn->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - InternalReturn* iret = new InternalReturn (_session); - if (iret->set_state (node, Stateful::loading_state_version)) { - delete iret; - return false; - } - - _intreturn.reset (iret); - processor = _intreturn; - - } else if (prop->value() == "main-outs") { - - if (_main_outs) { - if (_main_outs->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - Delivery* del = new Delivery (_session, _output, _mute_master, X_("toBeResetFroXML"), Delivery::Role (0)); - if (del->set_state (node, Stateful::loading_state_version)) { - delete del; - return false; - } - - _main_outs.reset (del); - processor = _main_outs; - - } else if (prop->value() == "intsend") { - - InternalSend* isend = new InternalSend (_session, _mute_master, boost::shared_ptr(), Delivery::Role (0)); - if (isend->set_state (node, Stateful::loading_state_version)) { - delete isend; - return false; - } - - processor.reset (isend); - - } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || - prop->value() == "lv2" || - prop->value() == "vst" || - prop->value() == "audiounit") { - - processor.reset (new PluginInsert(_session, node)); - - } else if (prop->value() == "port") { - - processor.reset (new PortInsert (_session, _mute_master, node)); - - } else if (prop->value() == "send") { - - processor.reset (new Send (_session, _mute_master, node)); - - } else { - error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; - return false; - } - - if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) { - /* check for invisible processors stacked at the end and leave them there */ - ProcessorList::iterator p; - p = _processors.end(); - --p; - while (!(*p)->display_to_user() && p != _processors.begin()) { - --p; - } - ++p; - iter = p; - } - - return (add_processor (processor, iter, 0, false) == 0); - - } else { - error << _("Processor XML node has no type property") << endmsg; - return false; - } - } - - catch (failed_constructor &err) { - warning << _("processor could not be created. Ignored.") << endmsg; - return false; - } -} - - bool Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorList::iterator iter) { @@ -1026,18 +905,18 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis prop->value() == "vst" || prop->value() == "audiounit") { - processor.reset (new PluginInsert (_session, node)); + processor.reset (new PluginInsert (_session)); } else { - processor.reset (new PortInsert (_session, _mute_master, node)); + processor.reset (new PortInsert (_session, _mute_master)); } } } else if (node.name() == "Send") { - processor.reset (new Send (_session, _mute_master, node, version)); + processor.reset (new Send (_session, _mute_master)); } else { @@ -1045,6 +924,10 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version, ProcessorLis return false; } + if (processor->set_state (node, version)) { + return false; + } + if (iter == _processors.end() && processor->display_to_user() && !_processors.empty()) { /* check for invisible processors stacked at the end and leave them there */ ProcessorList::iterator p; @@ -1145,6 +1028,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1345,6 +1229,7 @@ Route::clear_processors (Placement p) processor_max_streams.reset(); _have_internal_generator = false; processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); if (!already_deleting) { _session.clear_deletion_in_progress(); @@ -1436,6 +1321,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream processor->drop_references (); processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1527,6 +1413,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1567,18 +1454,16 @@ Route::configure_processors_unlocked (ProcessorStreams* err) uint32_t index = 0; DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configure processors\n", _name)); -#ifndef NDEBUG DEBUG_TRACE (DEBUG::Processors, "{\n"); for (list >::const_iterator p = _processors.begin(); p != _processors.end(); ++p) { DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 ID = %2\n", (*p)->name(), (*p)->id())); } DEBUG_TRACE (DEBUG::Processors, "}\n"); -#endif for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++index) { if ((*p)->can_support_io_configuration(in, out)) { - DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1in = %2 out = %3\n",(*p)->name(), in, out)); + DEBUG_TRACE (DEBUG::Processors, string_compose ("\t%1 in = %2 out = %3\n",(*p)->name(), in, out)); configuration.push_back(make_pair(in, out)); in = out; } else { @@ -1606,7 +1491,12 @@ Route::configure_processors_unlocked (ProcessorStreams* err) /* make sure we have sufficient scratch buffers to cope with the new processor configuration */ - _session.ensure_buffers (n_process_buffers ()); + { + Glib::Mutex::Lock em (_session.engine().process_lock ()); + _session.ensure_buffers (n_process_buffers ()); + } + + DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name)); _in_configure_processors = false; return 0; @@ -1767,7 +1657,10 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err } } - processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + if (true) { + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); + } return 0; } @@ -1828,8 +1721,10 @@ Route::state(bool full_state) } node->add_property ("order-keys", order_string); node->add_property ("self-solo", (_self_solo ? "yes" : "no")); - snprintf (buf, sizeof (buf), "%d", _soloed_by_others); - node->add_property ("soloed-by-others", buf); + snprintf (buf, sizeof (buf), "%d", _soloed_by_others_upstream); + node->add_property ("soloed-by-upstream", buf); + snprintf (buf, sizeof (buf), "%d", _soloed_by_others_downstream); + node->add_property ("soloed-by-downstream", buf); node->add_child_nocopy (_input->state (full_state)); node->add_child_nocopy (_output->state (full_state)); @@ -1895,6 +1790,10 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) _flags = Flag (0); } + if (is_master() || is_monitor() || is_hidden()) { + _mute_master->set_solo_ignore (true); + } + /* add all processors (except amp, which is always present) */ nlist = node.children(); @@ -1927,9 +1826,14 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) set_self_solo (string_is_affirmative (prop->value())); } - if ((prop = node.property ("soloed-by-others")) != 0) { - _soloed_by_others = 0; // needed for mod_solo_by_others () to work - mod_solo_by_others (atoi (prop->value())); + if ((prop = node.property ("soloed-by-upstream")) != 0) { + _soloed_by_others_upstream = 0; // needed for mod_.... () to work + mod_solo_by_others_upstream (atoi (prop->value())); + } + + if ((prop = node.property ("soloed-by-downstream")) != 0) { + _soloed_by_others_downstream = 0; // needed for mod_.... () to work + mod_solo_by_others_downstream (atoi (prop->value())); } if ((prop = node.property ("solo-isolated")) != 0) { @@ -1951,7 +1855,8 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/) } if ((prop = node.property (X_("meter-point"))) != 0) { - _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point)); + MeterPoint mp = MeterPoint (string_2_enum (prop->value (), _meter_point)); + set_meter_point (mp); if (_meter) { _meter->set_display_to_user (_meter_point == MeterCustom); } @@ -2035,11 +1940,6 @@ Route::_set_state_2X (const XMLNode& node, int version) /* 2X things which still remain to be handled: * default-type - * muted - * mute-affects-pre-fader - * mute-affects-post-fader - * mute-affects-control-outs - * mute-affects-main-outs * automation * controlouts */ @@ -2054,58 +1954,7 @@ Route::_set_state_2X (const XMLNode& node, int version) } else { _flags = Flag (0); } - - /* add standard processors */ - - _meter.reset (new PeakMeter (_session)); - add_processor (_meter, PreFader); - - if (is_monitor()) { - /* where we listen to tracks */ - _intreturn.reset (new InternalReturn (_session)); - add_processor (_intreturn, PreFader); - - _monitor_control.reset (new MonitorProcessor (_session)); - add_processor (_monitor_control, PostFader); - } - - _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); - add_processor (_main_outs, PostFader); - - /* IOs */ - - nlist = node.children (); - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - - child = *niter; - - if (child->name() == IO::state_node_name) { - - /* there is a note in IO::set_state_2X() about why we have to call - this directly. - */ - - _input->set_state_2X (*child, version, true); - _output->set_state_2X (*child, version, false); - - if ((prop = child->property (X_("name"))) != 0) { - set_name (prop->value ()); - } - - if ((prop = child->property (X_("id"))) != 0) { - _id = prop->value (); - } - - if ((prop = child->property (X_("active"))) != 0) { - bool yn = string_is_affirmative (prop->value()); - _active = !yn; // force switch - set_active (yn); - } - } - - /* XXX: panners? */ - } - + if ((prop = node.property (X_("phase-invert"))) != 0) { set_phase_invert (string_is_affirmative (prop->value())); } @@ -2122,6 +1971,65 @@ Route::_set_state_2X (const XMLNode& node, int version) set_solo (yn, this); } + if ((prop = node.property (X_("muted"))) != 0) { + + bool first = true; + bool muted = string_is_affirmative (prop->value()); + + if (muted){ + + string mute_point; + + if ((prop = node.property (X_("mute-affects-pre-fader"))) != 0) { + + if (string_is_affirmative (prop->value())){ + mute_point = mute_point + "PreFader"; + first = false; + } + } + + if ((prop = node.property (X_("mute-affects-post-fader"))) != 0) { + + if (string_is_affirmative (prop->value())){ + + if (!first) { + mute_point = mute_point + ","; + } + + mute_point = mute_point + "PostFader"; + first = false; + } + } + + if ((prop = node.property (X_("mute-affects-control-outs"))) != 0) { + + if (string_is_affirmative (prop->value())){ + + if (!first) { + mute_point = mute_point + ","; + } + + mute_point = mute_point + "Listen"; + first = false; + } + } + + if ((prop = node.property (X_("mute-affects-main-outs"))) != 0) { + + if (string_is_affirmative (prop->value())){ + + if (!first) { + mute_point = mute_point + ","; + } + + mute_point = mute_point + "Main"; + } + } + + _mute_master->set_mute_points (mute_point); + } + } + if ((prop = node.property (X_("meter-point"))) != 0) { _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point)); } @@ -2161,6 +2069,78 @@ Route::_set_state_2X (const XMLNode& node, int version) } } + /* add standard processors */ + + //_meter.reset (new PeakMeter (_session)); + //add_processor (_meter, PreFader); + + if (is_monitor()) { + /* where we listen to tracks */ + _intreturn.reset (new InternalReturn (_session)); + add_processor (_intreturn, PreFader); + + _monitor_control.reset (new MonitorProcessor (_session)); + add_processor (_monitor_control, PostFader); + } + + _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); + add_processor (_main_outs, PostFader); + + /* IOs */ + + nlist = node.children (); + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + + child = *niter; + + if (child->name() == IO::state_node_name) { + + /* there is a note in IO::set_state_2X() about why we have to call + this directly. + */ + + _input->set_state_2X (*child, version, true); + _output->set_state_2X (*child, version, false); + + if ((prop = child->property (X_("name"))) != 0) { + Route::set_name (prop->value ()); + } + + if ((prop = child->property (X_("id"))) != 0) { + _id = prop->value (); + } + + if ((prop = child->property (X_("active"))) != 0) { + bool yn = string_is_affirmative (prop->value()); + _active = !yn; // force switch + set_active (yn); + } + + if ((prop = child->property (X_("gain"))) != 0) { + gain_t val; + + if (sscanf (prop->value().c_str(), "%f", &val) == 1) { + _amp->gain_control()->set_value (val); + } + } + + /* Set up Panners in the IO */ + XMLNodeList io_nlist = child->children (); + + XMLNodeConstIterator io_niter; + XMLNode *io_child; + + for (io_niter = io_nlist.begin(); io_niter != io_nlist.end(); ++io_niter) { + + io_child = *io_niter; + + if (io_child->name() == X_("Panner")) { + _main_outs->panner()->set_state(*io_child, version); + } + } + } + } + XMLNodeList redirect_nodes; for (niter = nlist.begin(); niter != nlist.end(); ++niter){ @@ -2239,101 +2219,95 @@ Route::set_processor_state (const XMLNode& node) { const XMLNodeList &nlist = node.children(); XMLNodeConstIterator niter; - ProcessorList::iterator i, o; - - // Iterate through existing processors, remove those which are not in the state list - - for (i = _processors.begin(); i != _processors.end(); ) { - - /* leave amp alone, always */ - - if ((*i) == _amp) { - ++i; - continue; - } + ProcessorList new_order; + bool must_configure = false; - ProcessorList::iterator tmp = i; - ++tmp; - - bool processorInStateList = false; - - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - - XMLProperty* id_prop = (*niter)->property(X_("id")); - - if (id_prop && (*i)->id() == id_prop->value()) { - processorInStateList = true; - break; - } - } - - if (!processorInStateList) { - remove_processor (*i); - } - - i = tmp; - } - - // Iterate through state list and make sure all processors are on the track and in the correct order, - // set the state of existing processors according to the new state on the same go - - i = _processors.begin(); - - for (niter = nlist.begin(); niter != nlist.end(); ++niter, ++i) { + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { XMLProperty* prop = (*niter)->property ("type"); - o = i; - - // Check whether the next processor in the list is the right one, - // except for "amp" which is always there and may not have the - // old ID since it is always created anew in every Route + if (prop->value() == "amp") { + _amp->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_amp); + } else if (prop->value() == "meter") { + _meter->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_meter); + } else if (prop->value() == "main-outs") { + _main_outs->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_main_outs); + } else if (prop->value() == "intreturn") { + if (!_intreturn) { + _intreturn.reset (new InternalReturn (_session)); + must_configure = true; + } + _intreturn->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_intreturn); + } else if (is_monitor() && prop->value() == "monitor") { + if (!_monitor_control) { + _monitor_control.reset (new MonitorProcessor (_session)); + must_configure = true; + } + _monitor_control->set_state (**niter, Stateful::current_state_version); + new_order.push_back (_monitor_control); + } else { + ProcessorList::iterator o; - if (prop->value() != "amp") { - while (o != _processors.end()) { + for (o = _processors.begin(); o != _processors.end(); ++o) { XMLProperty* id_prop = (*niter)->property(X_("id")); if (id_prop && (*o)->id() == id_prop->value()) { + (*o)->set_state (**niter, Stateful::current_state_version); + new_order.push_back (*o); break; } - - ++o; - } - } - - // If the processor (*niter) is not on the route, - // create it and move it to the correct location - - if (o == _processors.end()) { - - if (add_processor_from_xml (**niter, i)) { - --i; // move iterator to the newly inserted processor - } else { - cerr << "Error restoring route: unable to restore processor" << endl; } - } else { - - // Otherwise, the processor already exists; just - // ensure it is at the location provided in the XML state - - if (i != o) { - boost::shared_ptr tmp = (*o); - _processors.erase (o); // remove the old copy - _processors.insert (i, tmp); // insert the processor at the correct location - --i; // move iterator to the correct processor - } - - // and make it (just) so + // If the processor (*niter) is not on the route then create it + + if (o == _processors.end()) { + + boost::shared_ptr processor; + + if (prop->value() == "intsend") { + + processor.reset (new InternalSend (_session, _mute_master, boost::shared_ptr(), Delivery::Role (0))); + + } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" || + prop->value() == "lv2" || + prop->value() == "vst" || + prop->value() == "audiounit") { + + processor.reset (new PluginInsert(_session)); + + } else if (prop->value() == "port") { + + processor.reset (new PortInsert (_session, _mute_master)); + + } else if (prop->value() == "send") { + + processor.reset (new Send (_session, _mute_master)); + + } else { + error << string_compose(_("unknown Processor type \"%1\"; ignored"), prop->value()) << endmsg; + continue; + } - (*i)->set_state (**niter, Stateful::current_state_version); - } - } + processor->set_state (**niter, Stateful::current_state_version); + new_order.push_back (processor); + must_configure = true; + } + } + } - /* note: there is no configure_processors() call because we figure that - the XML state represents a working signal route. - */ + { + Glib::RWLock::WriterLock lm (_processor_lock); + _processors = new_order; + if (must_configure) { + configure_processors_unlocked (0); + } + } - processors_changed (RouteProcessorChange ()); + processors_changed (RouteProcessorChange ()); + set_processor_positions (); } void @@ -2346,31 +2320,37 @@ Route::curve_reallocate () void Route::silence (nframes_t nframes) { - if (!_silent) { - - _output->silence (nframes); - - { - Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (!lm.locked()) { + return; + } - if (lm.locked()) { - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - boost::shared_ptr pi; + silence_unlocked (nframes); +} - if (!_active && (pi = boost::dynamic_pointer_cast (*i)) != 0) { - // skip plugins, they don't need anything when we're not active - continue; - } +void +Route::silence_unlocked (nframes_t nframes) +{ + /* Must be called with the processor lock held */ + + if (!_silent) { - (*i)->silence (nframes); - } + _output->silence (nframes); - if (nframes == _session.get_block_size()) { - // _silent = true; - } + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + boost::shared_ptr pi; + + if (!_active && (pi = boost::dynamic_pointer_cast (*i)) != 0) { + // skip plugins, they don't need anything when we're not active + continue; } + + (*i)->silence (nframes); + } + + if (nframes == _session.get_block_size()) { + // _silent = true; } - } } @@ -2435,11 +2415,6 @@ Route::listen_via (boost::shared_ptr route, Placement placement, bool /*a if (route == _session.monitor_out()) { _monitor_send = boost::dynamic_pointer_cast(d); - if (_monitor_send->active()) { - _monitor_send->set_solo_level (1); - } else { - _monitor_send->set_solo_level (0); - } } /* already listening via the specified IO: do nothing */ @@ -2464,8 +2439,6 @@ Route::listen_via (boost::shared_ptr route, Placement placement, bool /*a } else { listener.reset (new InternalSend (_session, _mute_master, route, (aux ? Delivery::Aux : Delivery::Listen))); - if (route == _session.monitor_out()) { - } } } catch (failed_constructor& err) { @@ -2530,7 +2503,53 @@ Route::set_comment (string cmt, void *src) } bool -Route::feeds (boost::shared_ptr other, bool* only_send) +Route::add_fed_by (boost::shared_ptr other, bool via_sends_only) +{ + FeedRecord fr (other, via_sends_only); + + pair result = _fed_by.insert (fr); + + if (!result.second) { + + /* already a record for "other" - make sure sends-only information is correct */ + if (!via_sends_only && result.first->sends_only) { + FeedRecord* frp = const_cast(&(*result.first)); + frp->sends_only = false; + } + } + + return result.second; +} + +void +Route::clear_fed_by () +{ + _fed_by.clear (); +} + +bool +Route::feeds (boost::shared_ptr other, bool* via_sends_only) +{ + const FedBy& fed_by (other->fed_by()); + + for (FedBy::iterator f = fed_by.begin(); f != fed_by.end(); ++f) { + boost::shared_ptr sr = f->r.lock(); + + if (sr && (sr.get() == this)) { + + if (via_sends_only) { + *via_sends_only = f->sends_only; + } + + return true; + } + } + + return false; +} + +bool +Route::direct_feeds (boost::shared_ptr other, bool* only_send) { DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _name)); @@ -2627,12 +2646,17 @@ int Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, bool session_state_changing, bool /*can_record*/, bool /*rec_monitors_input*/) { + Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (!lm.locked()) { + return 0; + } + if (n_outputs().n_total() == 0) { return 0; } if (!_active || n_inputs() == ChanCount::ZERO) { - silence (nframes); + silence_unlocked (nframes); return 0; } if (session_state_changing) { @@ -2642,7 +2666,7 @@ Route::no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, XXX note the absurdity of ::no_roll() being called when we ARE rolling! */ - silence (nframes); + silence_unlocked (nframes); return 0; } /* we're really not rolling, so we're either delivery silence or actually @@ -2662,14 +2686,14 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame) if (_roll_delay > nframes) { _roll_delay -= nframes; - silence (nframes); + silence_unlocked (nframes); /* transport frame is not legal for caller to use */ return 0; } else if (_roll_delay > 0) { nframes -= _roll_delay; - silence (_roll_delay); + silence_unlocked (_roll_delay); /* we've written _roll_delay of samples into the output ports, so make a note of that for future reference. @@ -2685,24 +2709,21 @@ Route::check_initial_delay (nframes_t nframes, nframes_t& transport_frame) int Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, - bool /*can_record*/, bool /*rec_monitors_input*/) + bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */) { - { - // automation snapshot can also be called from the non-rt context - // and it uses the processor list, so we try to acquire the lock here - Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); - - if (lm.locked()) { - automation_snapshot (_session.transport_frame(), false); - } + Glib::RWLock::ReaderLock lm (_processor_lock, Glib::TRY_LOCK); + if (!lm.locked()) { + return 0; } + + automation_snapshot (_session.transport_frame(), false); if (n_outputs().n_total() == 0) { return 0; } if (!_active || n_inputs().n_total() == 0) { - silence (nframes); + silence_unlocked (nframes); return 0; } @@ -2721,7 +2742,7 @@ Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int int Route::silent_roll (nframes_t nframes, sframes_t /*start_frame*/, sframes_t /*end_frame*/, - bool /*can_record*/, bool /*rec_monitors_input*/) + bool /*can_record*/, bool /*rec_monitors_input*/, bool& /* need_butler */) { silence (nframes); return 0; @@ -2779,7 +2800,7 @@ Route::flush_processors () } void -Route::set_meter_point (MeterPoint p, void *src) +Route::set_meter_point (MeterPoint p) { /* CAN BE CALLED FROM PROCESS CONTEXT */ @@ -2841,7 +2862,7 @@ Route::set_meter_point (MeterPoint p, void *src) } _meter_point = p; - meter_change (src); /* EMIT SIGNAL */ + meter_change (); /* EMIT SIGNAL */ bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user); @@ -3180,8 +3201,14 @@ void Route::set_phase_invert (bool yn) { if (_phase_invert != yn) { - _phase_invert = 0xffff; // XXX all channels + if (yn) { + _phase_invert = 0xffff; // XXX all channels + } else { + _phase_invert = 0; // XXX no channels + } + phase_invert_changed (); /* EMIT SIGNAL */ + _session.set_dirty (); } } @@ -3305,15 +3332,50 @@ Route::nth_send (uint32_t n) ProcessorList::iterator i; for (i = _processors.begin(); i != _processors.end(); ++i) { - cerr << "check " << (*i)->name() << endl; if (boost::dynamic_pointer_cast (*i)) { if (n-- == 0) { return *i; } - } else { - cerr << "\tnot a send\n"; - } + } } return boost::shared_ptr (); } + +bool +Route::has_io_processor_named (const string& name) +{ + Glib::RWLock::ReaderLock lm (_processor_lock); + ProcessorList::iterator i; + + for (i = _processors.begin(); i != _processors.end(); ++i) { + if (boost::dynamic_pointer_cast (*i) || + boost::dynamic_pointer_cast (*i)) { + if ((*i)->name() == name) { + return true; + } + } + } + + return false; +} + +MuteMaster::MutePoint +Route::mute_points () const +{ + return _mute_master->mute_points (); +} + +void +Route::set_processor_positions () +{ + Glib::RWLock::ReaderLock lm (_processor_lock); + + bool had_amp = false; + for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { + (*i)->set_pre_fader (!had_amp); + if (boost::dynamic_pointer_cast (*i)) { + had_amp = true; + } + } +}