Make automation record undo per pass rather than per touch.

This commit is contained in:
nick_m 2015-09-27 00:57:52 +10:00
parent 877b258c74
commit 9c102fa8d2
8 changed files with 70 additions and 18 deletions

View File

@ -196,7 +196,22 @@ void
AutomationController::toggled ()
{
ArdourButton* but = dynamic_cast<ArdourButton*>(_widget);
const AutoState as = _controllable->automation_state ();
const bool to_list = _controllable->list () && _controllable->session().transport_rolling () && (as == Touch || as == Write);
if (but) {
if (_controllable->session().transport_rolling()) {
if (_controllable->automation_state() == Touch && _controllable->list()->in_new_write_pass ()) {
_controllable->alist()->start_write_pass ( _controllable->session().audible_frame());
}
if (_controllable->list()) {
_controllable->list()->set_in_write_pass(true, false, _controllable->session().audible_frame());
}
}
_controllable->set_double (!but->get_active (), _controllable->session ().transport_frame (), to_list);
const bool was_active = _controllable->get_value() >= 0.5;
if (was_active && but->get_active()) {
_adjustment->set_value(0.0);

View File

@ -95,13 +95,13 @@ public:
const ParameterDescriptor& desc() const { return _desc; }
const ARDOUR::Session& session() const { return _session; }
void commit_transaction ();
protected:
ARDOUR::Session& _session;
const ParameterDescriptor _desc;
XMLNode* _before; //used for undo of touch start/stop pairs.
};

View File

@ -97,6 +97,9 @@ class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Ev
static PBD::Signal1<void,AutomationList*> AutomationListCreated;
void start_write_pass (double when);
void write_pass_finished (double when, double thinning_factor=0.0);
void start_touch (double when);
void stop_touch (bool mark, double when);
bool touching() const { return g_atomic_int_get (const_cast<gint*>(&_touching)); }
@ -110,6 +113,7 @@ class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Ev
bool operator!= (const AutomationList &) const;
XMLNode* before () { return _before; }
private:
void create_curve_if_necessary ();
int deserialize_events (const XMLNode&);
@ -121,6 +125,8 @@ class LIBARDOUR_API AutomationList : public PBD::StatefulDestructible, public Ev
gint _touching;
bool operator== (const AutomationList&) const { /* not called */ abort(); return false; }
XMLNode* _before; //used for undo of touch start/stop pairs.
};
} // namespace

View File

