#include <algorithm>
#include <sigc++/bind.h>
#include <ardour/automation_event.h>
+#include <pbd/stacktrace.h>
#include "i18n.h"
sigc::signal<void,AutomationList *> AutomationList::AutomationListCreated;
+static bool sort_events_by_time (ControlEvent* a, ControlEvent* b)
+{
+ return a->when < b->when;
+}
+
#if 0
static void dumpit (const AutomationList& al, string prefix = "")
{
AutomationList::AutomationList (double defval)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_state = Off;
_style = Absolute;
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
AutomationListCreated(this);
}
AutomationList::AutomationList (const AutomationList& other)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_style = other._style;
min_yval = other.min_yval;
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
for (const_iterator i = other.events.begin(); i != other.events.end(); ++i) {
/* we have to use other point_factory() because
AutomationList::AutomationList (const AutomationList& other, double start, double end)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_style = other._style;
min_yval = other.min_yval;
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
/* now grab the relevant points, and shift them back if necessary */
AutomationList::AutomationList (const XMLNode& node)
{
- _frozen = false;
+ _frozen = 0;
changed_when_thawed = false;
_touching = false;
min_yval = FLT_MIN;
rt_insertion_point = events.end();
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
+ sort_pending = false;
set_state (node);
if (_frozen) {
changed_when_thawed = true;
} else {
- StateChanged (Change (0));
+ StateChanged ();
}
}
}
if (insert) {
-
+
events.insert (insertion_point, point_factory (when, value));
reposition_for_rt_add (0);
while (start != end) {
(*start)->when += xdelta;
(*start)->value += ydelta;
+ if (isnan ((*start)->value)) {
+ abort ();
+ }
++start;
}
+ if (!_frozen) {
+ events.sort (sort_events_by_time);
+ } else {
+ sort_pending = true;
+ }
+
mark_dirty ();
}
maybe_signal_changed ();
}
+void
+AutomationList::slide (iterator before, double distance)
+{
+ {
+ Glib::Mutex::Lock lm (lock);
+
+ if (before == events.end()) {
+ return;
+ }
+
+ while (before != events.end()) {
+ (*before)->when += distance;
+ ++before;
+ }
+ }
+
+ maybe_signal_changed ();
+}
+
void
AutomationList::modify (iterator iter, double when, double val)
{
{
Glib::Mutex::Lock lm (lock);
+
(*iter)->when = when;
(*iter)->value = val;
+
+ if (isnan (val)) {
+ abort ();
+ }
+
+ if (!_frozen) {
+ events.sort (sort_events_by_time);
+ } else {
+ sort_pending = true;
+ }
+
mark_dirty ();
}
-
+
maybe_signal_changed ();
}
void
AutomationList::freeze ()
{
- _frozen = true;
+ _frozen++;
}
void
AutomationList::thaw ()
{
- _frozen = false;
+ if (_frozen == 0) {
+ PBD::stacktrace (cerr);
+ fatal << string_compose (_("programming error: %1"), X_("AutomationList::thaw() called while not frozen")) << endmsg;
+ /*NOTREACHED*/
+ }
+
+ if (--_frozen > 0) {
+ return;
+ }
+
+ {
+ Glib::Mutex::Lock lm (lock);
+
+ if (sort_pending) {
+ events.sort (sort_events_by_time);
+ sort_pending = false;
+ }
+ }
+
if (changed_when_thawed) {
- StateChanged(Change(0)); /* EMIT SIGNAL */
+ StateChanged(); /* EMIT SIGNAL */
}
}
double last_val;
if (events.empty()) {
- fatal << _("programming error:")
- << "AutomationList::truncate_end() called on an empty list"
- << endmsg;
- /*NOTREACHED*/
return;
}
}
thaw ();
+
return 0;
}
AutomationList::set_state (const XMLNode& node)
{
XMLNodeList nlist = node.children();
+ XMLNode* nsos;
XMLNodeIterator niter;
const XMLProperty* prop;
return deserialize_events (node);
}
+ if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) {
+
+ if ((nsos = node.child (X_("AutomationList")))) {
+ /* new school in old school clothing */
+ return set_state (*nsos);
+ }
+
+ /* old school */
+
+ const XMLNodeList& elist = node.children();
+ XMLNodeConstIterator i;
+ XMLProperty* prop;
+ jack_nframes_t x;
+ double y;
+
+ freeze ();
+ clear ();
+
+ for (i = elist.begin(); i != elist.end(); ++i) {
+
+ if ((prop = (*i)->property ("x")) == 0) {
+ error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg;
+ continue;
+ }
+ x = atoi (prop->value().c_str());
+
+ if ((prop = (*i)->property ("y")) == 0) {
+ error << _("automation list: no y-coordinate stored for control point (point ignored)") << endmsg;
+ continue;
+ }
+ y = atof (prop->value().c_str());
+
+ fast_simple_add (x, y);
+ }
+
+ thaw ();
+
+ return 0;
+ }
+
if (node.name() != X_("AutomationList") ) {
error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
return -1;
deserialize_events (*(*niter));
}
}
-
+
return 0;
}