some more information output to log during save-as, for debugging
[ardour.git] / libs / ardour / session_state.cc
index df2b919c161e834d30e72f37b02696c5fe215414..03acb63f0e0debe3ef368862fe197afe58842ff3 100644 (file)
@@ -232,6 +232,7 @@ Session::post_engine_init ()
        try {
                /* tempo map requires sample rate knowledge */
 
+               delete _tempo_map;
                _tempo_map = new TempoMap (_current_frame_rate);
                _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
                
@@ -657,7 +658,7 @@ Session::remove_state (string snapshot_name)
 
 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
 int
-Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
+Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
 {
        XMLTree tree;
        std::string xml_path(_session_dir->root_path());
@@ -693,9 +694,13 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot
                }
        }
 
-       SaveSession (); /* EMIT SIGNAL */
+       SessionSaveUnderway (); /* EMIT SIGNAL */
 
-       tree.set_root (&get_state());
+       if (template_only) {
+               tree.set_root (&get_template());
+       } else {
+               tree.set_root (&get_state());
+       }
 
        if (snapshot_name.empty()) {
                snapshot_name = _current_snapshot_name;
@@ -877,7 +882,7 @@ Session::load_state (string snapshot_name)
 int
 Session::load_options (const XMLNode& node)
 {
-       LocaleGuard lg (X_("POSIX"));
+       LocaleGuard lg (X_("C"));
        config.set_variables (node);
        return 0;
 }
@@ -1376,8 +1381,12 @@ Session::load_routes (const XMLNode& node, int version)
                new_routes.push_back (route);
        }
 
+       BootMessage (_("Tracks/busses loaded;  Adding to Session"));
+
        add_routes (new_routes, false, false, false);
 
+       BootMessage (_("Finished adding tracks/busses"));
+
        return 0;
 }
 
@@ -1844,6 +1853,22 @@ Session::get_sources_as_xml ()
        return *node;
 }
 
+void
+Session::reset_write_sources (bool mark_write_complete, bool force)
+{
+    boost::shared_ptr<RouteList> rl = routes.reader();
+    for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+        boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+        if (tr) {
+                       
+                       // block state saving
+                       _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
+                       tr->reset_write_sources(mark_write_complete, force);
+                       _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
+        }
+    }
+}
+
 int
 Session::load_sources (const XMLNode& node)
 {
@@ -2064,7 +2089,7 @@ Session::refresh_disk_space ()
                        _total_free_4k_blocks_uncertain = true;
                }
        }
-#elif defined (COMPILER_MSVC)
+#elif defined PLATFORM_WINDOWS
        vector<string> scanned_volumes;
        vector<string>::iterator j;
        vector<space_and_path>::iterator i;
@@ -2428,6 +2453,17 @@ Session::begin_reversible_command (GQuark q)
        _current_trans_quarks.push_front (q);
 }
 
+void
+Session::abort_reversible_command ()
+{
+       if (_current_trans != 0) {
+               _current_trans->clear();
+               delete _current_trans;
+               _current_trans = 0;
+               _current_trans_quarks.clear();
+       }
+}
+
 void
 Session::commit_reversible_command (Command *cmd)
 {
@@ -2753,6 +2789,16 @@ Session::cleanup_sources (CleanupReport& rep)
                                        
                                        RegionFactory::remove_regions_using_source (i->second);
                                        sources.erase (i);
+                                       
+                                       // also remove source from all_sources
+                                       
+                                       for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
+                                               spath = Glib::path_get_basename (*j);
+                                               if ( spath == i->second->name () ) {
+                                                       all_sources.erase (j);
+                                                       break;
+                                               }
+                                       }
                                }
                        }
                }
@@ -3045,6 +3091,10 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc)
                c = r->gain_control ();
                break;
 
+       case ControllableDescriptor::Trim:
+               c = r->trim()->gain_control ();
+               break;
+
        case ControllableDescriptor::Solo:
                 c = r->solo_control();
                break;
@@ -3595,7 +3645,7 @@ Session::solo_cut_control() const
 }
 
 int
