X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Froute.cc;h=4dcdcf1898a621d4a2018c08386e1565a4a82f24;hb=932d6c79d01be93f491415ef1491bca17d92671f;hp=89dbf3fcd27138806526d1faa1c544097bbf18cf;hpb=6dac4da98344ed8ce609a4e7d567ef2f9fbb9b31;p=ardour.git diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 89dbf3fcd2..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,7 +123,7 @@ Route::init () /* add amp processor */ - _amp.reset (new Amp (_session, _mute_master)); + _amp.reset (new Amp (_session)); add_processor (_amp, PostFader); /* add standard processors: meter, main outs, monitor out */ @@ -161,6 +163,10 @@ Route::init () _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))); @@ -268,7 +274,7 @@ Route::ensure_track_or_route_name(string name, Session &session) string newname = name; while (!session.io_name_is_legal (newname)) { - newname = bump_name_once (newname); + newname = bump_name_once (newname, '.'); } return newname; @@ -444,21 +450,17 @@ Route::process_output_buffers (BufferSet& bufs, and go .... ----------------------------------------------------------------------------------------- */ - Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK); - - if (rm.locked()) { - for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) { - - 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()); + 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()); } } @@ -478,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()); @@ -528,8 +530,10 @@ Route::set_listen (bool yn, void* src) if (yn != _monitor_send->active()) { if (yn) { _monitor_send->activate (); - } else { + _mute_master->set_soloed (true); + } else { _monitor_send->deactivate (); + _mute_master->set_soloed (false); } listen_changed (src); /* EMIT SIGNAL */ @@ -589,40 +593,87 @@ Route::set_self_solo (bool 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) abs (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_mute_master_solo (); solo_changed (false, this); } void -Route::set_mute_master_solo () +Route::mod_solo_by_others_downstream (int32_t delta) { - int32_t level; - - if (self_soloed()) { - level = 2; - } else if (soloed_by_others()) { - level = 1; - } else { - level = 0; + if (_solo_safe) { + return; } - _mute_master->set_solo_level (level); + 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 @@ -656,15 +707,27 @@ Route::set_solo_isolated (bool yn, void *src) /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */ + bool changed = false; + if (yn) { + if (_solo_isolated == 0) { + _mute_master->set_solo_ignore (true); + changed = true; + } _solo_isolated++; - _mute_master->clear_muted_by_others (); } else { if (_solo_isolated > 0) { _solo_isolated--; + if (_solo_isolated == 0) { + _mute_master->set_solo_ignore (false); + changed = true; + } } } + if (changed) { + solo_isolated_changed (src); + } } bool @@ -676,11 +739,10 @@ Route::solo_isolated () const void Route::set_mute_points (MuteMaster::MutePoint mp) { - _mute_points = mp; - _mute_master->set_mute_points (MuteMaster::AllPoints); + _mute_master->set_mute_points (mp); mute_points_changed (); /* EMIT SIGNAL */ - if (_mute_master->muted()) { + if (_mute_master->muted_by_self()) { mute_changed (this); /* EMIT SIGNAL */ } } @@ -693,8 +755,8 @@ Route::set_mute (bool yn, void *src) return; } - if (self_muted() != yn) { - _mute_master->set_self_muted (yn); + if (muted() != yn) { + _mute_master->set_muted_by_self (yn); mute_changed (src); /* EMIT SIGNAL */ } } @@ -702,35 +764,7 @@ Route::set_mute (bool yn, void *src) bool 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) -{ - bool old = muted (); - - if (_solo_isolated) { - return; - } - - _mute_master->mod_muted_by_others (delta); - - if (old != muted()) { - mute_changed (this); - } + return _mute_master->muted_by_self(); } #if 0 @@ -849,6 +883,7 @@ Route::add_processor (boost::shared_ptr processor, ProcessorList::ite } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -993,6 +1028,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1193,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(); @@ -1284,6 +1321,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream processor->drop_references (); processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1375,6 +1413,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* } processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); return 0; } @@ -1415,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 { @@ -1459,6 +1496,8 @@ Route::configure_processors_unlocked (ProcessorStreams* err) _session.ensure_buffers (n_process_buffers ()); } + DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name)); + _in_configure_processors = false; return 0; } @@ -1620,6 +1659,7 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err if (true) { processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */ + set_processor_positions (); } return 0; @@ -1681,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)); @@ -1748,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(); @@ -1780,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) { @@ -2256,6 +2307,7 @@ Route::set_processor_state (const XMLNode& node) } processors_changed (RouteProcessorChange ()); + set_processor_positions (); } void @@ -2268,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; } - } } @@ -2588,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) { @@ -2603,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 @@ -2623,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. @@ -2648,22 +2711,19 @@ int Route::roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick, 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; } @@ -2988,7 +3048,7 @@ Route::MuteControllable::set_value (float val) float Route::MuteControllable::get_value (void) const { - return route.self_muted() ? 1.0f : 0.0f; + return route.muted() ? 1.0f : 0.0f; } void @@ -3299,3 +3359,23 @@ Route::has_io_processor_named (const string& name) 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; + } + } +}