re-apply roll-delay after seek - fixes #5781
[ardour.git] / libs / ardour / session_state.cc
index df2b919c161e834d30e72f37b02696c5fe215414..d09385b8bfac2e6a8fe66c086bb8ca58e4741cf1 100644 (file)
@@ -50,7 +50,7 @@
 #endif
 
 #include <glib.h>
-#include <glib/gstdio.h>
+#include <pbd/gstdio_compat.h>
 
 #include <glibmm.h>
 #include <glibmm/threads.h>
@@ -66,6 +66,7 @@
 #include "pbd/boost_debug.h"
 #include "pbd/basename.h"
 #include "pbd/controllable_descriptor.h"
+#include "pbd/debug.h"
 #include "pbd/enumwriter.h"
 #include "pbd/error.h"
 #include "pbd/file_utils.h"
 #include "ardour/playlist_source.h"
 #include "ardour/port.h"
 #include "ardour/processor.h"
+#include "ardour/profile.h"
 #include "ardour/proxy_controllable.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/region_factory.h"
@@ -128,6 +130,8 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
+#define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
+
 void
 Session::pre_engine_init (string fullpath)
 {
@@ -141,8 +145,18 @@ Session::pre_engine_init (string fullpath)
        _path = canonical_path(fullpath);
 
        /* is it new ? */
+       if (Profile->get_trx() ) {
+               // Waves TracksLive has a usecase of session replacement with a new one.
+               // We should check session state file (<session_name>.ardour) existance
+               // to determine if the session is new or not
 
-       _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+               string full_session_name = Glib::build_filename( fullpath, _name );
+               full_session_name += statefile_suffix;
+               
+               _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+       } else {
+               _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+       }
 
        /* finish initialization that can't be done in a normal C++ constructor
           definition.
@@ -188,8 +202,6 @@ Session::pre_engine_init (string fullpath)
 
        Delivery::disable_panners ();
        IO::disable_connecting ();
-
-       AudioFileSource::set_peak_dir (_session_dir->peak_path());
 }
 
 int
@@ -232,6 +244,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));
                
@@ -269,6 +282,7 @@ Session::post_engine_init ()
                
                Config->map_parameters (ff);
                config.map_parameters (ft);
+                _butler->map_parameters ();
 
                /* Reset all panners */
                
@@ -350,9 +364,44 @@ Session::post_engine_init ()
                state_was_pending = false;
        }
 
+       /* Now, finally, we can fill the playback buffers */
+    
+       BootMessage (_("Filling playback buffers"));
+    
+       boost::shared_ptr<RouteList> rl = routes.reader();
+       for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
+               boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
+               if (trk && !trk->hidden()) {
+                       trk->seek (_transport_frame, true);
+               }
+       }
+
        return 0;
 }
 
