some provisional support for "real" solo-isolate behaviour, subject to more discussions with mr. oofus and others

git-svn-id: svn://localhost/ardour2/branches/3.0@6145 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2009-11-21 17:20:57 +00:00
parent 78503905d7
commit 9fa51e19b6
9 changed files with 129 additions and 100 deletions

View File

@ -43,6 +43,7 @@
#include "ardour/route.h"
#include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
#include "i18n.h"
@ -82,27 +83,27 @@ EditorRoutes::EditorRoutes (Editor* e)
rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
// Mute enable toggle
CellRendererPixbufToggle* mute_col_renderer = manage (new CellRendererPixbufToggle());
CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
mute_col_renderer->set_active_pixbuf (::get_icon("mute-enabled"));
mute_col_renderer->set_inactive_pixbuf (::get_icon("act-disabled"));
mute_col_renderer->signal_toggled().connect (mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
mute_col_renderer->signal_changed().connect (mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
Gtk::TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
mute_state_column->add_attribute(mute_col_renderer->property_active(), _columns.mute_enabled);
mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
mute_state_column->add_attribute(mute_col_renderer->property_visible(), _columns.is_track);
// Solo enable toggle
CellRendererPixbufToggle* solo_col_renderer = manage (new CellRendererPixbufToggle());
CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
solo_col_renderer->set_active_pixbuf (::get_icon("solo-enabled"));
solo_col_renderer->set_inactive_pixbuf (::get_icon("act-disabled"));
solo_col_renderer->signal_toggled().connect (mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
solo_col_renderer->signal_changed().connect (mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
Gtk::TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
solo_state_column->add_attribute(solo_col_renderer->property_active(), _columns.solo_enabled);
solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.is_track);
@ -167,7 +168,6 @@ EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
}
}
void
EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
{
@ -182,8 +182,6 @@ EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
}
}
void
EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
{
@ -198,7 +196,6 @@ EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
}
}
void
EditorRoutes::build_menu ()
{
@ -914,9 +911,9 @@ EditorRoutes::update_mute_display (void* /*src*/)
if (boost::dynamic_pointer_cast<Track>(route)) {
if (route->muted()){
(*i)[_columns.mute_enabled] = true;
(*i)[_columns.mute_state] = 1;
} else {
(*i)[_columns.mute_enabled] = false;
(*i)[_columns.mute_state] = 0;
}
}
}
@ -934,9 +931,9 @@ EditorRoutes::update_solo_display (void* /*src*/)
if (boost::dynamic_pointer_cast<Track>(route)) {
if (route->soloed()){
(*i)[_columns.solo_enabled] = true;
(*i)[_columns.solo_state] = 1;
} else {
(*i)[_columns.solo_enabled] = false;
(*i)[_columns.solo_state] = 0;
}
}
}

View File

@ -89,8 +89,8 @@ private:
add (text);
add (visible);
add (rec_enabled);
add (mute_enabled);
add (solo_enabled);
add (mute_state);
add (solo_state);
add (is_track);
add (tv);
add (route);
@ -99,8 +99,8 @@ private:
Gtk::TreeModelColumn<Glib::ustring> text;
Gtk::TreeModelColumn<bool> visible;
Gtk::TreeModelColumn<bool> rec_enabled;
Gtk::TreeModelColumn<bool> mute_enabled;
Gtk::TreeModelColumn<bool> solo_enabled;
Gtk::TreeModelColumn<uint32_t> mute_state;
Gtk::TreeModelColumn<uint32_t> solo_state;
Gtk::TreeModelColumn<bool> is_track;
Gtk::TreeModelColumn<TimeAxisView*> tv;
Gtk::TreeModelColumn<boost::shared_ptr<ARDOUR::Route> > route;

View File

@ -737,16 +737,21 @@ RouteUI::update_mute_display ()
if (Config->get_show_solo_mutes()) {
if (_route->muted()) {
/* full mute */
mute_button->set_visual_state (2);
} else if (!_route->soloed() && _session.soloing()) {
} else if (_session.soloing() && !_route->soloed() && !_route->solo_isolated()) {
/* mute-because-not-soloed */
mute_button->set_visual_state (1);
} else {
/* no mute at all */
mute_button->set_visual_state (0);
}
} else {
if (_route->muted()) {
/* full mute */
mute_button->set_visual_state (2);
} else {
/* no mute at all */
mute_button->set_visual_state (0);
}
}

View File