@ -365,7 +365,7 @@ Automatable::transport_located (framepos_t now)
boost::shared_ptr<AutomationList> l
= boost::dynamic_pointer_cast<AutomationList>(c->list());
if (l) {
if (l && l->automation_state () == Write) {
l->start_write_pass (now);
}
}
@ -394,7 +394,12 @@ Automatable::transport_stopped (framepos_t now)
when the transport is re-started, a touch will magically
be happening without it ever have being started in the usual way.
*/
const bool list_did_write = !l->in_new_write_pass ();
l->stop_touch (true, now);
if (list_did_write) {
c->commit_transaction ();
}
l->write_pass_finished (now, Config->get_automation_thinning_factor());
if (l->automation_playback()) {

View File

@ -88,8 +88,6 @@ AutomationControl::set_automation_state (AutoState as)
}
if (as == Write) {
/* get state for undo */
_before = &alist ()->get_state ();
AutomationWatch::instance().add_automation_watch (shared_from_this());
} else if (as == Touch) {
if (!touching()) {
@ -127,7 +125,6 @@ AutomationControl::start_touch(double when)
if (alist()->automation_state() == Touch) {
/* subtle. aligns the user value with the playback */
set_value (get_value ());
_before = &alist ()->get_state ();
alist()->start_touch (when);
if (!_desc.toggled) {
AutomationWatch::instance().add_automation_watch (shared_from_this());
@ -144,25 +141,25 @@ AutomationControl::stop_touch(bool mark, double when)
if (touching()) {
set_touching (false);
if (alist()->automation_state() == Write) {
_session.begin_reversible_command (string_compose (_("write %1 automation"), name ()));
_session.add_command (new MementoCommand<AutomationList> (*alist ().get (), _before, &alist ()->get_state ()));
_session.commit_reversible_command ();
}
if (alist()->automation_state() == Touch) {
alist()->stop_touch (mark, when);
if (!_desc.toggled) {
AutomationWatch::instance().remove_automation_watch (shared_from_this());
}
_session.begin_reversible_command (string_compose (_("touch %1 automation"), name ()));
_session.add_command (new MementoCommand<AutomationList> (*alist ().get (), _before, &alist ()->get_state ()));
_session.commit_reversible_command ();
}
}
}
}
void
AutomationControl::commit_transaction ()
{
if (alist ()->before ()) {
_session.begin_reversible_command (string_compose (_("record %1 automation"), name ()));
_session.commit_reversible_command (new MementoCommand<AutomationList> (*alist ().get (), alist ()->before (), &alist ()->get_state ()));
}
}
double
AutomationControl::internal_to_interface (double val) const
{

View File

@ -50,6 +50,7 @@ static void dumpit (const AutomationList& al, string prefix = "")
#endif
AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc)
: ControlList(id, desc)
, _before (0)
{
_state = Off;
_style = Absolute;
@ -63,6 +64,7 @@ AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::Param
AutomationList::AutomationList (const Evoral::Parameter& id)
: ControlList(id, ARDOUR::ParameterDescriptor(id))
, _before (0)
{
_state = Off;
_style = Absolute;
@ -77,6 +79,7 @@ AutomationList::AutomationList (const Evoral::Parameter& id)
AutomationList::AutomationList (const AutomationList& other)
: StatefulDestructible()
, ControlList(other)
, _before (0)
{
_style = other._style;
_state = other._state;
@ -90,6 +93,7 @@ AutomationList::AutomationList (const AutomationList& other)
AutomationList::AutomationList (const AutomationList& other, double start, double end)
: ControlList(other, start, end)
, _before (0)
{
_style = other._style;
_state = other._state;
@ -106,6 +110,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
*/
AutomationList::AutomationList (const XMLNode& node, Evoral::Parameter id)
: ControlList(id, ARDOUR::ParameterDescriptor(id))
, _before (0)
{
g_atomic_int_set (&_touching, 0);
_state = Off;
@ -186,6 +191,9 @@ AutomationList::set_automation_state (AutoState s)
{
if (s != _state) {
_state = s;
if (s == Write) {
_before = &get_state ();
}
automation_state_changed (s); /* EMIT SIGNAL */
}
}
@ -199,6 +207,22 @@ AutomationList::set_automation_style (AutoStyle s)
}
}
void
AutomationList::start_write_pass (double when)
{
if (in_new_write_pass ()) {
_before = &get_state ();
}
ControlList::start_write_pass (when);
}
void
AutomationList::write_pass_finished (double when, double thinning_factor)
{
ControlList::write_pass_finished (when, thinning_factor);
_before = 0;
}
void
AutomationList::start_touch (double when)
{

View File

@ -3904,11 +3904,15 @@ Route::MuteControllable::set_superficial_value(bool muted)
as currently MuteControllable can't be touching.
bool to_list = _list && ((AutomationList*)_list.get())->automation_write();
*/
const AutoState as = ((AutomationList*)_list.get())->automation_state ();
bool to_list = _list && _session.transport_rolling () && (as == Touch || as == Write);
AutomationList* alist = (AutomationList*)_list.get();
const AutoState as = alist->automation_state ();
const bool to_list = _list && _session.transport_rolling () && (as == Touch || as == Write);
if (to_list) {
_list->set_in_write_pass(true, false, _session.audible_frame ());
if (as == Touch && _list->in_new_write_pass ()) {
alist->start_write_pass (_session.audible_frame ());
}
_list->set_in_write_pass (true, false, _session.audible_frame ());
}
Control::set_double (muted, _session.transport_frame(), to_list);

View File

@ -267,6 +267,7 @@ public:
void write_pass_finished (double when, double thinning_factor=0.0);
void set_in_write_pass (bool, bool add_point = false, double when = 0.0);
bool in_write_pass () const;
bool in_new_write_pass () { return new_write_pass; }
/** Emitted when mark_dirty() is called on this object */
mutable PBD::Signal0<void> Dirty;