X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_state.cc;h=ee86a40e09d08f4b0c9cf24560d2c03b3d43d67c;hb=b25cd7683b25a502094a2ecefbadb4b7d6e6db09;hp=d27d9636461ed3afd996e8b0205f85e9041330e3;hpb=e25a4371cbc7faca0661bd7d85cef6ab1c2c8e69;p=ardour.git diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index d27d963646..ee86a40e09 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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" @@ -270,6 +272,7 @@ Session::post_engine_init () SndFileSource::setup_standard_crossfades (*this, frame_rate()); _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this)); + _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this)); AudioDiskstream::allocate_working_buffers(); refresh_disk_space (); @@ -633,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); } @@ -1050,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) { @@ -1136,7 +1213,14 @@ Session::state (bool full_state) node->add_child_nocopy (*midi_port_stuff); } - node->add_child_nocopy (config.get_variables ()); + XMLNode& cfgxml (config.get_variables ()); + if (!full_state) { + /* exclude search-paths from template */ + cfgxml.remove_nodes_and_delete ("name", "audio-search-path"); + cfgxml.remove_nodes_and_delete ("name", "midi-search-path"); + cfgxml.remove_nodes_and_delete ("name", "raid-path"); + } + node->add_child_nocopy (cfgxml); node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state()); @@ -1212,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(); @@ -2105,13 +2189,27 @@ Session::load_sources (const XMLNode& node) set_dirty(); for (niter = nlist.begin(); niter != nlist.end(); ++niter) { +#ifdef PLATFORM_WINDOWS + int old_mode = 0; +#endif + retry: try { +#ifdef PLATFORM_WINDOWS + // do not show "insert media" popups (files embedded from removable media). + old_mode = SetErrorMode(SEM_FAILCRITICALERRORS); +#endif if ((source = XMLSourceFactory (**niter)) == 0) { error << _("Session: cannot create Source from XML description.") << endmsg; } +#ifdef PLATFORM_WINDOWS + SetErrorMode(old_mode); +#endif } catch (MissingSource& err) { +#ifdef PLATFORM_WINDOWS + SetErrorMode(old_mode); +#endif int user_choice; @@ -2278,7 +2376,7 @@ Session::save_template (string template_name, bool replace_existing) void Session::refresh_disk_space () { -#if __APPLE__ || __FreeBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H) +#if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H) Glib::Threads::Mutex::Lock lm (space_lock); @@ -2288,10 +2386,15 @@ Session::refresh_disk_space () _total_free_4k_blocks_uncertain = false; for (vector::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) { +#if defined(__NetBSD__) + struct statvfs statfsbuf; + statvfs (i->path.c_str(), &statfsbuf); +#else struct statfs statfsbuf; - statfs (i->path.c_str(), &statfsbuf); + statfs (i->path.c_str(), &statfsbuf); +#endif double const scale = statfsbuf.f_bsize / 4096.0; /* See if this filesystem is read-only */ @@ -2591,6 +2694,25 @@ Session::possible_states () const return possible_states(_path); } +RouteGroup* +Session::new_route_group (const std::string& name) +{ + RouteGroup* rg = NULL; + + for (std::list::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) { + if ((*i)->name () == name) { + rg = *i; + break; + } + } + + if (!rg) { + rg = new RouteGroup (*this, name); + add_route_group (rg); + } + return (rg); +} + void Session::add_route_group (RouteGroup* g) { @@ -3610,6 +3732,11 @@ Session::add_instant_xml (XMLNode& node, bool write_to_config) XMLNode* Session::instant_xml (const string& node_name) { +#ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml + if (get_disable_all_loaded_plugins ()) { + return NULL; + } +#endif return Stateful::instant_xml (node_name, _path); } @@ -3693,7 +3820,7 @@ Session::restore_history (string snapshot_name) // replace history _history.clear(); - for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) { + for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) { XMLNode *t = *it; UndoTransaction* ut = new UndoTransaction (); @@ -3780,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") { @@ -3900,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 (); @@ -4303,68 +4428,78 @@ 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& created_version) { + bool found_sr = false; + bool found_data_format = false; + created_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 */ - - XMLProperty const * prop; - XMLNode const * root (tree.root()); + xmlNodePtr node = xmlDocGetRootElement(doc); - 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*)"created-with"); + if (val) { + created_version = string ((const char*)val); + } + 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 } @@ -5024,6 +5159,7 @@ Session::archive_session (const std::string& dest, blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR); std::map, std::string> orig_sources; + std::map, float> orig_gain; set > sources_used_by_this_snapshot; if (only_used_sources) { @@ -5090,6 +5226,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"); @@ -5102,6 +5239,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"; @@ -5175,8 +5313,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 uw (LV2Plugin::force_state_save, true); +#endif save_state (name); save_default_options (); @@ -5228,6 +5367,9 @@ Session::archive_session (const std::string& dest, for (std::map, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) { i->first->replace_file (i->second); } + for (std::map, 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);