@ -129,8 +129,11 @@ class Route : public SessionObject, public AutomatableControls
*/
void set_solo (bool yn, void *src);
bool soloed () const { return (bool) _solo_level; }
bool soloed_by_others () const { return !_solo_isolated && _soloed_by_others; }
bool self_soloed () const { return _self_solo; }
bool soloed () const {return self_soloed () || soloed_by_others (); }
void set_solo_isolated (bool yn, void *src);
bool solo_isolated() const;
@ -310,8 +313,7 @@ class Route : public SessionObject, public AutomatableControls
friend class Session;
void catch_up_on_solo_mute_override ();
void mod_solo_level (int32_t);
uint32_t solo_level () const { return _solo_level; }
void mod_solo_by_others (int32_t);
void set_block_size (nframes_t nframes);
bool has_external_redirects() const;
void curve_reallocate ();
@ -347,7 +349,8 @@ class Route : public SessionObject, public AutomatableControls
int _pending_declick;
MeterPoint _meter_point;
uint32_t _phase_invert;
uint32_t _solo_level;
bool _self_solo;
uint32_t _soloed_by_others;
bool _solo_isolated;
bool _denormal_protection;
@ -411,6 +414,9 @@ class Route : public SessionObject, public AutomatableControls
bool add_processor_from_xml_2X (const XMLNode&, int, ProcessorList::iterator iter);
void placement_range (Placement p, ProcessorList::iterator& start, ProcessorList::iterator& end);
void set_self_solo (bool yn);
void set_delivery_solo ();
};
} // namespace ARDOUR

View File

@ -529,6 +529,7 @@ Delivery::target_gain ()
gain_t desired_gain;
if (_solo_level) {
desired_gain = 1.0;
} else {
@ -549,18 +550,12 @@ Delivery::target_gain ()
mp = MuteMaster::PreFader;
break;
}
if (_solo_isolated) {
/* ... but we are isolated from all that nonsense */
desired_gain = _mute_master->mute_gain_at (mp);
} else if (_session.soloing()) {
if (!_solo_isolated && _session.soloing()) {
desired_gain = min (Config->get_solo_mute_gain(), _mute_master->mute_gain_at (mp));
} else {
desired_gain = _mute_master->mute_gain_at (mp);
}

View File

@ -133,7 +133,6 @@ IOProcessor::state (bool full_state)
node.add_property ("own-output", "yes");
if (_output) {
XMLNode& o (_output->state (full_state));
// o.name() = X_("output");
node.add_child_nocopy (o);
}
} else {
@ -166,12 +165,21 @@ IOProcessor::set_state (const XMLNode& node, int version)
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
const string instr = enum_2_string (IO::Input);
const string outstr = enum_2_string (IO::Output);
if (_own_input) {
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == "input") {
io_node = (*niter);
break;
const XMLProperty* prop;
if ((prop = (*niter)->property ("name")) != 0) {
if (prop->value() == _name) {
if ((prop = (*niter)->property ("direction")) != 0) {
if (prop->value() == instr) {
io_node = (*niter);
break;
}
}
}
}
}
@ -184,16 +192,25 @@ IOProcessor::set_state (const XMLNode& node, int version)
}
} else {
/* no input */
/* no input, which is OK */
}
}
if (_own_output) {
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
if ((*niter)->name() == "output") {
io_node = (*niter);
break;
if ((*niter)->name() == "IO") {
const XMLProperty* prop;
if ((prop = (*niter)->property ("name")) != 0) {
if (prop->value() == _name) {
if ((prop = (*niter)->property ("direction")) != 0) {
if (prop->value() == outstr) {
io_node = (*niter);
break;
}
}
}
}
}
}
@ -205,7 +222,7 @@ IOProcessor::set_state (const XMLNode& node, int version)
set_name (_output->name());
}
} else {
/* no output */
/* no output, which is OK */
}
}

View File

