#endif
#include <cmath>
-#include <fstream>
#include <cassert>
#include <algorithm>
on a transition between monitoring states we get a de-clicking gain
change in the _main_outs delivery, if config.get_use_monitor_fades()
is true.
-
+
We override this in the case where we have an internal generator.
*/
bool silence = _have_internal_generator ? false : (monitoring_state () == MonitoringSilence);
-
+
_main_outs->no_outs_cuz_we_no_monitor (silence);
/* -------------------------------------------------------------------------------------------
if (yn != _monitor_send->active()) {
if (yn) {
_monitor_send->activate ();
- _mute_master->set_soloed (true);
+ _mute_master->set_soloed_by_self (true);
} else {
_monitor_send->deactivate ();
- _mute_master->set_soloed (false);
+ _mute_master->set_soloed_by_self (false);
}
+ _mute_master->set_soloed_by_others (false);
listen_changed (src); /* EMIT SIGNAL */
}
void
Route::mod_solo_by_others_upstream (int32_t delta)
{
- if (_solo_safe) {
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-upstream due to solo-safe\n", name()));
- return;
- }
-
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-upstream by %2, current up = %3 down = %4\n",
name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
(old_sbu > 0 && _soloed_by_others_upstream == 0))) {
if (delta > 0 || !Config->get_exclusive_solo()) {
- DEBUG_TRACE (DEBUG::Solo, "\t ... INVERT push\n");
+ DEBUG_TRACE (DEBUG::Solo, string_compose("\t ... INVERT push from %1\n", _name));
for (FedBy::iterator i = _fed_by.begin(); i != _fed_by.end(); ++i) {
+ if (i->sends_only) {
+ continue;
+ }
boost::shared_ptr<Route> sr = i->r.lock();
if (sr) {
sr->mod_solo_by_others_downstream (-delta);
void
Route::mod_solo_by_others_downstream (int32_t delta)
{
- if (_solo_safe) {
- DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 ignore solo-by-downstream due to solo safe\n", name()));
- return;
- }
-
DEBUG_TRACE (DEBUG::Solo, string_compose ("%1 mod solo-by-downstream by %2, current up = %3 down = %4\n",
name(), delta, _soloed_by_others_upstream, _soloed_by_others_downstream));
void
Route::set_mute_master_solo ()
{
- _mute_master->set_soloed (self_soloed() || soloed_by_others_downstream() || soloed_by_others_upstream());
+ _mute_master->set_soloed_by_self (self_soloed());
+ _mute_master->set_soloed_by_others (soloed_by_others_downstream() || soloed_by_others_upstream());
}
void
}
}
-
+
if (!changed) {
return;
}
-
+
/* forward propagate solo-isolate status to everything fed by this route, but not those via sends only */
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_auditioner()) {
continue;
}
-
+
bool sends_only;
bool does_feed = feeds (*i, &sends_only);
-
+
if (does_feed && !sends_only) {
(*i)->mod_solo_isolated_by_upstream (yn, src);
}
}
-
+
/* XXX should we back-propagate as well? (April 2010: myself and chris goddard think not) */
solo_isolated_changed (src);
bool
Route::muted_by_others () const
{
+ // This method is only used by route_ui for display state.
+ // The real thing is MuteMaster::muted_by_others_at()
+
//master is never muted by others
if (is_master())
return false;
-
+
//now check to see if something is soloed (and I am not)
- return (_session.soloing() && !self_soloed() && !solo_isolated());
+ //see also MuteMaster::mute_gain_at()
+ return (_session.soloing() && !soloed() && !solo_isolated());
}
#if 0
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
ProcessorList::iterator loc;
-
+
if (p == PreFader) {
/* generic pre-fader: insert immediately before the amp */
loc = find (_processors.begin(), _processors.end(), _amp);
}
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
-
+
ProcessorList::iterator i = _processors.begin ();
int j = 0;
while (i != _processors.end() && j < index) {
if ((*i)->display_to_user()) {
++j;
}
-
+
++i;
}
if (processor->set_state (node, version)) {
return false;
}
-
+
//A2 uses the "active" flag in the toplevel redirect node, not in the child plugin/IO
if (i != children.end()) {
if ((prop = (*i)->property (X_("active"))) != 0) {
if (_processors.empty()) {
return;
}
-
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
if (!(*i)->display_to_user() || boost::dynamic_pointer_cast<Amp> (*i)) {
continue;
}
-
+
if (state) {
(*i)->activate ();
} else {
again:
for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
-
+
boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
-
+
if (d && d->target_route() == route) {
rl.release ();
if (remove_processor (*x, &err, false) > 0) {
} else {
cancel_solo_after_disconnect (true);
}
+#if 1
+ } else if (_soloed_by_others_upstream) {
+ bool cancel_solo = true;
+ 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_auditioner()) {
+ continue;
+ }
+ bool sends_only;
+ bool does_feed = (*i)->direct_feeds_according_to_reality (shared_from_this(), &sends_only);
+ if (does_feed && !sends_only) {
+ if ((*i)->soloed()) {
+ cancel_solo = false;
+ break;
+ }
+ }
+ }
+ if (cancel_solo) {
+ cancel_solo_after_disconnect (true);
+ }
+#else
+ } else if (self_soloed()) {
+#endif
+ // TODO propagate upstream
+ // see commment in output_change_handler() below
}
}
} else {
cancel_solo_after_disconnect (false);
}
+#if 1
+ } else if (_soloed_by_others_downstream) {
+ bool cancel_solo = true;
+ /* checking all all downstream routes for
+ * explicit of implict solo is a rather drastic measure,
+ * ideally the input_change_handler() of the other route
+ * would propagate the change to us.
+ */
+ boost::shared_ptr<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_auditioner()) {
+ continue;
+ }
+ bool sends_only;
+ bool does_feed = direct_feeds_according_to_reality (*i, &sends_only);
+ if (does_feed && !sends_only) {
+ if ((*i)->soloed()) {
+ cancel_solo = false;
+ break;
+ }
+ }
+ }
+ if (cancel_solo) {
+ cancel_solo_after_disconnect (false);
+ }
+#else
+ } else if (self_soloed()) {
+ // TODO propagate change downstream to the disconnected routes
+ // Q: how to get the routes that were just disconnected. ?
+ // A: /maybe/ by diff feeds() aka fed_by() vs direct_feeds_according_to_reality() ?!?
+#endif
}
}
/* Set up the meter for its new position */
ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter);
-
+
ChanCount m_in;
-
+
if (loc == _processors.begin()) {
m_in = _input->n_ports();
} else {
XMLNodeList children = node.children();
for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
-
+
if ((*i)->name() == X_("IO")) {
IO::set_name_in_state (**i, name);
if (role && role->value() == X_("Main")) {
(*i)->add_property (X_("name"), name);
}
-
+
} else if ((*i)->name() == X_("Diskstream")) {
(*i)->add_property (X_("playlist"), string_compose ("%1.1", name).c_str());
(*i)->add_property (X_("name"), name);
-
+
}
}
}
} else {
all_connections.min = ~((pframes_t) 0);
all_connections.max = 0;
-
+
/* iterate over all "from" ports and determine the latency range for all of their
connections to the "outside" (outside of this Route).
*/
-
+
for (PortSet::iterator p = from.begin(); p != from.end(); ++p) {
-
+
LatencyRange range;
-
+
p->get_connected_latency_range (range, playback);
-
+
all_connections.min = min (all_connections.min, range.min);
all_connections.max = max (all_connections.max, range.max);
}
if (_meter_point != MeterCustom) {
return;
}
-
+
_custom_meter_position_noted = true;
/* custom meter points range from after trim to before panner/main_outs
* this is a limitation by the current processor UI
/* ignore inactive processors and obviously ignore the main
* outs since everything has them and we don't care.
*/
-
+
if ((*i)->active() && (*i) != _main_outs && (*i)->does_routing()) {
return true;;
}
{
//Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
-
+
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
(*i)->transport_located (pos);
}
{
size_t n_buffers;
size_t i;
-
+
/* MIDI
*
* We don't currently mix MIDI input together, so we don't need the
boost::shared_ptr<MidiPort> source_port = io->midi (i);
MidiBuffer& buf (bufs.get_midi (i));
-
+
if (source_port) {
buf.copy (source_port->get_midi_buffer(nframes));
} else {
if (n_ports > n_buffers) {
scaling = ((float) n_buffers) / n_ports;
}
-
+
for (i = 0; i < n_ports; ++i) {
-
+
/* if there are more ports than buffers, map them onto buffers
* in a round-robin fashion
*/
boost::shared_ptr<AudioPort> source_port = io->audio (i);
AudioBuffer& buf (bufs.get_audio (i%n_buffers));
-
+
if (i < n_buffers) {
-
+
/* first time through just copy a channel into
the output buffer.
*/
if (scaling != 1.0f) {
buf.apply_gain (scaling, nframes);
}
-
+
} else {
-
+
/* on subsequent times around, merge data from
* the port with what is already there
*/