X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=33af0f8abfc199d0046f3d506ad8ae1c3c4eb735;hb=e33d4553b2b333c30835b00741fc5c1fd0e2b36d;hp=2199c71caa2f2f19a0095f7c57401f4797e99fbd;hpb=b3a3e66f7755fe35ace4cbb6b19b54a52bb71a2f;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 2199c71caa..33af0f8abf 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -72,16 +72,63 @@ PBD::Signal0 Route::RemoteControlIDChange; Route::Route (Session& sess, string name, Flag flg, DataType default_type) : SessionObject (sess, name) , AutomatableControls (sess) + , _active (true) + , _initial_delay (0) + , _roll_delay (0) , _flags (flg) + , _pending_declick (true) + , _meter_point (MeterPostFader) + , _phase_invert (0) + , _self_solo (false) + , _soloed_by_others_upstream (0) + , _soloed_by_others_downstream (0) + , _solo_isolated (0) + , _denormal_protection (false) + , _recordable (true) + , _silent (false) + , _declickable (false) , _solo_control (new SoloControllable (X_("solo"), *this)) , _mute_control (new MuteControllable (X_("mute"), *this)) , _mute_master (new MuteMaster (sess, name)) + , _mute_points (MuteMaster::AllPoints) + , _path_muted_by_others (false) + , _have_internal_generator (false) + , _physically_connected (false) + , _graph_level (-1) + , _solo_safe (false) , _default_type (default_type) + , _remote_control_id (0) + , _in_configure_processors (false) +{ + processor_max_streams.reset(); + order_keys[N_("signal")] = order_key_cnt++; +} +int +Route::init () { - init (); + /* add standard controls */ + + _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); + _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); + + add_control (_solo_control); + add_control (_mute_control); + + /* input and output objects */ + + _input.reset (new IO (_session, _name, IO::Input, _default_type)); + _output.reset (new IO (_session, _name, IO::Output, _default_type)); + + _input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2)); + _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); - /* add standard processors other than amp (added by ::init()) */ + /* add amp processor */ + + _amp.reset (new Amp (_session, _mute_master)); + add_processor (_amp, PostFader); + + /* add standard processors: meter, main outs, monitor out */ _meter.reset (new PeakMeter (_session)); _meter->set_display_to_user (false); @@ -89,7 +136,7 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) add_processor (_meter, PostFader); _main_outs.reset (new Delivery (_session, _output, _mute_master, _name, Delivery::Main)); - + add_processor (_main_outs, PostFader); if (is_monitor()) { @@ -112,60 +159,21 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type) */ _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 */ Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this))); -} - -void -Route::init () -{ - _self_solo = false; - _soloed_by_others = 0; - _solo_isolated = 0; - _solo_safe = false; - _active = true; - processor_max_streams.reset(); - _recordable = true; - order_keys[N_("signal")] = order_key_cnt++; - _silent = false; - _meter_point = MeterPostFader; - _initial_delay = 0; - _roll_delay = 0; - _have_internal_generator = false; - _declickable = false; - _pending_declick = true; - _remote_control_id = 0; - _in_configure_processors = false; - _mute_points = MuteMaster::AllPoints; - - _phase_invert = 0; - _denormal_protection = false; - - /* add standard controls */ - - _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); - _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle)); - - add_control (_solo_control); - add_control (_mute_control); - - /* input and output objects */ - - _input.reset (new IO (_session, _name, IO::Input, _default_type)); - _output.reset (new IO (_session, _name, IO::Output, _default_type)); - - _input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2)); - _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); - /* add amp processor */ - - _amp.reset (new Amp (_session, _mute_master)); - add_processor (_amp, PostFader); + return 0; } Route::~Route () @@ -267,7 +275,7 @@ Route::ensure_track_or_route_name(string name, Session &session) { string newname = name; - while (session.route_by_name (newname) != NULL) { + while (!session.io_name_is_legal (newname)) { newname = bump_name_once (newname); } @@ -418,7 +426,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()) { @@ -455,8 +467,6 @@ Route::process_output_buffers (BufferSet& bufs, << endl; } assert (bufs.count() == (*i)->input_streams()); - - cerr << _name << " run processor " << (*i)->name() << " with " << bufs.count() << endl; (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back()); bufs.set_count ((*i)->output_streams()); @@ -477,15 +487,15 @@ Route::passthru (sframes_t start_frame, sframes_t end_frame, nframes_t nframes, _silent = false; - assert (bufs.available() >= _input->n_ports()); + assert (bufs.available() >= input_streams()); if (_input->n_ports() == ChanCount::ZERO) { silence (nframes); } - bufs.set_count (_input->n_ports()); + bufs.set_count (input_streams()); - if (is_monitor() && _session.listening()) { + if (is_monitor() && _session.listening() && !_session.is_auditioning()) { /* control/monitor bus ignores input ports when something is feeding the listen "stream". data will "arrive" into the @@ -522,13 +532,15 @@ 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); _monitor_send->deactivate (); } @@ -576,8 +588,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 */ } } @@ -585,42 +597,67 @@ 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; + } + 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; } - 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; } + + set_mute_master_solo (); + solo_changed (false, this); +} + +void +Route::set_mute_master_solo () +{ + SoloLevel level; + + if (self_soloed()) { + level = SelfSoloed; + } else if (soloed_by_others_upstream()) { + level = UpstreamSoloed; + } else if (soloed_by_others_downstream()) { + level = DownstreamSoloed; + } else { + level = NotSoloed; + } + + _mute_master->set_solo_level (level); } void @@ -639,32 +676,32 @@ 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) */ if (yn) { - if (_solo_isolated == 0) { - changed = true; - } _solo_isolated++; + _mute_master->clear_muted_by_others (); + solo_isolated_changed (src); } else { - changed = (_solo_isolated == 1); if (_solo_isolated > 0) { _solo_isolated--; + solo_isolated_changed (src); } } - if (changed) { - set_delivery_solo (); - solo_isolated_changed (src); - } } bool @@ -676,13 +713,13 @@ 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_points = mp; + _mute_master->set_mute_points (MuteMaster::AllPoints); + mute_points_changed (); /* EMIT SIGNAL */ + + if (_mute_master->muted()) { + mute_changed (this); /* EMIT SIGNAL */ + } } void @@ -693,21 +730,56 @@ Route::set_mute (bool yn, void *src) return; } - if (muted() != yn) { - if (yn) { - _mute_master->mute_at (_mute_points); - } else { - _mute_master->clear_mute (); - } - + if (self_muted() != yn) { + _mute_master->set_self_muted (yn); mute_changed (src); /* EMIT SIGNAL */ } } bool -Route::muted() const +Route::muted () const +{ + return self_muted() || muted_by_others(); +} + +bool +Route::self_muted() const +{ + return _mute_master->self_muted (); +} + +bool +Route::muted_by_others() const +{ + return _mute_master->muted_by_others (); +} + +void +Route::mod_muted_by_others (int delta) +{ + if (_solo_isolated) { + return; + } + + bool old = muted (); + _mute_master->mod_muted_by_others (delta); + if (old != muted()) { + mute_changed (this); + } +} + +void +Route::mod_path_muted_by_others (int32_t delta) { - return _mute_master->muted (); + if (delta < 0) { + if (_path_muted_by_others >= (uint32_t) abs (delta)) { + _path_muted_by_others += delta; + } else { + _path_muted_by_others = 0; + } + } else { + _path_muted_by_others += delta; + } } #if 0 @@ -808,6 +880,14 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } + /* is this the monitor send ? if so, make sure we keep track of it */ + + boost::shared_ptr isend = boost::dynamic_pointer_cast (processor); + + if (isend && _session.monitor_out() && (isend->target_id() == _session.monitor_out()->id())) { + _monitor_send = isend; + } + if (activation_allowed && (processor != _monitor_send)) { processor->activate (); } @@ -822,151 +902,6 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite 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; - - 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 if (prop->value() == "meter") { - - if (_meter) { - if (_meter->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - return true; - } - } - - _meter.reset (new PeakMeter (_session, node)); - _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; - } - } - - _monitor_control.reset (new MonitorProcessor (_session)); - _monitor_control->set_state (node, Stateful::loading_state_version); - processor = _monitor_control; - - } else if (prop->value() == "amp") { - - /* amp always exists */ - - processor = _amp; - if (processor->set_state (node, Stateful::loading_state_version)) { - return false; - } else { - /* never any reason to add it */ - return true; - } - - } else if (prop->value() == "intsend") { - - InternalSend* isend = new InternalSend (_session, _mute_master, node); - - if (_session.monitor_out() && (isend->target_id() == _session.monitor_out()->id())) { - _monitor_send.reset (isend); - if (_monitor_send->active()) { - _monitor_send->set_solo_level (1); - } else { - _monitor_send->set_solo_level (0); - } - } - - processor.reset (isend); - - } 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; - } - } - _intreturn.reset (new InternalReturn (_session, node)); - 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; - } - } - - _main_outs.reset (new Delivery (_session, _output, _mute_master, node)); - processor = _main_outs; - - } 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) { @@ -984,18 +919,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 { @@ -1003,6 +938,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; @@ -1503,7 +1442,6 @@ Route::configure_processors (ProcessorStreams* err) ChanCount Route::input_streams () const { - cerr << "!!!!!!!!!" << _name << " ::input_streams()\n"; return _input->n_ports (); } @@ -1520,9 +1458,6 @@ Route::configure_processors_unlocked (ProcessorStreams* err) _in_configure_processors = true; // Check each processor in order to see if we can configure as requested - if (_name == "auditioner") { - cerr << "AUD conf\n"; - } ChanCount in = input_streams (); ChanCount out; list< pair > configuration; @@ -1568,7 +1503,10 @@ 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 ()); + } _in_configure_processors = false; return 0; @@ -1729,7 +1667,9 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err } } - processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + if (true) { + processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + } return 0; } @@ -1790,8 +1730,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)); @@ -1857,6 +1799,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(); @@ -1889,9 +1835,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) { @@ -1913,7 +1864,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); } @@ -1997,11 +1949,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 */ @@ -2016,58 +1963,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())); } @@ -2084,6 +1980,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)); } @@ -2123,6 +2078,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){ @@ -2201,101 +2228,94 @@ 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::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(); + ProcessorList new_order; + bool must_configure = false; - 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 ()); } void @@ -2397,11 +2417,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 */ @@ -2426,8 +2441,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) { @@ -2492,7 +2505,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)); @@ -2530,6 +2589,12 @@ Route::feeds (boost::shared_ptr other, bool* only_send) return false; } +void +Route::check_physical_connections () +{ + _physically_connected = _output->physically_connected (); +} + void Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool can_flush_processors) { @@ -2647,7 +2712,7 @@ 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 @@ -2683,7 +2748,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; @@ -2741,7 +2806,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 */ @@ -2803,7 +2868,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); @@ -2989,7 +3054,7 @@ Route::MuteControllable::set_value (float val) float Route::MuteControllable::get_value (void) const { - return route.muted() ? 1.0f : 0.0f; + return route.self_muted() ? 1.0f : 0.0f; } void @@ -3142,8 +3207,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 (); } } @@ -3267,15 +3338,36 @@ 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; +} + +void +Route::set_graph_level (int32_t l) +{ + _graph_level = l; +}