-Session::rename (const std::string& new_name, bool after_copy)
+Session::rename (const std::string& new_name)
 {
        string legal_name = legalize_for_path (new_name);
        string new_path;
@@ -3605,6 +3655,17 @@ Session::rename (const std::string& new_name, bool after_copy)
 
        string const old_sources_root = _session_dir->sources_root();
 
+       if (!_writable || (_state_of_the_state & CannotSave)) {
+               error << _("Cannot rename read-only session.") << endmsg;
+               return 0; // don't show "messed up" warning
+       }
+        if (record_status() == Recording) {
+               error << _("Cannot rename session while recording") << endmsg;
+               return 0; // don't show "messed up" warning
+       }
+
+       StateProtector stp (this);
+
        /* Rename:
 
         * session directory
@@ -3619,42 +3680,37 @@ Session::rename (const std::string& new_name, bool after_copy)
         * already exist ...
         */
 
-       if (!after_copy) {
-               for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
-                       
-                       if (first) {
-                               /* primary session directory */
-                               newstr = _path;
-                               first = false;
-                       } else {
-                               oldstr = (*i).path;
-                               
-                               /* this is a stupid hack because Glib::path_get_dirname() is
-                                * lexical-only, and so passing it /a/b/c/ gives a different
-                                * result than passing it /a/b/c ...
-                                */
-                               
-                               if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
-                                       oldstr = oldstr.substr (0, oldstr.length() - 1);
-                               }
-
-                               string base = Glib::path_get_dirname (oldstr);
-                               string p = Glib::path_get_basename (oldstr);
-                               
-                               newstr = Glib::build_filename (base, legal_name);
-                       }
-                       
-                       if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
-                               return -1;
-                       }
+       for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+               
+               oldstr = (*i).path;
+               
+               /* this is a stupid hack because Glib::path_get_dirname() is
+                * lexical-only, and so passing it /a/b/c/ gives a different
+                * result than passing it /a/b/c ...
+                */
+               
+               if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
+                       oldstr = oldstr.substr (0, oldstr.length() - 1);
+               }
+               
+               string base = Glib::path_get_dirname (oldstr);
+               
+               newstr = Glib::build_filename (base, legal_name);
+               
+               cerr << "Looking for " << newstr << endl;
+               
+               if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
+                       cerr << " exists\n";
+                       return -1;
                }
        }
 
        /* Session dirs */
 
-       first = false;
+       first = true;
        
        for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
+
                vector<string> v;
 
                oldstr = (*i).path;
@@ -3668,25 +3724,23 @@ Session::rename (const std::string& new_name, bool after_copy)
                        oldstr = oldstr.substr (0, oldstr.length() - 1);
                }
 
-               if (first) {
-                       newstr = _path;
-               } else {
-                       string base = Glib::path_get_dirname (oldstr);
-                       newstr = Glib::build_filename (base, legal_name);
-               }
+               string base = Glib::path_get_dirname (oldstr);
+               newstr = Glib::build_filename (base, legal_name);
 
-               if (!after_copy) {
-                       cerr << "Rename " << oldstr << " => " << newstr << endl;                
-                       if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
-                               error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
-                               return 1;
-                       }
+               cerr << "for " << oldstr << " new dir = " << newstr << endl;
+               
+               cerr << "Rename " << oldstr << " => " << newstr << endl;                
+               if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
+                       cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
+                       error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
+                       return 1;
                }
 
                /* Reset path in "session dirs" */
                
                (*i).path = newstr;
