diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 0b1f98e4b1..fbd5412d66 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -563,6 +563,7 @@ class LIBARDOUR_API Session : public PBD::StatefulDestructible, public PBD::Scop XMLNode& get_state(); int set_state(const XMLNode& node, int version); // not idempotent XMLNode& get_template(); + bool export_track_state (boost::shared_ptr rl, const std::string& path); /// The instant xml file is written to the session directory void add_instant_xml (XMLNode&, bool write_to_config = true); diff --git a/libs/ardour/luabindings.cc b/libs/ardour/luabindings.cc index a42aee18d3..d368eff6ca 100644 --- a/libs/ardour/luabindings.cc +++ b/libs/ardour/luabindings.cc @@ -2060,6 +2060,7 @@ LuaBindings::session (lua_State* L) .addFunction ("save_state", &Session::save_state) .addFunction ("set_dirty", &Session::set_dirty) .addFunction ("unknown_processors", &Session::unknown_processors) + .addFunction ("export_track_state", &Session::export_track_state) .addFunction ("new_route_from_template", &Session::new_route_from_template) // TODO session_add_audio_track session_add_midi_track session_add_mixed_track diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 6b16867e59..7cb47c2076 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -2235,7 +2235,6 @@ Route::state(bool full_state) { LocaleGuard lg; if (!_session._template_state_dir.empty()) { - assert (!full_state); // only for templates foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), _session._template_state_dir)); } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 7121326458..bae1f46d01 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -1053,6 +1053,80 @@ Session::get_template() return state(false); } +typedef std::set > PlaylistSet; +typedef std::set > SourceSet; + +bool +Session::export_track_state (boost::shared_ptr rl, const string& path) +{ + if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) { + return false; + } + if (g_mkdir_with_parents (path.c_str(), 0755) != 0) { + return false; + } + + PBD::Unwinder uw (_template_state_dir, path); + + LocaleGuard lg; + XMLNode* node = new XMLNode("TrackState"); // XXX + XMLNode* child; + + PlaylistSet playlists; // SessionPlaylists + SourceSet sources; + + // these will work with new_route_from_template() + // TODO: LV2 plugin-state-dir needs to be relative (on load?) + child = node->add_child ("Routes"); + for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { + if ((*i)->is_auditioner()) { + continue; + } + if ((*i)->is_master() || (*i)->is_monitor()) { + continue; + } + child->add_child_nocopy ((*i)->get_state()); + boost::shared_ptr track = boost::dynamic_pointer_cast (*i); + if (track) { + playlists.insert (track->playlist ()); + } + } + + // on load, Regions in the playlists need to resolve and map Source-IDs + // also playlist needs to be merged or created with new-name.. + // ... and Diskstream in tracks adjusted to use the correct playlist + child = node->add_child ("Playlists"); // SessionPlaylists::add_state + for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) { + child->add_child_nocopy ((*i)->get_state ()); + boost::shared_ptr prl = (*i)->region_list (); + for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) { + const Region::SourceList& sl = (*s)->sources (); + for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) { + sources.insert (*sli); + } + } + } + + child = node->add_child ("Sources"); + for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) { + child->add_child_nocopy ((*i)->get_state ()); + boost::shared_ptr fs = boost::dynamic_pointer_cast (*i); + if (fs) { +#ifdef PLATFORM_WINDOWS + fs->close (); +#endif + string p = fs->path (); + PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p))); + } + } + + std::string sn = Glib::build_filename (path, "share.axml"); + + XMLTree tree; + tree.set_root (node); + return tree.write (sn.c_str()); +} + XMLNode& Session::state (bool full_state) { diff --git a/scripts/_export_tracks.lua b/scripts/_export_tracks.lua new file mode 100644 index 0000000000..7db8dabe84 --- /dev/null +++ b/scripts/_export_tracks.lua @@ -0,0 +1,10 @@ +ardour { ["type"] = "Snippet", name = "Export Track XML" } + +function factory () return function () + local rlp = ARDOUR.RouteListPtr () + local sel = Editor:get_selection () + for r in sel.tracks:routelist ():iter () do + rlp:push_back (r) + end + print (Session:export_track_state (rlp, "/tmp/rexport")) +end end