a variety of changes that get closer to correctly functioning behaviour for VCA solo+mute (BUT ARE NOT DONE YET)
This commit is contained in:
parent
7d493b091a
commit
6de4953be8
@ -415,7 +415,7 @@ RouteUI::mute_press (GdkEventButton* ev)
|
||||
}
|
||||
|
||||
DisplaySuspender ds;
|
||||
_session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
_session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
|
||||
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
|
||||
|
||||
@ -444,7 +444,7 @@ RouteUI::mute_press (GdkEventButton* ev)
|
||||
}
|
||||
|
||||
DisplaySuspender ds;
|
||||
_session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted() ? 0.0 : 1.0, Controllable::InverseGroup);
|
||||
_session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
|
||||
}
|
||||
|
||||
} else {
|
||||
@ -458,7 +458,7 @@ RouteUI::mute_press (GdkEventButton* ev)
|
||||
_mute_release->routes = rl;
|
||||
}
|
||||
|
||||
_session->set_control (_route->mute_control(), _route->muted() ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
_session->set_control (_route->mute_control(), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
|
||||
|
||||
}
|
||||
}
|
||||
@ -1225,10 +1225,12 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
|
||||
|
||||
if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
|
||||
|
||||
if (r->muted ()) {
|
||||
std::cerr << r->name() << " self " << r->mute_control()->muted_by_self() << " others " << r->muted_by_others() << " soloing " << r->muted_by_others_soloing() << std::endl;
|
||||
|
||||
if (r->mute_control()->muted_by_self ()) {
|
||||
/* full mute */
|
||||
return Gtkmm2ext::ExplicitActive;
|
||||
} else if (r->muted_by_others_soloing () || r->mute_control()->get_masters_value()) {
|
||||
} else if (r->muted_by_others_soloing () || r->muted_by_others()) {
|
||||
/* this will reflect both solo mutes AND master mutes */
|
||||
return Gtkmm2ext::ImplicitActive;
|
||||
} else {
|
||||
@ -1238,15 +1240,11 @@ RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
|
||||
|
||||
} else {
|
||||
|
||||
if (r->muted()) {
|
||||
if (r->mute_control()->muted_by_self()) {
|
||||
/* full mute */
|
||||
return Gtkmm2ext::ExplicitActive;
|
||||
} else if (r->muted_by_others()) {
|
||||
/* note the direct use of MuteMaster API here. We are
|
||||
not interested in showing
|
||||
others-soloed-so-this-muted status in this
|
||||
conditional branch.
|
||||
*/
|
||||
/* this shows only master mutes, not mute-by-others-soloing */
|
||||
return Gtkmm2ext::ImplicitActive;
|
||||
} else {
|
||||
/* no mute at all */
|
||||
|
@ -131,6 +131,8 @@ VCAMasterStrip::VCAMasterStrip (Session* s, boost::shared_ptr<VCA> v)
|
||||
_vca->solo_control()->Changed.connect (vca_connections, invalidator (*this), boost::bind (&VCAMasterStrip::solo_changed, this), gui_context());
|
||||
_vca->mute_control()->Changed.connect (vca_connections, invalidator (*this), boost::bind (&VCAMasterStrip::mute_changed, this), gui_context());
|
||||
|
||||
/* only need to connect to one of these to update VCA status */
|
||||
|
||||
_vca->gain_control()->MasterStatusChange.connect (vca_connections,
|
||||
invalidator (*this),
|
||||
boost::bind (&VCAMasterStrip::update_vca_display, this),
|
||||
@ -198,14 +200,20 @@ VCAMasterStrip::set_selected (bool yn)
|
||||
bool
|
||||
VCAMasterStrip::solo_release (GdkEventButton*)
|
||||
{
|
||||
_vca->solo_control()->set_value (_vca->solo_control()->get_value() ? 0.0 : 1.0, Controllable::NoGroup);
|
||||
/* We use NoGroup because VCA controls are never part of a group. This
|
||||
is redundant, but clear.
|
||||
*/
|
||||
_vca->solo_control()->set_value (_vca->solo_control()->self_soloed() ? 0.0 : 1.0, Controllable::NoGroup);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
VCAMasterStrip::mute_release (GdkEventButton*)
|
||||
{
|
||||
_vca->mute_control()->set_value (_vca->mute_control()->get_value() ? 0.0 : 1.0, Controllable::NoGroup);
|
||||
/* We use NoGroup because VCA controls are never part of a group. This
|
||||
is redundant, but clear.
|
||||
*/
|
||||
_vca->mute_control()->set_value (_vca->mute_control()->muted_by_self() ? 0.0 : 1.0, Controllable::NoGroup);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -229,8 +237,11 @@ VCAMasterStrip::set_solo_text ()
|
||||
void
|
||||
VCAMasterStrip::mute_changed ()
|
||||
{
|
||||
if (_vca->mute_control()->muted()) {
|
||||
std::cerr << "Mute changed for " << _vca->number() << std::endl;
|
||||
if (_vca->mute_control()->muted_by_self()) {
|
||||
mute_button.set_active_state (ExplicitActive);
|
||||
} else if (_vca->mute_control()->muted_by_others()) {
|
||||
mute_button.set_active_state (ImplicitActive);
|
||||
} else {
|
||||
mute_button.set_active_state (Gtkmm2ext::Off);
|
||||
}
|
||||
@ -239,7 +250,7 @@ VCAMasterStrip::mute_changed ()
|
||||
void
|
||||
VCAMasterStrip::solo_changed ()
|
||||
{
|
||||
if (_vca->solo_control()->soloed()) {
|
||||
if (_vca->solo_control()->soloed() || _vca->solo_control()->get_masters_value()) {
|
||||
solo_button.set_active_state (ExplicitActive);
|
||||
} else {
|
||||
solo_button.set_active_state (Gtkmm2ext::Off);
|
||||
@ -257,10 +268,14 @@ VCAMasterStrip::vca_menu_toggle (CheckMenuItem* menuitem, uint32_t n)
|
||||
vca_unassign ();
|
||||
} else {
|
||||
_vca->gain_control()->remove_master (vca->gain_control());
|
||||
_vca->solo_control()->remove_master (vca->solo_control());
|
||||
_vca->mute_control()->remove_master (vca->mute_control());
|
||||
}
|
||||
} else {
|
||||
if (vca) {
|
||||
_vca->gain_control()->add_master (vca->gain_control());
|
||||
_vca->mute_control()->add_master (vca->mute_control());
|
||||
_vca->solo_control()->add_master (vca->solo_control());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -269,6 +284,8 @@ void
|
||||
VCAMasterStrip::vca_unassign ()
|
||||
{
|
||||
_vca->gain_control()->clear_masters ();
|
||||
_vca->solo_control()->clear_masters ();
|
||||
_vca->mute_control()->clear_masters ();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -152,8 +152,6 @@ class SlavableAutomationControl : public AutomationControl
|
||||
boost::shared_ptr<ARDOUR::AutomationList> l=boost::shared_ptr<ARDOUR::AutomationList>(),
|
||||
const std::string& name="");
|
||||
|
||||
~SlavableAutomationControl ();
|
||||
|
||||
double get_value () const;
|
||||
|
||||
void add_master (boost::shared_ptr<AutomationControl>);
|
||||
@ -200,7 +198,7 @@ class SlavableAutomationControl : public AutomationControl
|
||||
virtual void recompute_masters_ratios (double val) { /* do nothing by default */}
|
||||
virtual double get_masters_value_locked () const;
|
||||
double get_value_locked() const;
|
||||
|
||||
void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
|
||||
};
|
||||
|
||||
|
||||
|
@ -59,8 +59,6 @@ class LIBARDOUR_API GainControl : public SlavableAutomationControl {
|
||||
|
||||
void vcas_loaded();
|
||||
void recompute_masters_ratios (double val);
|
||||
|
||||
void actually_set_value (double val, PBD::Controllable::GroupControlDisposition group_override);
|
||||
};
|
||||
|
||||
} /* namespace */
|
||||
|
@ -53,6 +53,7 @@ class LIBARDOUR_API MuteControl : public SlavableAutomationControl
|
||||
*/
|
||||
|
||||
bool muted () const;
|
||||
bool muted_by_self () const;
|
||||
|
||||
bool muted_by_others_soloing () const;
|
||||
bool muted_by_others () const;
|
||||
@ -61,6 +62,7 @@ class LIBARDOUR_API MuteControl : public SlavableAutomationControl
|
||||
MuteMaster::MutePoint mute_points () const;
|
||||
|
||||
protected:
|
||||
void master_changed (bool, PBD::Controllable::GroupControlDisposition);
|
||||
void actually_set_value (double, PBD::Controllable::GroupControlDisposition group_override);
|
||||
|
||||
private:
|
||||
|
@ -70,7 +70,7 @@ class LIBARDOUR_API MuteMaster : public SessionHandleRef, public PBD::Stateful
|
||||
void set_solo_ignore (bool yn) { _solo_ignore = yn; }
|
||||
|
||||
void mod_muted_by_others (int32_t delta);
|
||||
bool muted_by_others () const { return _muted_by_others; }
|
||||
int32_t muted_by_others () const { return _muted_by_others; }
|
||||
|
||||
PBD::Signal0<void> MutePointChanged;
|
||||
|
||||
|
@ -460,8 +460,9 @@ public:
|
||||
|
||||
bool can_be_muted_by_others () const { return !is_master(); }
|
||||
bool muted () const { return _mute_control->muted(); }
|
||||
bool muted_by_others () const { return _mute_control->muted_by_others(); }
|
||||
bool muted_by_self () const { return _mute_control->muted_by_self(); }
|
||||
bool muted_by_others_soloing () const;
|
||||
bool muted_by_others () const;
|
||||
|
||||
boost::shared_ptr<SoloIsolateControl> solo_isolate_control() const {
|
||||
return _solo_isolate_control;
|
||||
|
@ -43,28 +43,6 @@ GainControl::GainControl (Session& session, const Evoral::Parameter ¶m, boos
|
||||
range_db = accurate_coefficient_to_dB (_desc.upper) - lower_db;
|
||||
}
|
||||
|
||||
void
|
||||
GainControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
|
||||
{
|
||||
val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
|
||||
|
||||
{
|
||||
Glib::Threads::RWLock::WriterLock lm (master_lock);
|
||||
|
||||
if (!_masters.empty()) {
|
||||
recompute_masters_ratios (val);
|
||||
}
|
||||
}
|
||||
|
||||
/* this sets the Evoral::Control::_user_value for us, which will
|
||||
be retrieved by AutomationControl::get_value ()
|
||||
*/
|
||||
|
||||
AutomationControl::actually_set_value (val, group_override);
|
||||
|
||||
_session.set_dirty ();
|
||||
}
|
||||
|
||||
double
|
||||
GainControl::internal_to_interface (double v) const
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ MuteControl::MuteControl (Session& session, std::string const & name, Muteable&
|
||||
void
|
||||
MuteControl::actually_set_value (double val, Controllable::GroupControlDisposition gcd)
|
||||
{
|
||||
if (muted() != bool (val)) {
|
||||
if (muted_by_self() != bool (val)) {
|
||||
_muteable.mute_master()->set_muted_by_self (val);
|
||||
|
||||
/* allow the Muteable to respond to the mute change
|
||||
@ -54,12 +54,63 @@ MuteControl::actually_set_value (double val, Controllable::GroupControlDispositi
|
||||
AutomationControl::actually_set_value (val, gcd);
|
||||
}
|
||||
|
||||
void
|
||||
MuteControl::master_changed (bool self_change, Controllable::GroupControlDisposition gcd)
|
||||
{
|
||||
double m = get_masters_value ();
|
||||
const int32_t old_muted_by_others = _muteable.mute_master()->muted_by_others ();
|
||||
std::cerr << "master " << (self_change ? " self " : " not-self") << " changed to " << m << " old others = " << old_muted_by_others << std::endl;
|
||||
|
||||
_muteable.mute_master()->mod_muted_by_others (m ? 1 : -1);
|
||||
|
||||
if (m) {
|
||||
/* master(s) are now muted. If we are self-muted, this
|
||||
doesn't change our status. If we are not self-muted,
|
||||
then it changes our status if either:
|
||||
|
||||
- the master had its own self-muted status changed OR
|
||||
- the total number of masters that are muted used to be zero
|
||||
*/
|
||||
|
||||
if (!muted_by_self()) {
|
||||
if (self_change || old_muted_by_others == 0) {
|
||||
/* note false as the first argument - our own
|
||||
value was not changed
|
||||
*/
|
||||
Changed (false, gcd);
|
||||
} else {
|
||||
cerr << " no Change signal\n";
|
||||
}
|
||||
} else {
|
||||
cerr << "muted by self, not relevant\n";
|
||||
}
|
||||
} else {
|
||||
/* no master(s) are now muted. If we are self-muted, this
|
||||
doesn't change our status. If we are not self-muted,
|
||||
then it changes our status if either:
|
||||
|
||||
- the master had its own self-muted status changed OR
|
||||
- the total number of masters that are muted used to be non-zero
|
||||
*/
|
||||
|
||||
if (!muted_by_self()) {
|
||||
if (self_change || old_muted_by_others != 0) {
|
||||
Changed (false, gcd);
|
||||
} else {
|
||||
cerr << " No change signal\n";
|
||||
}
|
||||
} else {
|
||||
cerr << "muted by self, not relevant\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
MuteControl::get_value () const
|
||||
{
|
||||
if (slaved()) {
|
||||
if (slaved ()) {
|
||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
||||
return get_masters_value_locked () ? 1.0 : 0.0;
|
||||
return get_masters_value_locked ();
|
||||
}
|
||||
|
||||
if (_list && boost::dynamic_pointer_cast<AutomationList>(_list)->automation_playback()) {
|
||||
@ -89,6 +140,12 @@ MuteControl::mute_points () const
|
||||
|
||||
bool
|
||||
MuteControl::muted () const
|
||||
{
|
||||
return _muteable.mute_master()->muted_by_self() || _muteable.mute_master()->muted_by_others();
|
||||
}
|
||||
|
||||
bool
|
||||
MuteControl::muted_by_self () const
|
||||
{
|
||||
return _muteable.mute_master()->muted_by_self();
|
||||
}
|
||||
@ -96,5 +153,5 @@ MuteControl::muted () const
|
||||
bool
|
||||
MuteControl::muted_by_others () const
|
||||
{
|
||||
return _muteable.mute_master()->muted_by_others () || get_masters_value();
|
||||
return _muteable.mute_master()->muted_by_others ();
|
||||
}
|
||||
|
@ -173,4 +173,5 @@ void
|
||||
MuteMaster::mod_muted_by_others (int32_t delta)
|
||||
{
|
||||
_muted_by_others = max (0, _muted_by_others + delta);
|
||||
std::cerr << this << " mod others by " << delta << " to get " << _muted_by_others << endl;
|
||||
}
|
||||
|
@ -5481,29 +5481,15 @@ Route::vca_unassign (boost::shared_ptr<VCA> vca)
|
||||
bool
|
||||
Route::muted_by_others_soloing () const
|
||||
{
|
||||
// This method is only used by route_ui for display state.
|
||||
// The DSP version is MuteMaster::muted_by_others_at()
|
||||
|
||||
if (!can_be_muted_by_others ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* XXX something needed here re: mute-overrides-solo */
|
||||
|
||||
return _session.soloing() && !_solo_control->soloed() && !_solo_isolate_control->solo_isolated();
|
||||
}
|
||||
|
||||
bool
|
||||
Route::muted_by_others () const
|
||||
{
|
||||
// This method is only used by route_ui for display state.
|
||||
// The DSP version is MuteMaster::muted_by_others_at()
|
||||
|
||||
if (!can_be_muted_by_others()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _mute_master->muted_by_others();
|
||||
}
|
||||
|
||||
void
|
||||
Route::clear_all_solo_state ()
|
||||
{
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef __libardour_slavable_automation_control_h__
|
||||
#define __libardour_slavable_automation_control_h__
|
||||
|
||||
#include "pbd/enumwriter.h"
|
||||
|
||||
#include "ardour/automation_control.h"
|
||||
#include "ardour/session.h"
|
||||
|
||||
@ -35,29 +37,26 @@ SlavableAutomationControl::SlavableAutomationControl(ARDOUR::Session& s,
|
||||
{
|
||||
}
|
||||
|
||||
SlavableAutomationControl::~SlavableAutomationControl ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
double
|
||||
SlavableAutomationControl::get_masters_value_locked () const
|
||||
{
|
||||
gain_t v = _desc.normal;
|
||||
double v = _desc.normal;
|
||||
|
||||
for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
|
||||
if (_desc.toggled) {
|
||||
/* if any master is enabled, the slaves are too */
|
||||
if (_desc.toggled) {
|
||||
for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
|
||||
if (mr->second.master()->get_value()) {
|
||||
return _desc.upper;
|
||||
}
|
||||
} else {
|
||||
/* get current master value, scale by our current ratio with that master */
|
||||
v *= mr->second.master()->get_value () * mr->second.ratio();
|
||||
}
|
||||
return _desc.lower;
|
||||
}
|
||||
|
||||
return min (_desc.upper, v);
|
||||
for (Masters::const_iterator mr = _masters.begin(); mr != _masters.end(); ++mr) {
|
||||
/* get current master value, scale by our current ratio with that master */
|
||||
v *= mr->second.master()->get_value () * mr->second.ratio();
|
||||
}
|
||||
|
||||
return min ((double) _desc.upper, v);
|
||||
}
|
||||
|
||||
double
|
||||
@ -69,6 +68,16 @@ SlavableAutomationControl::get_value_locked() const
|
||||
return Control::get_double (false, _session.transport_frame());
|
||||
}
|
||||
|
||||
if (_desc.toggled) {
|
||||
/* for boolean/toggle controls, if this slave OR any master is
|
||||
* enabled, this slave is enabled. So check our own value
|
||||
* first, because if we are enabled, we can return immediately.
|
||||
*/
|
||||
if (Control::get_double (false, _session.transport_frame())) {
|
||||
return _desc.upper;
|
||||
}
|
||||
}
|
||||
|
||||
return get_masters_value_locked ();
|
||||
}
|
||||
|
||||
@ -86,6 +95,27 @@ SlavableAutomationControl::get_value() const
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SlavableAutomationControl::actually_set_value (double val, Controllable::GroupControlDisposition group_override)
|
||||
{
|
||||
val = std::max (std::min (val, (double)_desc.upper), (double)_desc.lower);
|
||||
|
||||
{
|
||||
Glib::Threads::RWLock::WriterLock lm (master_lock);
|
||||
|
||||
if (!_masters.empty()) {
|
||||
recompute_masters_ratios (val);
|
||||
}
|
||||
}
|
||||
|
||||
/* this sets the Evoral::Control::_user_value for us, which will
|
||||
be retrieved by AutomationControl::get_value ()
|
||||
*/
|
||||
AutomationControl::actually_set_value (val, group_override);
|
||||
|
||||
_session.set_dirty ();
|
||||
}
|
||||
|
||||
void
|
||||
SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
|
||||
{
|
||||
@ -103,7 +133,9 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
|
||||
|
||||
if (res.second) {
|
||||
|
||||
recompute_masters_ratios (current_value);
|
||||
if (_desc.toggled) {
|
||||
recompute_masters_ratios (current_value);
|
||||
}
|
||||
|
||||
/* note that we bind @param m as a weak_ptr<AutomationControl>, thus
|
||||
avoiding holding a reference to the control in the binding
|
||||
@ -145,13 +177,17 @@ SlavableAutomationControl::add_master (boost::shared_ptr<AutomationControl> m)
|
||||
void
|
||||
SlavableAutomationControl::master_changed (bool /*from_self*/, GroupControlDisposition gcd)
|
||||
{
|
||||
cerr << this << enum_2_string ((AutomationType)_parameter.type()) << " master changed, relay changed along\n";
|
||||
|
||||
/* our value has (likely) changed, but not because we were
|
||||
* modified. Just the master.
|
||||
*/
|
||||
|
||||
Changed (false, gcd); /* EMIT SIGNAL */
|
||||
/* propagate master state into our own control so that if we stop
|
||||
* being slaved, our value doesn't change, and propagate to any
|
||||
* group this control is part of.
|
||||
*/
|
||||
|
||||
cerr << this << ' ' << enum_2_string ((AutomationType) _parameter.type()) << " pass along " << get_masters_value() << " from master to group\n";
|
||||
actually_set_value (get_masters_value(), Controllable::UseGroup);
|
||||
}
|
||||
|
||||
void
|
||||
@ -168,6 +204,7 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
|
||||
{
|
||||
double current_value;
|
||||
double new_value;
|
||||
bool masters_left;
|
||||
Masters::size_type erased = 0;
|
||||
|
||||
{
|
||||
@ -177,6 +214,7 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
|
||||
if (erased) {
|
||||
recompute_masters_ratios (current_value);
|
||||
}
|
||||
masters_left = _masters.size ();
|
||||
new_value = get_value_locked ();
|
||||
}
|
||||
|
||||
@ -185,7 +223,12 @@ SlavableAutomationControl::remove_master (boost::shared_ptr<AutomationControl> m
|
||||
}
|
||||
|
||||
if (new_value != current_value) {
|
||||
Changed (false, Controllable::NoGroup);
|
||||
if (masters_left == 0) {
|
||||
/* no masters left, make sure we keep the same value
|
||||
that we had before.
|
||||
*/
|
||||
actually_set_value (current_value, Controllable::UseGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,8 +155,7 @@ SoloControl::actually_set_value (double val, PBD::Controllable::GroupControlDisp
|
||||
be retrieved by AutomationControl::get_value (), and emits Changed
|
||||
*/
|
||||
|
||||
AutomationControl::actually_set_value (val, group_override);
|
||||
_session.set_dirty ();
|
||||
SlavableAutomationControl::actually_set_value (val, group_override);
|
||||
}
|
||||
|
||||
double
|
||||
|
Loading…
Reference in New Issue
Block a user