-
+               (*i).blocks = 0;
+               
                /* reset primary SessionDirectory object */
                
                if (first) {
@@ -3700,8 +3754,10 @@ Session::rename (const std::string& new_name, bool after_copy)
                string old_interchange_dir;
                string new_interchange_dir;
 
-               /* use newstr here because we renamed the path that used to be oldstr to newstr above */                
-
+               /* use newstr here because we renamed the path
+                * (folder/directory) that used to be oldstr to newstr above 
+                */     
+               
                v.push_back (newstr); 
                v.push_back (interchange_dir_name);
                v.push_back (Glib::path_get_basename (oldstr));
@@ -3718,6 +3774,10 @@ Session::rename (const std::string& new_name, bool after_copy)
                cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
                
                if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
+                       cerr << string_compose (_("renaming %s as %2 failed (%3)"),
+                                                old_interchange_dir, new_interchange_dir,
+                                                g_strerror (errno))
+                             << endl;
                        error << string_compose (_("renaming %s as %2 failed (%3)"),
                                                 old_interchange_dir, new_interchange_dir,
                                                 g_strerror (errno))
@@ -3728,13 +3788,14 @@ Session::rename (const std::string& new_name, bool after_copy)
 
        /* state file */
        
-       oldstr = Glib::build_filename (new_path, _current_snapshot_name) + statefile_suffix;
-       newstr= Glib::build_filename (new_path, legal_name) + statefile_suffix;
+       oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
+       newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
        
        cerr << "Rename " << oldstr << " => " << newstr << endl;                
 
        if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
-               error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
+               cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
+               error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
                return 1;
        }
 
@@ -3748,20 +3809,31 @@ Session::rename (const std::string& new_name, bool after_copy)
                cerr << "Rename " << oldstr << " => " << newstr << endl;                
                
                if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
-                       error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
+                       cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
+                       error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
                        return 1;
                }
        }
 
-       if (!after_copy) {
-               /* remove old name from recent sessions */
-               remove_recent_sessions (_path);
-               _path = new_path;
+       /* remove old name from recent sessions */
+       remove_recent_sessions (_path);
+       _path = new_path;
+       
+       /* update file source paths */
+       
+       for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
+               boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
+               if (fs) {
+                       string p = fs->path ();
+                       boost::replace_all (p, old_sources_root, _session_dir->sources_root());
+                       fs->set_path (p);
+                       SourceFactory::setup_peakfile(i->second, true);
+               }
        }
 
        _current_snapshot_name = new_name;
        _name = new_name;
-
+       
        set_dirty ();
 
        /* save state again to get everything just right */
@@ -3867,7 +3939,6 @@ Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,
                        }
                        
                        if (fs->within_session()) {
-                               cerr << "skip " << fs->name() << endl;
                                continue;
                        }
                        
@@ -3902,9 +3973,14 @@ Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,
                                break;
                                
                        case DataType::MIDI:
+                               /* XXX not implemented yet */
                                break;
                        }
                        
+                       if (new_path.empty()) {
+                               continue;
+                       }
+                       
                        cerr << "Move " << old_path << " => " << new_path << endl;
                        
                        if (!copy_file (old_path, new_path)) {
@@ -3942,6 +4018,22 @@ Session::save_as_bring_callback (uint32_t,uint32_t,string)
        */
 }
 
