}
#endif
-AutomationList::AutomationList (double defval, bool with_state)
+AutomationList::AutomationList (double defval)
{
_frozen = false;
changed_when_thawed = false;
_state = Off;
_style = Absolute;
_touching = false;
- no_state = with_state;
min_yval = FLT_MIN;
max_yval = FLT_MAX;
max_xval = 0; // means "no limit"
_touching = other._touching;
_dirty = false;
rt_insertion_point = events.end();
- no_state = other.no_state;
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
_touching = other._touching;
_dirty = false;
rt_insertion_point = events.end();
- no_state = other.no_state;
lookup_cache.left = -1;
lookup_cache.range.first = events.end();
delete section;
mark_dirty ();
+
+ AutomationListCreated(this);
+}
+
+AutomationList::AutomationList (const XMLNode& node)
+{
+ _frozen = false;
+ changed_when_thawed = false;
+ _touching = false;
+ min_yval = FLT_MIN;
+ max_yval = FLT_MAX;
+ max_xval = 0; // means "no limit"
+ _dirty = false;
+ _state = Off;
+ _style = Absolute;
+ rt_insertion_point = events.end();
+ lookup_cache.left = -1;
+ lookup_cache.range.first = events.end();
+
+ set_state (node);
+
AutomationListCreated(this);
}
AutomationList::~AutomationList()
{
GoingAway ();
-
+
for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) {
delete (*x);
}
maybe_signal_changed ();
}
+void
+AutomationList::fast_simple_add (double when, double value)
+{
+ /* to be used only for loading pre-sorted data from saved state */
+ events.insert (events.end(), point_factory (when, value));
+}
+
#undef last_rt_insertion_point
void
AutomationList::add (double when, double value)
{
- /* this is for graphical editing and loading data from storage */
+ /* this is for graphical editing */
{
Glib::Mutex::Lock lm (lock);
Glib::Mutex::Lock lm (lock);
events.erase (i);
reposition_for_rt_add (0);
- if (!no_state) {
-#ifdef STATE_MANAGER
- save_state (_("removed event"));
-#endif
- }
mark_dirty ();
}
maybe_signal_changed ();
double last_val;
if (events.empty()) {
- fatal << _("programming error:")
- << "AutomationList::truncate_end() called on an empty list"
- << endmsg;
- /*NOTREACHED*/
return;
}
XMLNode&
AutomationList::get_state ()
{
- stringstream str;
+ return state (true);
+}
+
+XMLNode&
+AutomationList::state (bool full)
+{
+ XMLNode* root = new XMLNode (X_("AutomationList"));
+ char buf[64];
+ LocaleGuard lg (X_("POSIX"));
+
+ root->add_property ("id", _id.to_s());
+
+ snprintf (buf, sizeof (buf), "%.12g", default_value);
+ root->add_property ("default", buf);
+ snprintf (buf, sizeof (buf), "%.12g", min_yval);
+ root->add_property ("min_yval", buf);
+ snprintf (buf, sizeof (buf), "%.12g", max_yval);
+ root->add_property ("max_yval", buf);
+ snprintf (buf, sizeof (buf), "%.12g", max_xval);
+ root->add_property ("max_xval", buf);
+
+ if (full) {
+ root->add_property ("state", auto_state_to_string (_state));
+ } else {
+ /* never save anything but Off for automation state to a template */
+ root->add_property ("state", auto_state_to_string (Off));
+ }
+
+ root->add_property ("style", auto_style_to_string (_style));
+
+ if (!events.empty()) {
+ root->add_child_nocopy (serialize_events());
+ }
+
+ return *root;
+}
+
+XMLNode&
+AutomationList::serialize_events ()
+{
XMLNode* node = new XMLNode (X_("events"));
- iterator xx;
+ stringstream str;
- for (xx = events.begin(); xx != events.end(); ++xx) {
+ for (iterator xx = events.begin(); xx != events.end(); ++xx) {
str << (double) (*xx)->when;
str << ' ';
str <<(double) (*xx)->value;
str << '\n';
}
- node->add_content (str.str());
+ /* XML is a bit wierd */
+
+ XMLNode* content_node = new XMLNode (X_("foo")); /* it gets renamed by libxml when we set content */
+ content_node->set_content (str.str());
+
+ node->add_child_nocopy (*content_node);
return *node;
}
int
-AutomationList::set_state (const XMLNode& node)
+AutomationList::deserialize_events (const XMLNode& node)
{
- const XMLNodeList& elist = node.children();
- XMLNodeConstIterator i;
- XMLProperty* prop;
+ if (node.children().empty()) {
+ return -1;
+ }
- freeze ();
+ XMLNode* content_node = node.children().front();
+ if (content_node->content().empty()) {
+ return -1;
+ }
+
+ freeze ();
clear ();
- for (i = elist.begin(); i != elist.end(); ++i) {
-
- if ((*i)->name() == X_("events")) {
-
- /* new style */
-
- stringstream str (node.content());
+ stringstream str (content_node->content());
+
+ double x;
+ double y;
+ bool ok = true;
+
+ while (str) {
+ str >> x;
+ if (!str) {
+ break;
+ }
+ str >> y;
+ if (!str) {
+ ok = false;
+ break;
+ }
+ fast_simple_add (x, y);
+ }
+
+ if (!ok) {
+ clear ();
+ error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
+ } else {
+ mark_dirty ();
+ reposition_for_rt_add (0);
+ maybe_signal_changed ();
+ }
- double x;
- double y;
- bool ok = true;
+ thaw ();
+ return 0;
+}
- while (str) {
- str >> x;
- if (!str) {
- ok = false;
- break;
- }
- str >> y;
- if (!str) {
- ok = false;
- break;
- }
- add (x, y);
- }
+int
+AutomationList::set_state (const XMLNode& node)
+{
+ XMLNodeList nlist = node.children();
+ XMLNodeIterator niter;
+ const XMLProperty* prop;
- if (!ok) {
- clear ();
- error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg;
- }
+ if (node.name() == X_("events")) {
+ /* partial state setting*/
+ return deserialize_events (node);
+ }
+
+ if (node.name() == X_("Envelope") || node.name() == X_("FadeOut") || node.name() == X_("FadeIn")) {
- } else {
+ /* old school */
- /* old style */
+ const XMLNodeList& elist = node.children();
+ XMLNodeConstIterator i;
+ XMLProperty* prop;
+ jack_nframes_t x;
+ double y;
- nframes_t x;
- double y;
-
+ 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;
add (x, y);
}
+
+ return 0;
}
- thaw ();
+ if (node.name() != X_("AutomationList") ) {
+ error << string_compose (_("AutomationList: passed XML node called %1, not \"AutomationList\" - ignored"), node.name()) << endmsg;
+ return -1;
+ }
+
+ if ((prop = node.property ("id")) != 0) {
+ _id = prop->value ();
+ /* update session AL list */
+ AutomationListCreated(this);
+ }
+
+ if ((prop = node.property (X_("default"))) != 0){
+ default_value = atof (prop->value());
+ } else {
+ default_value = 0.0;
+ }
+
+ if ((prop = node.property (X_("style"))) != 0) {
+ _style = string_to_auto_style (prop->value());
+ } else {
+ _style = Absolute;
+ }
+
+ if ((prop = node.property (X_("state"))) != 0) {
+ _state = string_to_auto_state (prop->value());
+ } else {
+ _state = Off;
+ }
+
+ if ((prop = node.property (X_("min_yval"))) != 0) {
+ min_yval = atof (prop->value ());
+ } else {
+ min_yval = FLT_MIN;
+ }
+
+ if ((prop = node.property (X_("max_yval"))) != 0) {
+ max_yval = atof (prop->value ());
+ } else {
+ max_yval = FLT_MAX;
+ }
+
+ if ((prop = node.property (X_("max_xval"))) != 0) {
+ max_xval = atof (prop->value ());
+ } else {
+ max_xval = 0; // means "no limit ;
+ }
+
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+ if ((*niter)->name() == X_("events")) {
+ deserialize_events (*(*niter));
+ }
+ }
+
return 0;
}