+void
+Session::session_loaded ()
+{
+       SessionLoaded();
+       
+       _state_of_the_state = Clean;
+       
+       DirtyChanged (); /* EMIT SIGNAL */
+       
+       if (_is_new) {
+               save_state ("");
+       } else if (state_was_pending) {
+               save_state ("");
+               remove_pending_capture_state ();
+               state_was_pending = false;
+       }
+       
+       /* Now, finally, we can fill the playback buffers */
+       
+       BootMessage (_("Filling playback buffers"));
+       force_locate (_transport_frame, false);
+}
+
 string
 Session::raid_path () const
 {
@@ -489,9 +538,9 @@ Session::create (const string& session_template, BusProfile* bus_profile)
        _writable = exists_and_writable (_path);
 
        if (!session_template.empty()) {
-               std::string in_path = session_template_dir_to_file (session_template);
+               string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
 
-               ifstream in(in_path.c_str());
+               FILE* in = g_fopen (in_path.c_str(), "rb");
 
                if (in) {
                        /* no need to call legalize_for_path() since the string
@@ -499,21 +548,51 @@ Session::create (const string& session_template, BusProfile* bus_profile)
                         */
                        string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
 
-                       ofstream out(out_path.c_str());
+                       FILE* out = g_fopen (out_path.c_str(), "wb");
 
                        if (out) {
-                               out << in.rdbuf();
-                                _is_new = false;
+                               char buf[1024];
+                               stringstream new_session;
 
-                               /* Copy plugin state files from template to new session */
-                               std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
-                               copy_recurse (template_plugins, plugins_dir ());
-                               
+                               while (!feof (in)) {
+                                       size_t charsRead = fread (buf, sizeof(char), 1024, in);
+       
+                                       if (ferror (in)) {
+                                               error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
+                                               fclose (in);
+                                               fclose (out);
+                                               return -1;
+                                       }
+                                       if (charsRead == 0) {
+                                               break;
+                                       }
+                                       new_session.write (buf, charsRead);
+                               }
+                               fclose (in);
+
+                               string file_contents = new_session.str();
+                               size_t writeSize = file_contents.length();
+                               if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
+                                       error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
+                                       fclose (out);
+                                       return -1;
+                               }
+                               fclose (out);
+
+                               _is_new = false;
+
+                               if (!ARDOUR::Profile->get_trx()) {
+                                       /* Copy plugin state files from template to new session */
+                                       std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
+                                       copy_recurse (template_plugins, plugins_dir ());
+                               }
+                                
                                return 0;
 
                        } else {
                                error << string_compose (_("Could not open %1 for writing session template"), out_path)
                                        << endmsg;
+                               fclose(in);
                                return -1;
                        }
 
@@ -525,7 +604,21 @@ Session::create (const string& session_template, BusProfile* bus_profile)
 
        }
 
-       /* set initial start + end point */
+       if (Profile->get_trx()) {
+       
+               /* set initial start + end point : ARDOUR::Session::session_end_shift long.
+                  Remember that this is a brand new session. Sessions
+                  loaded from saved state will get this range from the saved state.
+               */
+               
+               set_session_range_location (0, 0);
+               
+               /* Initial loop location, from absolute zero, length 10 seconds  */
+               
+               Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"),  Location::IsAutoLoop);
+               _locations->add (loc, true);
+               set_auto_loop_location (loc);
+       }
 
        _state_of_the_state = Clean;
 
@@ -536,8 +629,9 @@ Session::create (const string& session_template, BusProfile* bus_profile)
                RouteList rl;
                 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
 
-               if (bus_profile->master_out_channels) {
-                       boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
+                // Waves Tracks: always create master bus for Tracks
+                if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
+                       boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
                         if (r->init ()) {
                                 return -1;
                         }
@@ -561,16 +655,20 @@ Session::create (const string& session_template, BusProfile* bus_profile)
                        add_routes (rl, false, false, false);
                }
 
-                /* this allows the user to override settings with an environment variable.
-                 */
-
-                if (no_auto_connect()) {
-                        bus_profile->input_ac = AutoConnectOption (0);
-                        bus_profile->output_ac = AutoConnectOption (0);
-                }
-
-                Config->set_input_auto_connect (bus_profile->input_ac);
-                Config->set_output_auto_connect (bus_profile->output_ac);
+               // Waves Tracks: Skip this. Always use autoconnection for Tracks
+               if (!ARDOUR::Profile->get_trx()) {
+                       
+                       /* this allows the user to override settings with an environment variable.
+                        */
+                       
+                       if (no_auto_connect()) {
+                               bus_profile->input_ac = AutoConnectOption (0);
+                               bus_profile->output_ac = AutoConnectOption (0);
+                       }
+                       
+                       Config->set_input_auto_connect (bus_profile->input_ac);
+                       Config->set_output_auto_connect (bus_profile->output_ac);
+               }
         }
 
        if (Config->get_use_monitor_bus() && bus_profile) {
@@ -657,7 +755,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 +791,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 +979,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;
 }
@@ -1040,17 +1142,32 @@ Session::state (bool full_state)
                        }
                }
        }
+       
+       
 
        if (full_state) {
-               node->add_child_nocopy (_locations->get_state());
+               
+               if (_locations) {
+                       node->add_child_nocopy (_locations->get_state());       
+               }
        } else {
+               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.
-               Locations loc (*this);
                Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
                range->set (max_framepos, 0);
                loc.add (range);
-               node->add_child_nocopy (loc.get_state());
+               XMLNode& locations_state = loc.get_state();
+               
+               if (ARDOUR::Profile->get_trx() && _locations) {
+                       // For tracks we need stored the Auto Loop Range and all MIDI markers.
+                       for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
+                               if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
+                                       locations_state.add_child_nocopy ((*i)->get_state ());
+                               }
+                       }
+               }
+               node->add_child_nocopy (locations_state);
        }
 
        child = node->add_child ("Bundles");
@@ -1071,12 +1188,12 @@ Session::state (bool full_state)
                RoutePublicOrderSorter cmp;
                RouteList public_order (*r);
                public_order.sort (cmp);
