diff --git a/libs/ardour/ardour/automation_event.h b/libs/ardour/ardour/automation_event.h index 89823bc738..fcc9bb5e91 100644 --- a/libs/ardour/ardour/automation_event.h +++ b/libs/ardour/ardour/automation_event.h @@ -84,8 +84,7 @@ class AutomationList : public PBD::StatefulDestructible void reposition_for_rt_add (double when); void rt_add (double when, double value); - iterator add (double when, double value, iterator, bool ignore_mode = false); - void add (double when, double value, bool for_loading = false); + void add (double when, double value); void reset_range (double start, double end); void erase_range (double start, double end); @@ -152,9 +151,6 @@ class AutomationList : public PBD::StatefulDestructible sigc::signal StateChanged; - virtual void store_state (XMLNode& node) const; - virtual void load_state (const XMLNode&); - XMLNode &get_state(void); int set_state (const XMLNode &s); diff --git a/libs/ardour/ardour/io.h b/libs/ardour/ardour/io.h index e1ed7aef95..b078b3488d 100644 --- a/libs/ardour/ardour/io.h +++ b/libs/ardour/ardour/io.h @@ -295,11 +295,11 @@ public: bool apply_gain_automation; Curve _gain_automation_curve; - int save_automation (const string&); - int load_automation (const string&); - Glib::Mutex automation_lock; + virtual int set_automation_state (const XMLNode&); + virtual XMLNode& get_automation_state (); + /* AudioTrack::deprecated_use_diskstream_connections() needs these */ int set_inputs (const string& str); diff --git a/libs/ardour/ardour/redirect.h b/libs/ardour/ardour/redirect.h index e60438f3ba..ccfd8590b2 100644 --- a/libs/ardour/ardour/redirect.h +++ b/libs/ardour/ardour/redirect.h @@ -99,9 +99,6 @@ class Redirect : public IO return 1.0f; } - int load_automation (string path); - int save_automation (string path); - void what_has_automation (set&) const; void what_has_visible_automation (set&) const; const set& what_can_be_automated () const { return can_automate_list; } @@ -128,6 +125,9 @@ class Redirect : public IO virtual void automation_list_creation_callback (uint32_t, AutomationList&) {} + int set_automation_state (const XMLNode&); + XMLNode& get_automation_state (); + private: bool _active; Placement _placement; diff --git a/libs/ardour/audioregion.cc b/libs/ardour/audioregion.cc index d2cf279d3e..552218f824 100644 --- a/libs/ardour/audioregion.cc +++ b/libs/ardour/audioregion.cc @@ -598,7 +598,7 @@ AudioRegion::state (bool full) if ((_flags & DefaultFadeIn)) { child->add_property (X_("default"), X_("yes")); } else { - _fade_in.store_state (*child); + child->add_child_nocopy (_fade_in.get_state ()); } child->add_property (X_("active"), _fade_in_disabled ? X_("no") : X_("yes")); @@ -608,9 +608,9 @@ AudioRegion::state (bool full) if ((_flags & DefaultFadeOut)) { child->add_property (X_("default"), X_("yes")); } else { - _fade_out.store_state (*child); + child->add_child_nocopy (_fade_out.get_state ()); } - + child->add_property (X_("active"), _fade_out_disabled ? X_("no") : X_("yes")); } @@ -621,6 +621,7 @@ AudioRegion::state (bool full) // If there are only two points, the points are in the start of the region and the end of the region // so, if they are both at 1.0f, that means the default region. + if (_envelope.size() == 2 && _envelope.front()->value == 1.0f && _envelope.back()->value==1.0f) { @@ -632,7 +633,7 @@ AudioRegion::state (bool full) if (default_env) { child->add_property ("default", "yes"); } else { - _envelope.store_state (*child); + child->add_child_nocopy (_envelope.get_state ()); } } else { @@ -696,7 +697,7 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen if ((prop = child->property ("default")) != 0) { set_default_envelope (); } else { - _envelope.load_state (*child); + _envelope.set_state (*child); } _envelope.set_max_xval (_length); @@ -709,7 +710,7 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) { set_default_fade_in (); } else { - _fade_in.load_state (*child); + _fade_in.set_state (*child); } } else if (child->name() == "FadeOut") { @@ -719,7 +720,7 @@ AudioRegion::set_live_state (const XMLNode& node, Change& what_changed, bool sen if ((prop = child->property ("default")) != 0 || (prop = child->property ("steepness")) != 0) { set_default_fade_out (); } else { - _fade_out.load_state (*child); + _fade_out.set_state (*child); } } } diff --git a/libs/ardour/automation_event.cc b/libs/ardour/automation_event.cc index 00a6e638a7..c82a95e058 100644 --- a/libs/ardour/automation_event.cc +++ b/libs/ardour/automation_event.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -348,7 +349,7 @@ AutomationList::rt_add (double when, double 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 */ @@ -384,9 +385,7 @@ AutomationList::add (double when, double value, bool for_loading) mark_dirty (); } - if (!for_loading) { - maybe_signal_changed (); - } + maybe_signal_changed (); } void @@ -1116,68 +1115,91 @@ AutomationList::point_factory (const ControlEvent& other) const return new ControlEvent (other); } -void -AutomationList::store_state (XMLNode& node) const +XMLNode& +AutomationList::get_state () { - LocaleGuard lg (X_("POSIX")); + stringstream str; + XMLNode* node = new XMLNode (X_("events")); + iterator xx; - 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); - - node.add_child_nocopy (*pointnode); + for (xx = events.begin(); xx != events.end(); ++xx) { + str << (double) (*xx)->when; + str << ' '; + str <<(double) (*xx)->value; + str << '\n'; } + + node->add_content (str.str()); + + return *node; } -void -AutomationList::load_state (const XMLNode& node) +int +AutomationList::set_state (const XMLNode& node) { const XMLNodeList& elist = node.children(); XMLNodeConstIterator i; XMLProperty* prop; - nframes_t x; - double y; freeze (); clear (); for (i = elist.begin(); i != elist.end(); ++i) { + + if ((*i)->name() == X_("events")) { + + /* new style */ + + stringstream str (node.content()); + + double x; + double y; + bool ok = true; + + while (str) { + str >> x; + if (!str) { + ok = false; + break; + } + str >> y; + if (!str) { + ok = false; + break; + } + add (x, y); + } + + if (!ok) { + clear (); + error << _("automation list: cannot load coordinates from XML, all points ignored") << endmsg; + } + + } else { + + /* old style */ - if ((prop = (*i)->property ("x")) == 0) { - error << _("automation list: no x-coordinate stored for control point (point ignored)") << endmsg; - continue; + nframes_t x; + double y; + + 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); } - 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); } thaw (); -} - -XMLNode &AutomationList::get_state () -{ - XMLNode *node = new XMLNode("AutomationList"); - store_state(*node); - return *node; -} - -int AutomationList::set_state(const XMLNode &s) -{ - load_state(s); - return 0; + return 0; } diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc index 323c58b65e..4de8105a5c 100644 --- a/libs/ardour/io.cc +++ b/libs/ardour/io.cc @@ -1527,11 +1527,13 @@ IO::state (bool full_state) /* automation */ if (full_state) { + node->add_child_nocopy (get_automation_state ()); snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_state()); } else { /* never store anything except Off for automation state in a template */ snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off); } + node->add_property ("automation-state", buf); snprintf (buf, sizeof (buf), "0x%x", (int) _gain_automation_curve.automation_style()); node->add_property ("automation-style", buf); @@ -2362,116 +2364,6 @@ IO::meter () } } -int -IO::save_automation (const string& path) -{ - string fullpath; - ofstream out; - - fullpath = _session.automation_dir(); - fullpath += path; - - out.open (fullpath.c_str()); - - if (!out) { - error << string_compose(_("%1: could not open automation event file \"%2\""), _name, fullpath) << endmsg; - return -1; - } - - out << X_("version ") << current_automation_version_number << endl; - - /* XXX use apply_to_points to get thread safety */ - - for (AutomationList::iterator i = _gain_automation_curve.begin(); i != _gain_automation_curve.end(); ++i) { - out << "g " << (nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl; - } - - _panner->save (); - - return 0; -} - -int -IO::load_automation (const string& path) -{ - string fullpath; - ifstream in; - char line[128]; - uint32_t linecnt = 0; - float version; - LocaleGuard lg (X_("POSIX")); - - fullpath = _session.automation_dir(); - fullpath += path; - - in.open (fullpath.c_str()); - - if (!in) { - fullpath = _session.automation_dir(); - fullpath += _session.snap_name(); - fullpath += '-'; - fullpath += path; - in.open (fullpath.c_str()); - if (!in) { - error << string_compose(_("%1: cannot open automation event file \"%2\" (%2)"), _name, fullpath, strerror (errno)) << endmsg; - return -1; - } - } - - clear_automation (); - - while (in.getline (line, sizeof(line), '\n')) { - char type; - nframes_t when; - double value; - - if (++linecnt == 1) { - if (memcmp (line, "version", 7) == 0) { - if (sscanf (line, "version %f", &version) != 1) { - error << string_compose(_("badly formed version number in automation event file \"%1\""), path) << endmsg; - return -1; - } - } else { - error << string_compose(_("no version information in automation event file \"%1\""), path) << endmsg; - return -1; - } - - if (version != current_automation_version_number) { - error << string_compose(_("mismatched automation event file version (%1)"), version) << endmsg; - return -1; - } - - continue; - } - - if (sscanf (line, "%c %" PRIu32 " %lf", &type, &when, &value) != 3) { - warning << string_compose(_("badly formatted automation event record at line %1 of %2 (ignored)"), linecnt, path) << endmsg; - continue; - } - - switch (type) { - case 'g': - _gain_automation_curve.add (when, value, true); - break; - - case 's': - break; - - case 'm': - break; - - case 'p': - /* older (pre-1.0) versions of ardour used this */ - break; - - default: - warning << _("dubious automation event found (and ignored)") << endmsg; - } - } - - return 0; -} - void IO::clear_automation () { diff --git a/libs/ardour/redirect.cc b/libs/ardour/redirect.cc index e609687662..f414860ec8 100644 --- a/libs/ardour/redirect.cc +++ b/libs/ardour/redirect.cc @@ -109,96 +109,90 @@ Redirect::set_placement (const string& str, void *src) } int -Redirect::load_automation (string path) +Redirect::set_automation_state (const XMLNode& node) { - string fullpath; + /* NODE STRUCTURE - if (path[0] == '/') { // legacy - fullpath = path; - } else { - fullpath = _session.automation_dir(); - fullpath += path; - } - ifstream in (fullpath.c_str()); - - if (!in) { - warning << string_compose(_("%1: cannot open %2 to load automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg; - return 1; - } + + + + X1 Y1 + X2 Y2 + .... + + + + + */ Glib::Mutex::Lock lm (_automation_lock); - set tosave; + parameter_automation.clear (); - while (in) { - double when; - double value; - uint32_t port; + XMLNodeList nlist = node.children(); + XMLNodeIterator niter; - in >> port; if (!in) break; - in >> when; if (!in) goto bad; - in >> value; if (!in) goto bad; - - AutomationList& al = automation_list (port); - al.add (when, value); - tosave.insert (port); + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { + uint32_t param; + + if (sscanf ((*niter)->name().c_str(), "parameter-%" PRIu32, ¶m) != 1) { + error << string_compose (_("%2: badly formatted node name in XML automation state, ignored"), _name) << endmsg; + continue; + } + + AutomationList& al = automation_list (param); + if (al.set_state (*(*niter)->children().front())) { + goto bad; + } } - + return 0; bad: - error << string_compose(_("%1: cannot load automation data from %2"), _name, fullpath) << endmsg; + error << string_compose(_("%1: cannot load automation data from XML"), _name) << endmsg; parameter_automation.clear (); return -1; } -int -Redirect::save_automation (string path) +XMLNode& +Redirect::get_automation_state () { + /* NODE STRUCTURE + + + + + X1 Y1 + X2 Y2 + .... + + + + + */ + Glib::Mutex::Lock lm (_automation_lock); + XMLNode* node = new XMLNode (X_("Automation")); string fullpath; if (parameter_automation.empty()) { - return 1; + return *node; } - fullpath = _session.automation_dir(); - fullpath += path; - - ofstream out (fullpath.c_str()); - - if (!out) { - error << string_compose(_("%1: cannot open %2 to store automation data (%3)"), _name, fullpath, strerror (errno)) << endmsg; - return -1; - } - - AutomationList::const_iterator i; map::iterator li; for (li = parameter_automation.begin(); li != parameter_automation.end(); ++li) { - for (i = (*li).second->begin(); i != (*li).second->end(); ++i) { - - out << (*li).first << ' ' << (*i)->when << ' ' << (*i)->value << endl; - - if (!out) { - break; - } - } + + XMLNode* child; - if (i != (*li).second->end()) { - unlink (fullpath.c_str()); - error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg; - return -1; - } + char buf[64]; + stringstream str; + snprintf (buf, sizeof (buf), "parameter-%" PRIu32, li->first); + child = new XMLNode (buf); + child->add_child_nocopy (li->second->get_state ()); } - if (li != parameter_automation.end()) { - unlink (fullpath.c_str()); - error << string_compose(_("%1: could not save automation state to %2"), _name, fullpath) << endmsg; - return -1; - } - - return 0; + return *node; } XMLNode& @@ -210,7 +204,6 @@ Redirect::get_state (void) XMLNode& Redirect::state (bool full_state) { - char buf[64]; XMLNode* node = new XMLNode (state_node_name); stringstream sstr; @@ -224,38 +217,32 @@ Redirect::state (bool full_state) if (full_state) { - string path; - string legal_name; - - path = _session.snap_name(); - path += "-redirect-"; - id().print (buf, sizeof (buf)); - path += buf; - path += ".automation"; - - /* XXX we didn't ask for a state save, we asked for the current state. - FIX ME! + /* NODE STRUCTURE + + + + + X1 Y1 + X2 Y2 + .... + + + + */ + + XMLNode& automation = get_automation_state(); - switch (save_automation (path)) { - case -1: - error << string_compose(_("Could not get state from Redirect (%1). Problem with save_automation"), _name) << endmsg; - break; - - case 0: - XMLNode *aevents = node->add_child("Automation"); - - for (set::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) { - if (x != visible_parameter_automation.begin()) { - sstr << ' '; - } - sstr << *x; + for (set::iterator x = visible_parameter_automation.begin(); x != visible_parameter_automation.end(); ++x) { + if (x != visible_parameter_automation.begin()) { + sstr << ' '; } - - aevents->add_property ("path", path); - aevents->add_property ("visible", sstr.str()); - break; + sstr << *x; } + + automation.add_property ("visible", sstr.str()); + + node->add_child_nocopy (automation); } return *node; @@ -309,9 +296,9 @@ Redirect::set_state (const XMLNode& node) XMLProperty *prop; if ((prop = (*niter)->property ("path")) != 0) { - load_automation (prop->value()); + warning << string_compose (_("old automation data found for %1, ignored"), _name) << endmsg; } else { - warning << string_compose(_("%1: Automation node has no path property"), _name) << endmsg; + set_automation_state (*(*niter)); } if ((prop = (*niter)->property ("visible")) != 0) { diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 82f1c4b31c..535508bca6 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -1396,26 +1396,6 @@ Route::state(bool full_state) cmt->add_content (_comment); } - if (full_state) { - string path; - - path = _session.snap_name(); - path += "-gain-"; - path += legalize_for_path (_name); - path += ".automation"; - - /* XXX we didn't ask for a state save, we asked for the current state. - FIX ME! - */ - - if (save_automation (path)) { - error << _("Could not get state of route. Problem with save_automation") << endmsg; - } - - aevents = node->add_child ("Automation"); - aevents->add_property ("path", path); - } - for (i = _redirects.begin(); i != _redirects.end(); ++i) { node->add_child_nocopy((*i)->state (full_state)); } @@ -1668,7 +1648,9 @@ Route::set_state (const XMLNode& node) for (piter = plist.begin(); piter != plist.end(); ++piter) { prop = *piter; if (prop->name() == "path") { - load_automation (prop->value()); + warning << string_compose (_("old automation data found for %1, ignored"), _name) << endmsg; + } else { + set_automation_state (*(*piter)); } } diff --git a/libs/ardour/session_click.cc b/libs/ardour/session_click.cc index ba7f7ae811..38cc27be0b 100644 --- a/libs/ardour/session_click.cc +++ b/libs/ardour/session_click.cc @@ -84,8 +84,6 @@ Session::click (nframes_t start, nframes_t nframes, nframes_t offset) } delete points; - - delete points; run_clicks: