Write inverse master automation.
* The UI and ctrl-surface controls use and display the combined value, including control-masters. * The Automation lane of a control is the raw value of the control without masters. When touching (or writing) automation, the control-master needs to be factored out (or subtracted). e.g press+hold a control -> write inverse master automation.
This commit is contained in:
parent
b34d891b23
commit
c1912b6d51
|
@ -45,11 +45,18 @@ public:
|
|||
void clear_masters ();
|
||||
bool slaved_to (boost::shared_ptr<AutomationControl>) const;
|
||||
bool slaved () const;
|
||||
|
||||
double get_masters_value () const {
|
||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
||||
return get_masters_value_locked ();
|
||||
}
|
||||
|
||||
/* factor out get_masters_value() */
|
||||
double reduce_by_masters (double val, bool ignore_automation_state = false) const {
|
||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
||||
return reduce_by_masters_locked (val, ignore_automation_state);
|
||||
}
|
||||
|
||||
bool get_masters_curve (framepos_t s, framepos_t e, float* v, framecnt_t l) const {
|
||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
||||
return get_masters_curve_locked (s, e, v, l);
|
||||
|
@ -130,6 +137,8 @@ protected:
|
|||
virtual bool get_masters_curve_locked (framepos_t, framepos_t, float*, framecnt_t) const;
|
||||
bool masters_curve_multiply (framepos_t, framepos_t, float*, framecnt_t) const;
|
||||
|
||||
virtual double reduce_by_masters_locked (double val, bool) const;
|
||||
|
||||
virtual bool handle_master_change (boost::shared_ptr<AutomationControl>);
|
||||
virtual bool boolean_automation_run_locked (framepos_t start, pframes_t len);
|
||||
bool boolean_automation_run (framepos_t start, pframes_t len);
|
||||
|
|
|
@ -257,10 +257,14 @@ AutomationControl::start_touch(double when)
|
|||
}
|
||||
|
||||
if (!touching()) {
|
||||
|
||||
if (alist()->automation_state() == Touch) {
|
||||
/* subtle. aligns the user value with the playback */
|
||||
set_value (get_value (), Controllable::NoGroup);
|
||||
/* subtle. aligns the user value with the playback and
|
||||
* use take actual value (incl masters).
|
||||
*
|
||||
* Touch + hold writes inverse curve of master-automation
|
||||
* using AutomationWatch::timer ()
|
||||
*/
|
||||
AutomationControl::actually_set_value (get_value (), Controllable::NoGroup);
|
||||
alist()->start_touch (when);
|
||||
if (!_desc.toggled) {
|
||||
AutomationWatch::instance().add_automation_watch (shared_from_this());
|
||||
|
|
|
@ -149,7 +149,12 @@ AutomationWatch::timer ()
|
|||
if (time > _last_time) { //we only write automation in the forward direction; this fixes automation-recording in a loop
|
||||
for (AutomationWatches::iterator aw = automation_watches.begin(); aw != automation_watches.end(); ++aw) {
|
||||
if ((*aw)->alist()->automation_write()) {
|
||||
(*aw)->list()->add (time, (*aw)->user_double(), true);
|
||||
double val = (*aw)->user_double();
|
||||
boost::shared_ptr<SlavableAutomationControl> sc = boost::dynamic_pointer_cast<SlavableAutomationControl> (*aw);
|
||||
if (sc) {
|
||||
val = sc->reduce_by_masters (val, true);
|
||||
}
|
||||
(*aw)->list()->add (time, val, true);
|
||||
}
|
||||
}
|
||||
} else if (time != _last_time) { //transport stopped or reversed. stop the automation pass and start a new one (for bonus points, someday store the previous pass in an undo record)
|
||||
|
|
|
@ -106,6 +106,10 @@ SlavableAutomationControl::get_value() const
|
|||
|
||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
||||
if (!from_list) {
|
||||
if (!_masters.empty() && automation_write ()) {
|
||||
/* writing automation takes the fader value as-is, factor out the master */
|
||||
return Control::user_double ();
|
||||
}
|
||||
return get_value_locked ();
|
||||
} else {
|
||||
return Control::get_double (true, _session.transport_frame()) * get_masters_value_locked();
|
||||
|
@ -153,14 +157,12 @@ SlavableAutomationControl::masters_curve_multiply (framepos_t start, framepos_t
|
|||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
|
||||
double
|
||||
SlavableAutomationControl::reduce_by_masters_locked (double value, bool ignore_automation_state) const
|
||||
{
|
||||
if (!_desc.toggled) {
|
||||
|
||||
Glib::Threads::RWLock::WriterLock lm (master_lock);
|
||||
|
||||
if (!_masters.empty()) {
|
||||
Glib::Threads::RWLock::ReaderLock lm (master_lock);
|
||||
if (!_masters.empty() && (ignore_automation_state || !automation_write ())) {
|
||||
/* need to scale given value by current master's scaling */
|
||||
const double masters_value = get_masters_value_locked();
|
||||
if (masters_value == 0.0) {
|
||||
|
@ -171,7 +173,13 @@ SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::
|
|||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
SlavableAutomationControl::actually_set_value (double value, PBD::Controllable::GroupControlDisposition gcd)
|
||||
{
|
||||
value = reduce_by_masters (value);
|
||||
/* this will call Control::set_double() and emit Changed signals as appropriate */
|
||||
AutomationControl::actually_set_value (value, gcd);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user