-
-                /* the sort should have put control outs first */
-
-                if (_monitor_out) {
-                        assert (_monitor_out == public_order.front());
-                }
+               
+               /* the sort should have put control outs first */
+               
+               if (_monitor_out) {
+                       assert (_monitor_out == public_order.front());
+               }
 
                for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
                        if (!(*i)->is_auditioner()) {
@@ -1330,7 +1447,7 @@ Session::set_state (const XMLNode& node, int version)
                ControlProtocolManager::instance().set_state (*child, version);
        }
 
-       update_have_rec_enabled_track ();
+       update_route_record_state ();
 
        /* here beginneth the second phase ... */
 
@@ -1376,8 +1493,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 +1965,20 @@ 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) {
+                       _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)
 {
@@ -1960,60 +2095,80 @@ Session::XMLSourceFactory (const XMLNode& node)
 int
 Session::save_template (string template_name)
 {
-       XMLTree tree;
-
-       if (_state_of_the_state & CannotSave) {
+       if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
                return -1;
        }
 
-       std::string user_template_dir(user_template_directory());
+       bool absolute_path = Glib::path_is_absolute (template_name);
 
-       if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
-               error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
-                               user_template_dir, g_strerror (errno)) << endmsg;
-               return -1;
-       }
+       /* directory to put the template in */
+       std::string template_dir_path;
 
-       tree.set_root (&get_template());
+       if (!absolute_path) {
+               std::string user_template_dir(user_template_directory());
 
-       std::string template_dir_path(user_template_dir);
-       
-       /* directory to put the template in */
-       template_dir_path = Glib::build_filename (template_dir_path, template_name);
+               if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
+                       error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
+                                       user_template_dir, g_strerror (errno)) << endmsg;
+                       return -1;
+               }
 
-       if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
-               warning << string_compose(_("Template \"%1\" already exists - new version not created"),
-                               template_dir_path) << endmsg;
-               return -1;
+               template_dir_path = Glib::build_filename (user_template_dir, template_name);
+       } else {
+               template_dir_path = template_name;
        }
-       
-       if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
-               error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
-                               template_dir_path, g_strerror (errno)) << endmsg;
-               return -1;
+
+       if (!ARDOUR::Profile->get_trx()) {
+               if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
+                       warning << string_compose(_("Template \"%1\" already exists - new version not created"),
+                                                                         template_dir_path) << endmsg;
+                       return -1;
+               }
+               
+               if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
+                       error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
+                                                                       template_dir_path, g_strerror (errno)) << endmsg;
+                       return -1;
+               }
        }
 
        /* file to write */
-       std::string template_file_path(template_dir_path);
-       template_file_path = Glib::build_filename (template_file_path, template_name + template_suffix);
+       std::string template_file_path;
+       
+       if (ARDOUR::Profile->get_trx()) {
+               template_file_path = template_name;
+       } else {
+               if (absolute_path) {
+                       template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
+               } else {
+                       template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
+               }
+       }
+
+       SessionSaveUnderway (); /* EMIT SIGNAL */
+       
+       XMLTree tree;
 
+       tree.set_root (&get_template());
        if (!tree.write (template_file_path)) {
                error << _("template not saved") << endmsg;
                return -1;
        }
 
-       /* copy plugin state directory */
+       if (!ARDOUR::Profile->get_trx()) {
+               /* copy plugin state directory */
 
-       std::string template_plugin_state_path(template_dir_path);
-       template_plugin_state_path = Glib::build_filename (template_plugin_state_path, X_("plugins"));
+               std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
 
-       if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
-               error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
-                               template_plugin_state_path, g_strerror (errno)) << endmsg;
-               return -1;
+               if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
+                       error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
+                                                                       template_plugin_state_path, g_strerror (errno)) << endmsg;
+                       return -1;
+               }
+               copy_files (plugins_dir(), template_plugin_state_path);
        }
 
-       copy_recurse (plugins_dir(), template_plugin_state_path);
+       store_recent_templates (template_file_path);
 
        return 0;
 }
