update bbe62da55a - use last-modified-with, strip git-rev
[ardour.git] / libs / ardour / session_state.cc
index f82212345d707aa11a7b43fd9be58f6d48ef771a..834f054e0fe9b2800bf731945f45e0a2889bb63a 100644 (file)
@@ -92,7 +92,9 @@
 #include "ardour/filename_extensions.h"
 #include "ardour/graph.h"
 #include "ardour/location.h"
+#ifdef LV2_SUPPORT
 #include "ardour/lv2_plugin.h"
+#endif
 #include "ardour/midi_model.h"
 #include "ardour/midi_patch_manager.h"
 #include "ardour/midi_region.h"
@@ -634,7 +636,7 @@ Session::create (const string& session_template, BusProfile* bus_profile)
 
                /* Initial loop location, from absolute zero, length 10 seconds  */
 
-               Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"),  Location::IsAutoLoop);
+               Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"),  Location::IsAutoLoop, 0);
                _locations->add (loc, true);
                set_auto_loop_location (loc);
        }
@@ -1051,6 +1053,80 @@ Session::get_template()
        return state(false);
 }
 
+typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
+typedef std::set<boost::shared_ptr<Source> > SourceSet;
+
+bool
+Session::export_track_state (boost::shared_ptr<RouteList> 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<std::string> 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> track = boost::dynamic_pointer_cast<Track> (*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<RegionList> 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<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*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)
 {
@@ -1220,7 +1296,7 @@ Session::state (bool full_state)
                Locations loc (*this);
                // for a template, just create a new Locations, populate it
                // with the default start and end, and get the state for that.
-               Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
+               Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
                range->set (max_framepos, 0);
                loc.add (range);
                XMLNode& locations_state = loc.get_state();
@@ -3831,11 +3907,13 @@ Session::config_changed (std::string p, bool ours)
 
        } else if (p == "auto-loop") {
 
+       } else if (p == "session-monitoring") {
+
        } else if (p == "auto-input") {
 
                if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
                        /* auto-input only makes a difference if we're rolling */
-                        set_track_monitor_input_status (!config.get_auto_input());
+                       set_track_monitor_input_status (!config.get_auto_input());
                }
 
        } else if (p == "punch-in") {
@@ -3951,10 +4029,6 @@ Session::config_changed (std::string p, bool ours)
 
                _mmc->enable_send (Config->get_send_mmc ());
 
-       } else if (p == "midi-feedback") {
-
-               session_midi_feedback = Config->get_midi_feedback();
-
        } else if (p == "jack-time-master") {
 
                engine().reset_timebase ();
@@ -4354,68 +4428,82 @@ Session::rename (const std::string& new_name)
 }
 
 int
-Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
+Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
 {
+       bool found_sr = false;
+       bool found_data_format = false;
+       program_version = "";
+
        if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
                return -1;
-        }
+       }
 
-       if (!tree.read (xmlpath)) {
+       xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
+       if (ctxt == NULL) {
                return -1;
        }
+       xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
 
-       return 0;
-}
-
-int
-Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
-{
-       XMLTree tree;
-       bool found_sr = false;
-       bool found_data_format = false;
-
-       if (get_session_info_from_path (tree, xmlpath)) {
+       if (doc == NULL) {
+               xmlFreeParserCtxt(ctxt);
                return -1;
        }
 
-       /* sample rate */
+       xmlNodePtr node = xmlDocGetRootElement(doc);
 
-       XMLProperty const * prop;
-       XMLNode const * root (tree.root());
-
-       if ((prop = root->property (X_("sample-rate"))) != 0) {
-               sample_rate = atoi (prop->value());
-               found_sr = true;
+       if (node == NULL) {
+               xmlFreeParserCtxt(ctxt);
+               xmlFreeDoc (doc);
+               return -1;
        }
 
-       const XMLNodeList& children (root->children());
-       for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
-               const XMLNode* child = *c;
-               if (child->name() == "Config") {
-                       const XMLNodeList& options (child->children());
-                       for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
-                               XMLNode const * option = *oc;
-                               XMLProperty const * name = option->property("name");
-
-                               if (!name) {
-                                       continue;
-                               }
+       /* sample rate */
 
-                               if (name->value() == "native-file-data-format") {
-                                       XMLProperty const * value = option->property ("value");
-                                       if (value) {
-                                               SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
-                                               data_format = fmt;
-                                               found_data_format = true;
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               if (found_data_format) {
-                       break;
-               }
-       }
+       xmlAttrPtr attr;
+       for (attr = node->properties; attr; attr = attr->next) {
+               if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
+                       sample_rate = atoi ((char*)attr->children->content);
+                       found_sr = true;
+               }
+       }
+
+       node = node->children;
+       while (node != NULL) {
+                if (!strcmp((const char*) node->name, "ProgramVersion")) {
+                        xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
+                        if (val) {
+                                program_version = string ((const char*)val);
+                                size_t sep = program_version.find_first_of("-");
+                                if (sep != string::npos) {
+                                        program_version = program_version.substr (0, sep);
+                                }
+                        }
+                        xmlFree (val);
+                }
+                if (strcmp((const char*) node->name, "Config")) {
+                        node = node->next;
+                        continue;
+                }
+                for (node = node->children; node; node = node->next) {
+                        xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
+                        if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
+                                xmlFree (pv);
+                                xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
+                                if (val) {
+                                        SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
+                                        data_format = fmt;
+                                        found_data_format = true;
+                                }
+                                xmlFree (val);
+                                break;
+                        }
+                        xmlFree (pv);
+                }
+                break;
+       }
+
+       xmlFreeParserCtxt(ctxt);
+       xmlFreeDoc (doc);
 
        return !(found_sr && found_data_format); // zero if they are both found
 }
@@ -5075,6 +5163,7 @@ Session::archive_session (const std::string& dest,
        blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
 
        std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
+       std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
 
        set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
        if (only_used_sources) {
@@ -5141,6 +5230,7 @@ Session::archive_session (const std::string& dest,
                        }
 
                        orig_sources[afs] = afs->path();
+                       orig_gain[afs]    = afs->gain();
 
                        std::string new_path = make_new_media_path (afs->path (), to_dir, name);
                        new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
@@ -5153,6 +5243,7 @@ Session::archive_session (const std::string& dest,
                        try {
                                SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
                                afs->replace_file (new_path);
+                               afs->set_gain (ns->gain(), true);
                                delete ns;
                        } catch (...) {
                                cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
@@ -5226,8 +5317,9 @@ Session::archive_session (const std::string& dest,
        /* write session file */
        _path = to_dir;
        g_mkdir_with_parents (externals_dir ().c_str (), 0755);
-
+#ifdef LV2_SUPPORT
        PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
+#endif
        save_state (name);
        save_default_options ();
 
@@ -5279,6 +5371,9 @@ Session::archive_session (const std::string& dest,
        for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
                i->first->replace_file (i->second);
        }
+       for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
+               i->first->set_gain (i->second, true);
+       }
 
        int rv = ar.create (filemap);
        remove_directory (to_dir);