diff options
Diffstat (limited to 'libs/ardour/automation_event.cc')
-rw-r--r-- | libs/ardour/automation_event.cc | 389 |
1 files changed, 235 insertions, 154 deletions
diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index f286b11607..5cc2f50e38 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -22,9 +22,11 @@ #include <climits> #include <float.h> #include <cmath> +#include <sstream> #include <algorithm> #include <sigc++/bind.h> #include <ardour/automation_event.h> +#include <pbd/convert.h> #include "i18n.h" @@ -46,14 +48,13 @@ static void dumpit (const AutomationList& al, string prefix = "") } #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" @@ -63,10 +64,6 @@ AutomationList::AutomationList (double defval, bool with_state) lookup_cache.left = -1; lookup_cache.range.first = events.end(); - if (!no_state) { - save_state (_("initial")); - } - AutomationListCreated(this); } @@ -83,7 +80,6 @@ AutomationList::AutomationList (const AutomationList& other) _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(); @@ -111,7 +107,6 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl _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(); @@ -128,32 +123,36 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl delete section; mark_dirty (); + AutomationListCreated(this); } -AutomationList::~AutomationList() +AutomationList::AutomationList (const XMLNode& node) { - std::set<ControlEvent*> all_events; - AutomationList::State* asp; + _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); - GoingAway (); + AutomationListCreated(this); +} +AutomationList::~AutomationList() +{ + GoingAway (); + for (AutomationEventList::iterator x = events.begin(); x != events.end(); ++x) { - all_events.insert (*x); - } - - for (StateMap::iterator i = states.begin(); i != states.end(); ++i) { - - if ((asp = dynamic_cast<AutomationList::State*> (*i)) != 0) { - - for (AutomationEventList::iterator x = asp->events.begin(); x != asp->events.end(); ++x) { - all_events.insert (*x); - } - } - } - - for (std::set<ControlEvent*>::iterator i = all_events.begin(); i != all_events.end(); ++i) { - delete (*i); + delete (*x); } } @@ -194,7 +193,7 @@ AutomationList::maybe_signal_changed () if (_frozen) { changed_when_thawed = true; } else { - StateChanged (Change (0)); + StateChanged (); } } @@ -236,9 +235,6 @@ AutomationList::clear () { Glib::Mutex::Lock lm (lock); events.clear (); - if (!no_state) { - save_state (_("cleared")); - } mark_dirty (); } @@ -270,7 +266,6 @@ void AutomationList::_x_scale (double factor) (*i)->when = floor ((*i)->when * factor); } - save_state ("x-scaled"); mark_dirty (); } @@ -370,12 +365,19 @@ AutomationList::rt_add (double when, double value) 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, bool for_loading) +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); @@ -407,15 +409,9 @@ AutomationList::add (double when, double value, bool for_loading) } mark_dirty (); - - if (!no_state && !for_loading) { - save_state (_("added event")); - } } - if (!for_loading) { - maybe_signal_changed (); - } + maybe_signal_changed (); } void @@ -425,9 +421,6 @@ AutomationList::erase (AutomationList::iterator i) Glib::Mutex::Lock lm (lock); events.erase (i); reposition_for_rt_add (0); - if (!no_state) { - save_state (_("removed event")); - } mark_dirty (); } maybe_signal_changed (); @@ -440,9 +433,6 @@ AutomationList::erase (AutomationList::iterator start, AutomationList::iterator Glib::Mutex::Lock lm (lock); events.erase (start, end); reposition_for_rt_add (0); - if (!no_state) { - save_state (_("removed multiple events")); - } mark_dirty (); } maybe_signal_changed (); @@ -471,10 +461,6 @@ AutomationList::reset_range (double start, double endt) reset = true; - if (!no_state) { - save_state (_("removed range")); - } - mark_dirty (); } } @@ -502,9 +488,6 @@ AutomationList::erase_range (double start, double endt) events.erase (s, e); reposition_for_rt_add (0); erased = true; - if (!no_state) { - save_state (_("removed range")); - } mark_dirty (); } @@ -532,10 +515,6 @@ AutomationList::move_range (iterator start, iterator end, double xdelta, double ++start; } - if (!no_state) { - save_state (_("event range adjusted")); - } - mark_dirty (); } @@ -554,10 +533,6 @@ AutomationList::modify (iterator iter, double when, double val) Glib::Mutex::Lock lm (lock); (*iter)->when = when; (*iter)->value = val; - if (!no_state) { - save_state (_("event adjusted")); - } - mark_dirty (); } @@ -609,44 +584,10 @@ AutomationList::thaw () { _frozen = false; if (changed_when_thawed) { - StateChanged(Change(0)); /* EMIT SIGNAL */ + StateChanged(); /* EMIT SIGNAL */ } } -StateManager::State* -AutomationList::state_factory (std::string why) const -{ - State* state = new State (why); - - for (AutomationEventList::const_iterator x = events.begin(); x != events.end(); ++x) { - state->events.push_back (point_factory (**x)); - } - - return state; -} - -Change -AutomationList::restore_state (StateManager::State& state) -{ - { - Glib::Mutex::Lock lm (lock); - State* lstate = dynamic_cast<State*> (&state); - - events.clear (); - for (AutomationEventList::const_iterator x = lstate->events.begin(); x != lstate->events.end(); ++x) { - events.push_back (point_factory (**x)); - } - } - - return Change (0); -} - -UndoAction -AutomationList::get_memento () const -{ - return sigc::bind (mem_fun (*(const_cast<AutomationList*> (this)), &StateManager::use_state), _current_state_id); -} - void AutomationList::set_max_xval (double x) { @@ -670,10 +611,6 @@ AutomationList::truncate_end (double last_coordinate) double last_val; if (events.empty()) { - fatal << _("programming error:") - << "AutomationList::truncate_end() called on an empty list" - << endmsg; - /*NOTREACHED*/ return; } @@ -1083,9 +1020,6 @@ AutomationList::cut_copy_clear (double start, double end, int op) if (changed) { reposition_for_rt_add (0); - if (!no_state) { - save_state (_("cut/copy/clear")); - } } mark_dirty (); @@ -1115,10 +1049,6 @@ AutomationList::copy (iterator start, iterator end) x = tmp; } - - if (!no_state) { - save_state (_("copy")); - } } return nal; @@ -1183,11 +1113,6 @@ AutomationList::paste (AutomationList& alist, double pos, float times) } reposition_for_rt_add (0); - - if (!no_state) { - save_state (_("paste")); - } - mark_dirty (); } @@ -1207,64 +1132,220 @@ AutomationList::point_factory (const ControlEvent& other) const return new ControlEvent (other); } -void -AutomationList::store_state (XMLNode& node) const +XMLNode& +AutomationList::get_state () { + return state (true); +} + +XMLNode& +AutomationList::state (bool full) +{ + XMLNode* root = new XMLNode (X_("AutomationList")); + char buf[64]; LocaleGuard lg (X_("POSIX")); - for (const_iterator i = const_begin(); i != const_end(); ++i) { - char buf[64]; - - XMLNode *pointnode = new XMLNode ("point"); - - snprintf (buf, sizeof (buf), "%" PRIu32, (nframes_t) floor ((*i)->when)); - pointnode->add_property ("x", buf); - snprintf (buf, sizeof (buf), "%.12g", (*i)->value); - pointnode->add_property ("y", buf); + root->add_property ("id", _id.to_s()); - node.add_child_nocopy (*pointnode); + 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; } -void -AutomationList::load_state (const XMLNode& node) +XMLNode& +AutomationList::serialize_events () { - const XMLNodeList& elist = node.children(); - XMLNodeConstIterator i; - XMLProperty* prop; - nframes_t x; - double y; + XMLNode* node = new XMLNode (X_("events")); + stringstream str; + + for (iterator xx = events.begin(); xx != events.end(); ++xx) { + str << (double) (*xx)->when; + str << ' '; + str <<(double) (*xx)->value; + str << '\n'; + } + + /* 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::deserialize_events (const XMLNode& node) +{ + if (node.children().empty()) { + return -1; + } + + XMLNode* content_node = node.children().front(); + if (content_node->content().empty()) { + return -1; + } + + 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; + stringstream str (content_node->content()); + + double x; + double y; + bool ok = true; + + while (str) { + str >> x; + if (!str) { + break; } - 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; + str >> y; + if (!str) { + ok = false; + break; } - y = atof (prop->value().c_str()); - - add (x, y); + 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 (); } -} -XMLNode &AutomationList::get_state () -{ - XMLNode *node = new XMLNode("AutomationList"); - store_state(*node); - return *node; + thaw (); + return 0; } -int AutomationList::set_state(const XMLNode &s) +int +AutomationList::set_state (const XMLNode& node) { - load_state(s); - return 0; + XMLNodeList nlist = node.children(); + XMLNode* nsos; + XMLNodeIterator niter; + const XMLProperty* prop; + + 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")) { + + 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; + + 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()); + + add (x, y); + } + + return 0; + } + + 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; } |