@@ -2064,7 +2219,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;
@@ -2216,25 +2371,25 @@ Session::get_best_session_directory_for_new_audio ()
 string
 Session::automation_dir () const
 {
-       return Glib::build_filename (_path, "automation");
+       return Glib::build_filename (_path, automation_dir_name);
 }
 
 string
 Session::analysis_dir () const
 {
-       return Glib::build_filename (_path, "analysis");
+       return Glib::build_filename (_path, analysis_dir_name);
 }
 
 string
 Session::plugins_dir () const
 {
-       return Glib::build_filename (_path, "plugins");
+       return Glib::build_filename (_path, plugins_dir_name);
 }
 
 string
 Session::externals_dir () const
 {
-       return Glib::build_filename (_path, "externals");
+       return Glib::build_filename (_path, externals_dir_name);
 }
 
 int
@@ -2400,6 +2555,16 @@ Session::add_commands (vector<Command*> const & cmds)
        }
 }
 
+void
+Session::add_command (Command* const cmd)
+{
+       assert (_current_trans);
+       DEBUG_UNDO_HISTORY (
+           string_compose ("Current Undo Transaction %1, adding command: %2",
+                           _current_trans->name (),
+                           cmd->name ()));
+       _current_trans->add_command (cmd);
+}
 void
 Session::begin_reversible_command (const string& name)
 {
@@ -2419,15 +2584,35 @@ Session::begin_reversible_command (GQuark q)
        */
 
        if (_current_trans == 0) {
+               DEBUG_UNDO_HISTORY (string_compose (
+                   "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
+
                /* start a new transaction */
                assert (_current_trans_quarks.empty ());
                _current_trans = new UndoTransaction();
                _current_trans->set_name (g_quark_to_string (q));
+       } else {
+               DEBUG_UNDO_HISTORY (
+                   string_compose ("Begin Reversible Command, current transaction: %1",
+                                   _current_trans->name ()));
        }
 
        _current_trans_quarks.push_front (q);
 }
 
+void
+Session::abort_reversible_command ()
+{
+       if (_current_trans != 0) {
+               DEBUG_UNDO_HISTORY (
+                   string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
+               _current_trans->clear();
+               delete _current_trans;
+               _current_trans = 0;
+               _current_trans_quarks.clear();
+       }
+}
+
 void
 Session::commit_reversible_command (Command *cmd)
 {
@@ -2437,18 +2622,34 @@ Session::commit_reversible_command (Command *cmd)
        struct timeval now;
 
        if (cmd) {
+               DEBUG_UNDO_HISTORY (
+                   string_compose ("Current Undo Transaction %1, adding command: %2",
+                                   _current_trans->name (),
+                                   cmd->name ()));
                _current_trans->add_command (cmd);
        }
 
+       DEBUG_UNDO_HISTORY (
+           string_compose ("Commit Reversible Command, current transaction: %1",
+                           _current_trans->name ()));
+
        _current_trans_quarks.pop_front ();
 
        if (!_current_trans_quarks.empty ()) {
+               DEBUG_UNDO_HISTORY (
+                   string_compose ("Commit Reversible Command, transaction is not "
+                                   "top-level, current transaction: %1",
+                                   _current_trans->name ()));
                /* the transaction we're committing is not the top-level one */
                return;
        }
 
        if (_current_trans->empty()) {
                /* no commands were added to the transaction, so just get rid of it */
+               DEBUG_UNDO_HISTORY (
+                   string_compose ("Commit Reversible Command, No commands were "
+                                   "added to current transaction: %1",
+                                   _current_trans->name ()));
                delete _current_trans;
                _current_trans = 0;
                return;
@@ -2616,25 +2817,34 @@ Session::cleanup_regions ()
        bool removed = false;
        const RegionFactory::RegionMap& regions (RegionFactory::regions());
 
-       for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+       for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
 
                uint32_t used = playlists->region_use_count (i->second);
 
                if (used == 0 && !i->second->automatic ()) {
+                       boost::weak_ptr<Region> w = i->second;
+                       ++i;
                        removed = true;
-                       RegionFactory::map_remove (i->second);
+                       RegionFactory::map_remove (w);
+               } else {
+                       ++i;
                }
        }
 
        if (removed) {
                // re-check to remove parent references of compound regions
-               for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+               for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
                        if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
+                               ++i;
                                continue;
                        }
                        assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
                        if (0 == playlists->region_use_count (i->second)) {
-                               RegionFactory::map_remove (i->second);
+                               boost::weak_ptr<Region> w = i->second;
+                               ++i;
+                               RegionFactory::map_remove (w);
+                       } else {
+                               ++i;
                        }
                }
        }
@@ -2645,6 +2855,66 @@ Session::cleanup_regions ()
        save_state ("");
 }
 
+bool
+Session::can_cleanup_peakfiles () const
+{
+       if (deletion_in_progress()) {
+               return false;
+       }
+       if (!_writable || (_state_of_the_state & CannotSave)) {
+               warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
+               return false;
+       }
+        if (record_status() == Recording) {
+               error << _("Cannot cleanup peak-files while recording") << endmsg;
+               return false;
+       }
+       return true;
+}
+
+int
+Session::cleanup_peakfiles ()
+{
+       Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
+       if (!lm.locked()) {
+               return -1;
+       }
+
+       assert (can_cleanup_peakfiles ());
+       assert (!peaks_cleanup_in_progres());
+
+       _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
+
+       int timeout = 5000; // 5 seconds
+       while (!SourceFactory::files_with_peaks.empty()) {
+               Glib::usleep (1000);
+               if (--timeout < 0) {
+                       warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
+                       _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
+                       return -1;
+               }
+       }
+
+       for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
+               boost::shared_ptr<AudioSource> as;
+               if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
+                       as->close_peakfile();
+               }
+       }
+
+       PBD::clear_directory (session_directory().peak_path());
+
+       _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
+
+       for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
+               boost::shared_ptr<AudioSource> as;
+               if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
+                       SourceFactory::setup_peakfile(as, true);
+               }
+       }
+       return 0;
+}
+
 int
 Session::cleanup_sources (CleanupReport& rep)
 {
@@ -2752,6 +3022,17 @@ Session::cleanup_sources (CleanupReport& rep)
                                        */
                                        
                                        RegionFactory::remove_regions_using_source (i->second);
+                                       
+                                       // 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;
+                                               }
+                                       }
+
                                        sources.erase (i);
                                }
                        }