+static string
+make_new_media_path (string old_path, string new_session_folder, string new_session_path)
+{
+       /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
+
+       string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
+       vector<string> v;
+       v.push_back (new_session_folder); /* full path */
+       v.push_back (interchange_dir_name);
+       v.push_back (new_session_path);   /* just one directory/folder */
+       v.push_back (typedir);
+       v.push_back (Glib::path_get_basename (old_path));
+       
+       return Glib::build_filename (v);
+}
+
 int
 Session::save_as (SaveAs& saveas)
 {
@@ -4009,9 +4101,8 @@ Session::save_as (SaveAs& saveas)
        }
 
        try {
-               /* copy all media files. Find each location in
-                * session_dirs, and copy files from there to
-                * target.
+               /* copy all relevant files. Find each location in session_dirs,
+                * and copy files from there to target.
                 */
                
                for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
@@ -4042,19 +4133,11 @@ Session::save_as (SaveAs& saveas)
                                        
                                        /* media file */
 
-                                       if (saveas.copy_media) {
+                                       if (saveas.include_media && saveas.copy_media) {
                                                
-                                               /* typedir is the "midifiles" or "audiofiles" etc. part of the path.
-                                                */
-                                               string typedir = Glib::path_get_basename (Glib::path_get_dirname (*i));
-                                               vector<string> v;
-                                               v.push_back (to_dir);
-                                               v.push_back (interchange_dir_name);
-                                               v.push_back (new_folder);
-                                               v.push_back (typedir);
-                                               v.push_back (Glib::path_get_basename (*i));
-                                               
-                                               std::string to = Glib::build_filename (v);
+                                               string to = make_new_media_path (*i, to_dir, new_folder);
+
+                                               info << "media file copying from " << from << " to " << to << endmsg;
                                                
                                                if (!copy_file (from, to)) {
                                                        throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
@@ -4083,6 +4166,14 @@ Session::save_as (SaveAs& saveas)
                                        if (do_copy) {
                                                string to = Glib::build_filename (to_dir, (*i).substr (prefix_len));
                                                
+                                               info << "attempting to make directory/folder " << to << endmsg;
+
+                                               if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
+                                                       throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
+                                               }
+
+                                               info << "attempting to copy " << from << " to " << to << endmsg;
+                                               
                                                if (!copy_file (from, to)) {
                                                        throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
                                                }
@@ -4114,13 +4205,51 @@ Session::save_as (SaveAs& saveas)
                                        throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
                                }
                        }
+
                }
 
+               /* copy optional folders, if any */
+
+               string old = plugins_dir ();
+               if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
+                       string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
+                       copy_files (old, newdir);
+               }
+
+               old = externals_dir ();
+               if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
+                       string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
+                       copy_files (old, newdir);
+               }
+
+               old = automation_dir ();
+               if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
+                       string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
+                       copy_files (old, newdir);
+               }
+
+               if (saveas.include_media) {
+               
+                       if (saveas.copy_media) {
+                               
+                               /* only needed if we are copying media, since the
+                                * analysis data refers to media data
+                                */
+                               
+                               old = analysis_dir ();
+                               if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
+                                       string newdir = Glib::build_filename (to_dir, "analysis");
+                                       copy_files (old, newdir);
+                               }
+                       }
+               }
+                       
+               
                _path = to_dir;
                _current_snapshot_name = saveas.new_name;
                _name = saveas.new_name;
 
-               if (!saveas.copy_media) {
+               if (saveas.include_media && !saveas.copy_media) {
 
                        /* reset search paths of the new session (which we're pretending to be right now) to
                           include the original session search path, so we can still find all audio.
@@ -4129,6 +4258,7 @@ Session::save_as (SaveAs& saveas)
                        if (internal_file_cnt) {
                                for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
                                        ensure_search_path_includes (*s, DataType::AUDIO);
+                                       cerr << "be sure to include " << *s << "  for audio" << endl;
                                }
 
                                for (vector<string>::iterator s = old_search_path[DataType::MIDI].begin(); s != old_search_path[DataType::MIDI].end(); ++s) {
@@ -4139,7 +4269,7 @@ Session::save_as (SaveAs& saveas)
                
                bool was_dirty = dirty ();
 
-               save_state ("", false, false);
+               save_state ("", false, false, !saveas.include_media);
                save_default_options ();
                
                if (saveas.copy_media && saveas.copy_external) {
@@ -4148,6 +4278,8 @@ Session::save_as (SaveAs& saveas)
                        }
                }
 
+               saveas.final_session_folder_name = _path;
+               
                if (!saveas.switch_to) {
 
                        /* switch back to the way things were */
@@ -4182,6 +4314,23 @@ Session::save_as (SaveAs& saveas)
                        /* ensure that all existing tracks reset their current capture source paths 
                         */
                        reset_write_sources (true, true);
+
+                       /* the copying above was based on actually discovering files, not just iterating over the sources list.
+                          But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
+                       */
+
+                       for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
+                               boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
+
+                               if (!fs) {
+                                       continue;
+                               }
+
+                               if (fs->within_session()) {
+                                       string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
+                                       fs->set_path (newpath);
+                               }
+                       }
                }
 
        } catch (Glib::FileError& e) {