@ -116,11 +116,12 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type)
void
Route::init ()
{
_solo_level = 0;
_self_solo = false;
_soloed_by_others = 0;
_solo_isolated = false;
_solo_safe = false;
_active = true;
processor_max_streams.reset();
_solo_safe = false;
_recordable = true;
order_keys[N_("signal")] = order_key_cnt++;
_silent = false;
@ -523,7 +524,7 @@ Route::listening () const
void
Route::set_solo (bool yn, void *src)
{
if (_solo_safe || _solo_isolated) {
if (_solo_safe) {
return;
}
@ -532,40 +533,51 @@ Route::set_solo (bool yn, void *src)
return;
}
if (soloed() != yn) {
mod_solo_level (yn ? 1 : -1);
if (self_soloed() != yn) {
set_self_solo (yn);
set_delivery_solo ();
solo_changed (src); /* EMIT SIGNAL */
_solo_control->Changed (); /* EMIT SIGNAL */
}
}
void
Route::mod_solo_level (int32_t delta)
Route::set_self_solo (bool yn)
{
_self_solo = yn;
}
void
Route::mod_solo_by_others (int32_t delta)
{
if (delta < 0) {
if (_solo_level >= (uint32_t) delta) {
_solo_level += delta;
if (_soloed_by_others >= (uint32_t) delta) {
_soloed_by_others += delta;
} else {
_solo_level = 0;
_soloed_by_others = 0;
}
} else {
_solo_level += delta;
_soloed_by_others += 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.
*/
Glib::RWLock::ReaderLock rm (_processor_lock);
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<Delivery> d;
set_delivery_solo ();
}
if ((d = boost::dynamic_pointer_cast<Delivery> (*i)) != 0) {
d->set_solo_level (_solo_level);
d->set_solo_isolated (_solo_isolated);
}
void
Route::set_delivery_solo ()
{
/* 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.
*/
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());
}
}
}
@ -580,13 +592,7 @@ Route::set_solo_isolated (bool yn, void *src)
if (yn != _solo_isolated) {
_solo_isolated = yn;
/* tell main outs what the solo situation is
*/
_main_outs->set_solo_level (_solo_level);
_main_outs->set_solo_isolated (_solo_isolated);
set_delivery_solo ();
solo_isolated_changed (src);
}
}
@ -1679,6 +1685,9 @@ Route::state(bool full_state)
order_string += ':';
}
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);
node->add_child_nocopy (_input->state (full_state));
node->add_child_nocopy (_output->state (full_state));
@ -1772,9 +1781,13 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
set_processor_state (processor_state);
if ((prop = node.property ("solo_level")) != 0) {
_solo_level = 0; // needed for mod_solo_level() to work
mod_solo_level (atoi (prop->value()));
if ((prop = node.property ("self-solo")) != 0) {
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 ("solo-isolated")) != 0) {
@ -1795,14 +1808,6 @@ Route::_set_state (const XMLNode& node, int version, bool /*call_base*/)
set_active (yn);
}
if ((prop = node.property (X_("soloed"))) != 0) {
bool yn = string_is_affirmative (prop->value());
/* XXX force reset of solo status */
set_solo (yn, this);
}
if ((prop = node.property (X_("meter-point"))) != 0) {
_meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
if (_meter) {
@ -2830,7 +2835,7 @@ Route::SoloControllable::set_value (float val)
float
Route::SoloControllable::get_value (void) const
{
return route.soloed() ? 1.0f : 0.0f;
return route.self_soloed() ? 1.0f : 0.0f;
}
void

View File

@ -2426,7 +2426,7 @@ Session::route_solo_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
shared_ptr<RouteList> r = routes.reader ();
int32_t delta;
if (route->soloed()) {
if (route->self_soloed()) {
delta = 1;
} else {
delta = -1;
@ -2437,27 +2437,30 @@ Session::route_solo_changed (void* /*src*/, boost::weak_ptr<Route> wpr)
*/
solo_update_disabled = true;
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
bool via_sends_only;
if ((*i)->feeds (route, &via_sends_only) && !(*i)->is_hidden() && !(*i)->is_master() && !(*i)->is_control()) {
if ((*i) == route || !(*i)->solo_isolated() || !(*i)->is_master() || !(*i)->is_control() || (*i)->is_hidden()) {
continue;
} else if ((*i)->feeds (route, &via_sends_only)) {
if (!via_sends_only) {
/* do it */
(*i)->mod_solo_level (delta);
}
}
(*i)->mod_solo_by_others (delta);
}
}
}
/* make sure master is never muted by solo */
if (_master_out && route != _master_out && _master_out->solo_level() == 0 && !_master_out->soloed()) {
_master_out->mod_solo_level (1);
}
if (_master_out && route != _master_out && _master_out->soloed_by_others() == 0 && !_master_out->soloed()) {
_master_out->mod_solo_by_others (1);
}
/* ditto for control outs make sure master is never muted by solo */
if (_control_out && route != _control_out && _control_out && _control_out->solo_level() == 0) {
_control_out->mod_solo_level (1);
if (_control_out && route != _control_out && _control_out && _control_out->soloed_by_others() == 0) {
_control_out->mod_solo_by_others (1);
}
solo_update_disabled = false;
@ -2478,7 +2481,7 @@ Session::update_route_solo_state (boost::shared_ptr<RouteList> r)
}
for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
if (!(*i)->is_master() && !(*i)->is_control() && !(*i)->is_hidden() && (*i)->soloed()) {
if (!(*i)->is_master() && !(*i)->is_control() && !(*i)->is_hidden() && (*i)->self_soloed()) {
something_soloed = true;
break;
}

View File

@ -22,6 +22,7 @@ gtkmm2ext_sources = [
'auto_spin.cc',
'barcontroller.cc',
'binding_proxy.cc',
'cell_renderer_pixbuf_multi.cc',
'cell_renderer_pixbuf_toggle.cc',
'choice.cc',
'click_box.cc',