@@ -2861,12 +3142,12 @@ Session::cleanup_sources (CleanupReport& rep)
                /* see if there an easy to find peakfile for this file, and remove it.
                 */
 
-                string base = basename_nosuffix (*x);
+                string base = Glib::path_get_basename (*x);
                 base += "%A"; /* this is what we add for the channel suffix of all native files,
                                  or for the first channel of embedded files. it will miss
                                  some peakfiles for other channels
                               */
-               string peakpath = peak_path (base);
+               string peakpath = construct_peak_filepath (base);
 
                if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
                        if (::g_unlink (peakpath.c_str()) != 0) {
@@ -3045,6 +3326,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;
@@ -3511,6 +3796,8 @@ Session::config_changed (std::string p, bool ours)
                reconnect_ltc_output ();
        } else if (p == "timecode-generator-offset") {
                ltc_tx_parse_offset();
+       } else if (p == "auto-return-target-list") {
+               follow_playhead_priority ();
        }
 
        set_dirty ();
@@ -3595,7 +3882,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 +3892,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
@@ -3615,46 +3913,55 @@ Session::rename (const std::string& new_name, bool after_copy)
         * Backup files are left unchanged and not renamed.
         */
 
+       /* Windows requires that we close all files before attempting the
+        * rename. This works on other platforms, but isn't necessary there.
+        * Leave it in place for all platforms though, since it may help
+        * catch issues that could arise if the way Source files work ever
+        * change (since most developers are not using Windows).
+        */
+
+       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) {
+                       fs->close ();
+               }
+       }
+       
        /* pass one: not 100% safe check that the new directory names don't
         * 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 +3975,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 +4005,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 +4025,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 +4039,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 +4060,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 +4190,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 +4224,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 +4269,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 +4352,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) {
@@ -4028,6 +4370,15 @@ Session::save_as (SaveAs& saveas)
                        
                        find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
                        
+                       /* add dir separator to protect against collisions with
+                        * track names (e.g. track named "audiofiles" or
+                        * "analysis".
+                        */
+
+                       static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
+                       static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
+                       static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
+
                        /* copy all the files. Handling is different for media files
                           than others because of the *silly* subtree we have below the interchange
                           folder. That really was a bad idea, but I'm not fixing it as part of
@@ -4037,33 +4388,66 @@ Session::save_as (SaveAs& saveas)
                        for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
 
                                std::string from = *i;
+
+#ifdef __APPLE__
+                               string filename = Glib::path_get_basename (from);
+                               std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
+                               if (filename == ".DS_STORE") {
+                                       continue;
+                               }
+#endif
                                
-                               if ((*i).find (interchange_dir_name) != string::npos) {
+                               if (from.find (audiofile_dir_string) != string::npos) {
                                        
-                                       /* media file */
+                                       /* audio file: only copy if asked */
 
