, _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)
, _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)
/* 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 */
_main_outs->panner()->set_bypassed (true);
}
- markup_solo_ignore ();
+ if (is_master() || is_monitor() || is_hidden()) {
+ _mute_master->set_solo_ignore (true);
+ }
/* now that we have _meter, its safe to connect to this */
Glib::RWLock::ReaderLock rm (_processor_lock, Glib::TRY_LOCK);
if (rm.locked()) {
+ //cerr << name() << " upstream solo " << _soloed_by_others_upstream
+ // << " downstream solo " << _soloed_by_others_downstream
+ // << " self " << _self_solo
+ //<< endl;
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (bufs.count() != (*i)->input_streams()) {
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 */
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 */
}
}
}
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<Route> sr = i->r.lock();
+ if (sr) {
+ sr->mod_solo_by_others_downstream (-delta);
+ }
+ }
+ }
+ }
- set_delivery_solo ();
- solo_changed (this);
+ 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<Delivery> d;
-
- if ((d = boost::dynamic_pointer_cast<Delivery> (*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
boost::shared_ptr<RouteList> 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());
}
}
- /* XXX should we back-propagate as well? */
+ /* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
- bool changed = false;
+ 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
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()) {
+ mute_changed (this); /* EMIT SIGNAL */
+ }
}
void
}
if (muted() != yn) {
- if (yn) {
- _mute_master->mute_at (_mute_points);
- } else {
- _mute_master->clear_mute ();
- }
-
+ _mute_master->set_muted (yn);
mute_changed (src); /* EMIT SIGNAL */
}
}
bool
-Route::muted() const
+Route::muted () const
{
- return _mute_master->muted ();
+ return _mute_master->muted();
}
#if 0
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)) {
}
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ set_processor_positions ();
return 0;
}
}
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ set_processor_positions ();
return 0;
}
processor_max_streams.reset();
_have_internal_generator = false;
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ set_processor_positions ();
if (!already_deleting) {
_session.clear_deletion_in_progress();
processor->drop_references ();
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ set_processor_positions ();
return 0;
}
}
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ set_processor_positions ();
return 0;
}
if (true) {
processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
+ set_processor_positions ();
}
return 0;
}
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));
_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();
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) {
bool first = true;
bool muted = string_is_affirmative (prop->value());
- if(muted){
+ if (muted){
string mute_point;
}
}
- _mute_master->set_state (mute_point);
+ _mute_master->set_mute_points (mute_point);
}
}
}
}
- markup_solo_ignore ();
-
processors_changed (RouteProcessorChange ());
-}
-
-void
-Route::markup_solo_ignore ()
-{
- Glib::RWLock::ReaderLock lm (_processor_lock);
-
- for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p) {
-
- /* all delivery processors on master, monitor and auditioner never ever pay attention to solo
- */
-
- boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery>(*p);
-
- if (d && (is_master() || is_monitor() || is_hidden())) {
- cerr << _name << " Found a delivery unit, mark solo ignored\n";
- d->set_solo_ignored (true);
- }
- }
+ set_processor_positions ();
}
void
if (route == _session.monitor_out()) {
_monitor_send = boost::dynamic_pointer_cast<Delivery>(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 */
}
bool
-Route::feeds (boost::shared_ptr<Route> other, bool* only_send)
+Route::add_fed_by (boost::shared_ptr<Route> other, bool via_sends_only)
+{
+ FeedRecord fr (other, via_sends_only);
+
+ pair<FedBy::iterator,bool> 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<FeedRecord*>(&(*result.first));
+ frp->sends_only = false;
+ }
+ }
+
+ return result.second;
+}
+
+void
+Route::clear_fed_by ()
+{
+ _fed_by.clear ();
+}
+
+bool
+Route::feeds (boost::shared_ptr<Route> 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<Route> 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<Route> other, bool* only_send)
{
DEBUG_TRACE (DEBUG::Graph, string_compose ("Feeds? %1\n", _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<Amp> (*i)) {
+ had_amp = true;
+ }
+ }
+}