-                                       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");
+                                                       throw Glib::FileError (Glib::FileError::IO_ERROR,
+                                                                                                  string_compose(_("\ncopying \"%1\" failed !"), from));
                                                }
                                        }
                                        
                                        /* we found media files inside the session folder */
                                        
                                        internal_file_cnt++;
+
+                               } else if (from.find (midifile_dir_string) != string::npos) {
+
+                                       /* midi file: always copy unless
+                                        * creating an empty new session
+                                        */
+
+                                       if (saveas.include_media) {
+                                       
+                                               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");
+                                               }
+                                       }
+
+                                       /* we found media files inside the session folder */
+                                               
+                                       internal_file_cnt++;
+                                       
+                               } else if (from.find (analysis_dir_string) != string::npos) {
+
+                                       /*  make sure analysis dir exists in
+                                        *  new session folder, but we're not
+                                        *  copying analysis files here, see
+                                        *  below 
+                                        */
+                                       
+                                       (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
+                                       continue;
                                        
                                } else {
                                        
@@ -4073,18 +4457,34 @@ Session::save_as (SaveAs& saveas)
                                        bool do_copy = true;
                                        
                                        for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
-                                               if (((*i).length() > (*v).length()) && ((*i).find (*v) == (*i).length() - (*v).length())) {
+                                               if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
                                                        /* end of filename matches extension, do not copy file */
                                                        do_copy = false;
                                                        break;
                                                } 
                                        }
+
+                                       if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
+                                               /* don't copy peakfiles if
+                                                * we're not copying media
+                                                */
+                                               do_copy = false;
+                                       }
                                        
                                        if (do_copy) {
-                                               string to = Glib::build_filename (to_dir, (*i).substr (prefix_len));
+                                               string to = Glib::build_filename (to_dir, from.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");
+                                                       throw Glib::FileError (Glib::FileError::IO_ERROR,
+                                                                                                  string_compose(_("\ncopying \"%1\" failed !"), from));
                                                }
                                        }
                                }
@@ -4095,32 +4495,93 @@ Session::save_as (SaveAs& saveas)
                                */
                                
                                GStatBuf gsb;
-                               g_stat ((*i).c_str(), &gsb);
+                               g_stat (from.c_str(), &gsb);
                                copied += gsb.st_size;
                                cnt++;
                                
                                double fraction = (double) copied / total_bytes;
                                
-                               /* tell someone "X percent, file M of N"; M is one-based */
-                               
-                               boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
                                bool keep_going = true;
 
-                               if (res) {
-                                       keep_going = *res;
+                               if (saveas.copy_media) {
+
+                                       /* no need or expectation of this if
+                                        * media is not being copied, because
+                                        * it will be fast(ish).
+                                        */
+                                       
+                                       /* tell someone "X percent, file M of N"; M is one-based */
+                                       
+                                       boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
+                                       
+                                       if (res) {
+                                               keep_going = *res;
+                                       }
                                }
 
                                if (!keep_going) {
                                        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) {
+#ifndef PLATFORM_WINDOWS
+                               /* There are problems with analysis files on
+                                * Windows, because they used a colon in their
+                                * names as late as 4.0. Colons are not legal
+                                * under Windows even if NTFS allows them.
+                                *
+                                * This is a tricky problem to solve so for
+                                * just don't copy these files. They will be
+                                * regenerated as-needed anyway, subject to the 
+                                * existing issue that the filenames will be
+                                * rejected by Windows, which is a separate
+                                * problem (though related).
+                                */
+
+                               /* 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);
+                               }
+#endif /* PLATFORM_WINDOWS */                          
+                       }
+               }
+                       
+               
                _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,17 +4590,19 @@ 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) {
-                                       ensure_search_path_includes (*s, DataType::MIDI);
-                               }
+                               /* we do not do this for MIDI because we copy
+                                  all MIDI files if saveas.include_media is
+                                  true
+                               */
                        }
                }
                
                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 +4611,10 @@ Session::save_as (SaveAs& saveas)
                        }
                }
 
+               saveas.final_session_folder_name = _path;
+
+               store_recent_sessions (_name, _path);
+               
                if (!saveas.switch_to) {
 
                        /* switch back to the way things were */
@@ -4182,6 +4649,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) {