*** NEW CODING POLICY ***
[ardour.git] / libs / ardour / session.cc
index f870a677dc4859dda37b7cc4a86fa37cb4ca3ab8..51f55cb6b9d50a93901a3687bbc432051f6917e4 100644 (file)
 #include <glibmm/miscutils.h>
 #include <glibmm/fileutils.h>
 
-#include <pbd/error.h>
+#include "pbd/error.h"
 #include <glibmm/thread.h>
-#include <pbd/pathscanner.h>
-#include <pbd/stl_delete.h>
-#include <pbd/basename.h>
-#include <pbd/stacktrace.h>
-#include <pbd/file_utils.h>
-
-#include <ardour/audioengine.h>
-#include <ardour/configuration.h>
-#include <ardour/session.h>
-#include <ardour/session_directory.h>
-#include <ardour/session_metadata.h>
-#include <ardour/utils.h>
-#include <ardour/audio_diskstream.h>
-#include <ardour/audioplaylist.h>
-#include <ardour/audioregion.h>
-#include <ardour/audiofilesource.h>
-#include <ardour/midi_diskstream.h>
-#include <ardour/midi_playlist.h>
-#include <ardour/midi_region.h>
-#include <ardour/smf_source.h>
-#include <ardour/auditioner.h>
-#include <ardour/recent_sessions.h>
-#include <ardour/io_processor.h>
-#include <ardour/send.h>
-#include <ardour/processor.h>
-#include <ardour/plugin_insert.h>
-#include <ardour/port_insert.h>
-#include <ardour/slave.h>
-#include <ardour/tempo.h>
-#include <ardour/audio_track.h>
-#include <ardour/midi_track.h>
-#include <ardour/cycle_timer.h>
-#include <ardour/named_selection.h>
-#include <ardour/crossfade.h>
-#include <ardour/playlist.h>
-#include <ardour/click.h>
-#include <ardour/data_type.h>
-#include <ardour/buffer_set.h>
-#include <ardour/source_factory.h>
-#include <ardour/region_factory.h>
-#include <ardour/filename_extensions.h>
-#include <ardour/session_directory.h>
-#include <ardour/tape_file_matcher.h>
-#include <ardour/analyser.h>
-#include <ardour/audio_buffer.h>
-#include <ardour/bundle.h>
+#include "pbd/pathscanner.h"
+#include "pbd/stl_delete.h"
+#include "pbd/basename.h"
+#include "pbd/stacktrace.h"
+#include "pbd/file_utils.h"
+
+#include "ardour/analyser.h"
+#include "ardour/audio_buffer.h"
+#include "ardour/audio_diskstream.h"
+#include "ardour/audio_track.h"
+#include "ardour/audioengine.h"
+#include "ardour/audiofilesource.h"
+#include "ardour/audioplaylist.h"
+#include "ardour/audioregion.h"
+#include "ardour/auditioner.h"
+#include "ardour/buffer_set.h"
+#include "ardour/bundle.h"
+#include "ardour/click.h"
+#include "ardour/configuration.h"
+#include "ardour/crossfade.h"
+#include "ardour/cycle_timer.h"
+#include "ardour/data_type.h"
+#include "ardour/filename_extensions.h"
+#include "ardour/io_processor.h"
+#include "ardour/midi_diskstream.h"
+#include "ardour/midi_playlist.h"
+#include "ardour/midi_region.h"
+#include "ardour/midi_track.h"
+#include "ardour/named_selection.h"
+#include "ardour/playlist.h"
+#include "ardour/plugin_insert.h"
+#include "ardour/port_insert.h"
+#include "ardour/processor.h"
+#include "ardour/recent_sessions.h"
+#include "ardour/region_factory.h"
+#include "ardour/route_group.h"
+#include "ardour/send.h"
+#include "ardour/session.h"
+#include "ardour/session_directory.h"
+#include "ardour/session_directory.h"
+#include "ardour/session_metadata.h"
+#include "ardour/slave.h"
+#include "ardour/smf_source.h"
+#include "ardour/source_factory.h"
+#include "ardour/tape_file_matcher.h"
+#include "ardour/tempo.h"
+#include "ardour/utils.h"
 
 #include "i18n.h"
 
@@ -117,6 +118,7 @@ Session::Session (AudioEngine &eng,
                  string mix_template)
 
        : _engine (eng),
+         _requested_return_frame (-1),
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
          _mix_buffers(new BufferSet()),
@@ -138,6 +140,7 @@ Session::Session (AudioEngine &eng,
          routes (new RouteList),
          auditioner ((Auditioner*) 0),
          _total_free_4k_blocks (0),
+         _bundles (new BundleList),
          _bundle_xml_node (0),
          _click_io ((IO*) 0),
          click_data (0),
@@ -198,6 +201,7 @@ Session::Session (AudioEngine &eng,
                  nframes_t initial_length)
 
        : _engine (eng),
+         _requested_return_frame (-1),
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
          _mix_buffers(new BufferSet()),
@@ -219,6 +223,7 @@ Session::Session (AudioEngine &eng,
          routes (new RouteList),
          auditioner ((Auditioner *) 0),
          _total_free_4k_blocks (0),
+         _bundles (new BundleList),
          _bundle_xml_node (0),
          _click_io ((IO *) 0),
          click_data (0),
@@ -589,7 +594,11 @@ Session::when_engine_running ()
        BootMessage (_("Set up standard connections"));
 
        /* Create a set of Bundle objects that map
-          to the physical I/O currently available */
+          to the physical I/O currently available.  We create both
+          mono and stereo bundles, so that the common cases of mono
+          and stereo tracks get bundles to put in their mixer strip
+          in / out menus.  There may be a nicer way of achieving that;
+          it doesn't really scale that well to higher channel counts */
 
        for (uint32_t np = 0; np < n_physical_outputs; ++np) {
                char buf[32];
@@ -602,6 +611,20 @@ Session::when_engine_running ()
                add_bundle (c);
        }
 
+       for (uint32_t np = 0; np < n_physical_outputs; np += 2) {
+               if (np + 1 < n_physical_outputs) {
+                       char buf[32];
+                       snprintf (buf, sizeof(buf), _("out %" PRIu32 "+%" PRIu32), np + 1, np + 2);
+                       shared_ptr<Bundle> c (new Bundle (buf, true));
+                       c->add_channel (_("L"));
+                       c->set_port (0, _engine.get_nth_physical_output (DataType::AUDIO, np));
+                       c->add_channel (_("R"));
+                       c->set_port (1, _engine.get_nth_physical_output (DataType::AUDIO, np + 1));
+
+                       add_bundle (c);
+               }
+       }
+
        for (uint32_t np = 0; np < n_physical_inputs; ++np) {
                char buf[32];
                snprintf (buf, sizeof (buf), _("in %" PRIu32), np+1);
@@ -613,6 +636,21 @@ Session::when_engine_running ()
                add_bundle (c);
        }
 
+       for (uint32_t np = 0; np < n_physical_inputs; np += 2) {
+               if (np + 1 < n_physical_inputs) {
+                       char buf[32];
+                       snprintf (buf, sizeof(buf), _("in %" PRIu32 "+%" PRIu32), np + 1, np + 2);
+
+                       shared_ptr<Bundle> c (new Bundle (buf, false));
+                       c->add_channel (_("L"));
+                       c->set_port (0, _engine.get_nth_physical_input (DataType::AUDIO, np));
+                       c->add_channel (_("R"));
+                       c->set_port (1, _engine.get_nth_physical_input (DataType::AUDIO, np + 1));
+
+                       add_bundle (c);
+               }
+       }
+
        if (_master_out) {
 
                /* create master/control ports */
@@ -1170,10 +1208,6 @@ Session::audible_frame () const
        nframes_t offset;
        nframes_t tf;
 
-       if (_transport_speed == 0.0f && non_realtime_work_pending()) {
-               return last_stop_frame;
-       }
-
        /* the first of these two possible settings for "offset"
           mean that the audible frame is stationary until
           audio emerges from the latency compensation
@@ -1210,17 +1244,16 @@ Session::audible_frame () const
                /* MOVING */
 
                /* check to see if we have passed the first guaranteed
-                  audible frame past our last stopping position. if not,
-                  the return that last stopping point because in terms
+                  audible frame past our last start position. if not,
+                  return that last start point because in terms
                   of audible frames, we have not moved yet.
                */
 
                if (_transport_speed > 0.0f) {
 
                        if (!play_loop || !have_looped) {
-                               if (tf < last_stop_frame + offset) {
-                                       return last_stop_frame;
-                                       
+                               if (tf < _last_roll_location + offset) {
+                                       return _last_roll_location;
                                }
                        } 
                        
@@ -1232,8 +1265,8 @@ Session::audible_frame () const
 
                        /* XXX wot? no backward looping? */
 
-                       if (tf > last_stop_frame - offset) {
-                               return last_stop_frame;
+                       if (tf > _last_roll_location - offset) {
+                               return _last_roll_location;
                        } else {
                                /* backwards */
                                ret += offset;
@@ -1820,7 +1853,7 @@ Session::set_remote_control_ids ()
 }
 
 
-Session::RouteList
+RouteList
 Session::new_audio_route (int input_channels, int output_channels, uint32_t how_many)
 {
        char bus_name[32];
@@ -2501,7 +2534,9 @@ Session::region_name (string& result, string base, bool newlevel)
        char buf[16];
        string subbase;
 
-       assert(base.find("/") == string::npos);
+       if (base.find("/") != string::npos) {
+               base = base.substr(base.find_last_of("/") + 1);
+       }
 
        if (base == "") {
 
@@ -2809,6 +2844,7 @@ Session::remove_region_from_region_list (boost::shared_ptr<Region> r)
 }
 
 /* Source Management */
+
 void
 Session::add_source (boost::shared_ptr<Source> source)
 {
@@ -2879,7 +2915,6 @@ Session::source_by_id (const PBD::ID& id)
        return source;
 }
 
-
 boost::shared_ptr<Source>
 Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
 {
@@ -2887,26 +2922,19 @@ Session::source_by_path_and_channel (const Glib::ustring& path, uint16_t chn)
 
        for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
                cerr << "comparing " << path << " with " << i->second->name() << endl;
-               boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(i->second);
+               boost::shared_ptr<AudioFileSource> afs
+                       = boost::dynamic_pointer_cast<AudioFileSource>(i->second);
 
                if (afs && afs->path() == path && chn == afs->channel()) {
                        return afs;
                }
-
        }
        return boost::shared_ptr<Source>();
 }
 
-Glib::ustring
-Session::peak_path (Glib::ustring base) const
-{
-       sys::path peakfile_path(_session_dir->peak_path());
-       peakfile_path /= basename_nosuffix (base) + peakfile_suffix;
-       return peakfile_path.to_string();
-}
 
 string
-Session::change_audio_path_by_name (string path, string oldname, string newname, bool destructive)
+Session::change_source_path_by_name (string path, string oldname, string newname, bool destructive)
 {
        string look_for;
        string old_basename = PBD::basename_nosuffix (oldname);
@@ -2954,7 +2982,7 @@ Session::change_audio_path_by_name (string path, string oldname, string newname,
 
                /* non-destructive file sources have a name of the form:
 
-                   /path/to/NAME-nnnnn(%[LR])?.wav
+                   /path/to/NAME-nnnnn(%[LR])?.ext
 
                    the task here is to replace NAME with the new name.
                */
@@ -2992,7 +3020,7 @@ Session::change_audio_path_by_name (string path, string oldname, string newname,
                if (postfix != string::npos) {
                        suffix = suffix.substr (postfix);
                } else {
-                       error << "Logic error in Session::change_audio_path_by_name(), please report to the developers" << endl;
+                       error << "Logic error in Session::change_source_path_by_name(), please report" << endl;
                        return "";
                }
 
@@ -3019,8 +3047,42 @@ Session::change_audio_path_by_name (string path, string oldname, string newname,
        return path;
 }
 
+/** Return the full path (in some session directory) for a new embedded source.
+ * \a name must be a session-unique name that does not contain slashes
+ *         (e.g. as returned by new_*_source_name)
+ */
 string
-Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool destructive)
+Session::new_source_path_from_name (DataType type, const string& name)
+{
+       assert(name.find("/") == string::npos);
+
+       SessionDirectory sdir(get_best_session_directory_for_new_source());
+
+       sys::path p;
+       if (type == DataType::AUDIO) {
+               p = sdir.sound_path();
+       } else if (type == DataType::MIDI) {
+               p = sdir.midi_path();
+       } else {
+               error << "Unknown source type, unable to create file path" << endmsg;
+               return "";
+       }
+
+       p /= name;
+       return p.to_string();
+}
+
+Glib::ustring
+Session::peak_path (Glib::ustring base) const
+{
+       sys::path peakfile_path(_session_dir->peak_path());
+       peakfile_path /= basename_nosuffix (base) + peakfile_suffix;
+       return peakfile_path.to_string();
+}
+
+/** Return a unique name based on \a base for a new internal audio source */
+string
+Session::new_audio_source_name (const string& base, uint32_t nchan, uint32_t chan, bool destructive)
 {
        string spath;
        uint32_t cnt;
@@ -3029,12 +3091,9 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
        string legalized;
 
        buf[0] = '\0';
-       legalized = legalize_for_path (name);
-
-       /* find a "version" of the file name that doesn't exist in
-          any of the possible directories.
-       */
+       legalized = legalize_for_path (base);
 
+       // Find a "version" of the base name that doesn't exist in any of the possible directories.
        for (cnt = (destructive ? ++destructive_index : 1); cnt <= limit; ++cnt) {
 
                vector<space_and_path>::iterator i;
@@ -3047,18 +3106,24 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
                        spath = sdir.sound_path().to_string();
 
                        if (destructive) {
+
                                if (nchan < 2) {
-                                       snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", spath.c_str(), cnt, legalized.c_str());
+                                       snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav",
+                                                       spath.c_str(), cnt, legalized.c_str());
                                } else if (nchan == 2) {
                                        if (chan == 0) {
-                                               snprintf (buf, sizeof(buf), "%s/T%04d-%s%%L.wav", spath.c_str(), cnt, legalized.c_str());
+                                               snprintf (buf, sizeof(buf), "%s/T%04d-%s%%L.wav",
+                                                               spath.c_str(), cnt, legalized.c_str());
                                        } else {
-                                               snprintf (buf, sizeof(buf), "%s/T%04d-%s%%R.wav", spath.c_str(), cnt, legalized.c_str());
+                                               snprintf (buf, sizeof(buf), "%s/T%04d-%s%%R.wav",
+                                                               spath.c_str(), cnt, legalized.c_str());
                                        }
                                } else if (nchan < 26) {
-                                       snprintf (buf, sizeof(buf), "%s/T%04d-%s%%%c.wav", spath.c_str(), cnt, legalized.c_str(), 'a' + chan);
+                                       snprintf (buf, sizeof(buf), "%s/T%04d-%s%%%c.wav",
+                                                       spath.c_str(), cnt, legalized.c_str(), 'a' + chan);
                                } else {
-                                       snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav", spath.c_str(), cnt, legalized.c_str());
+                                       snprintf (buf, sizeof(buf), "%s/T%04d-%s.wav",
+                                                       spath.c_str(), cnt, legalized.c_str());
                                }
 
                        } else {
@@ -3092,173 +3157,42 @@ Session::audio_path_from_name (string name, uint32_t nchan, uint32_t chan, bool
                }
 
                if (cnt > limit) {
-                       error << string_compose(_("There are already %1 recordings for %2, which I consider too many."), limit, name) << endmsg;
+                       error << string_compose(
+                                       _("There are already %1 recordings for %2, which I consider too many."),
+                                       limit, base) << endmsg;
                        destroy ();
                        throw failed_constructor();
                }
        }
 
-       /* we now have a unique name for the file, but figure out where to
-          actually put it.
-       */
-
-       string foo = buf;
-
-       SessionDirectory sdir(get_best_session_directory_for_new_source ());
-
-       spath = sdir.sound_path().to_string();
-       spath += '/';
-
-       string::size_type pos = foo.find_last_of ('/');
-
-       if (pos == string::npos) {
-               spath += foo;
-       } else {
-               spath += foo.substr (pos + 1);
-       }
-
-       return spath;
+       return Glib::path_get_basename(buf);
 }
 
+/** Create a new embedded audio source */
 boost::shared_ptr<AudioFileSource>
 Session::create_audio_source_for_session (AudioDiskstream& ds, uint32_t chan, bool destructive)
 {
-       string spath = audio_path_from_name (ds.name(), ds.n_channels().n_audio(), chan, destructive);
+       const size_t n_chans = ds.n_channels().n_audio();
+       const string name    = new_audio_source_name (ds.name(), n_chans, chan, destructive);
+       const string path    = new_source_path_from_name(DataType::AUDIO, name);
        return boost::dynamic_pointer_cast<AudioFileSource> (
-               SourceFactory::createWritable (DataType::AUDIO, *this, spath, destructive, frame_rate()));
+                       SourceFactory::createWritable (
+                                       DataType::AUDIO, *this, path, true, destructive, frame_rate()));
 }
 
-// FIXME: _terrible_ code duplication
+/** Return a unique name based on \a base for a new internal MIDI source */
 string
-Session::change_midi_path_by_name (string path, string oldname, string newname, bool destructive)
+Session::new_midi_source_name (const string& base)
 {
-       string look_for;
-       string old_basename = PBD::basename_nosuffix (oldname);
-       string new_legalized = legalize_for_path (newname);
-
-       /* note: we know (or assume) the old path is already valid */
-
-       if (destructive) {
-
-               /* destructive file sources have a name of the form:
-
-                   /path/to/Tnnnn-NAME(%[LR])?.wav
-
-                   the task here is to replace NAME with the new name.
-               */
-
-               /* find last slash */
-
-               string dir;
-               string prefix;
-               string::size_type slash;
-               string::size_type dash;
-
-               if ((slash = path.find_last_of ('/')) == string::npos) {
-                       return "";
-               }
-
-               dir = path.substr (0, slash+1);
-
-               /* '-' is not a legal character for the NAME part of the path */
-
-               if ((dash = path.find_last_of ('-')) == string::npos) {
-                       return "";
-               }
-
-               prefix = path.substr (slash+1, dash-(slash+1));
-
-               path = dir;
-               path += prefix;
-               path += '-';
-               path += new_legalized;
-               path += ".mid";  /* XXX gag me with a spoon */
-
-       } else {
-
-               /* non-destructive file sources have a name of the form:
-
-                   /path/to/NAME-nnnnn(%[LR])?.wav
-
-                   the task here is to replace NAME with the new name.
-               */
-
-               string dir;
-               string suffix;
-               string::size_type slash;
-               string::size_type dash;
-               string::size_type postfix;
-
-               /* find last slash */
-
-               if ((slash = path.find_last_of ('/')) == string::npos) {
-                       return "";
-               }
-
-               dir = path.substr (0, slash+1);
-
-               /* '-' is not a legal character for the NAME part of the path */
-
-               if ((dash = path.find_last_of ('-')) == string::npos) {
-                       return "";
-               }
-
-               suffix = path.substr (dash+1);
-
-               // Suffix is now everything after the dash. Now we need to eliminate
-               // the nnnnn part, which is done by either finding a '%' or a '.'
-
-               postfix = suffix.find_last_of ("%");
-               if (postfix == string::npos) {
-                       postfix = suffix.find_last_of ('.');
-               }
-
-               if (postfix != string::npos) {
-                       suffix = suffix.substr (postfix);
-               } else {
-                       error << "Logic error in Session::change_midi_path_by_name(), please report to the developers" << endl;
-                       return "";
-               }
-
-               const uint32_t limit = 10000;
-               char buf[PATH_MAX+1];
-
-               for (uint32_t cnt = 1; cnt <= limit; ++cnt) {
-
-                       snprintf (buf, sizeof(buf), "%s%s-%u%s", dir.c_str(), newname.c_str(), cnt, suffix.c_str());
-
-                       if (access (buf, F_OK) != 0) {
-                               path = buf;
-                               break;
-                       }
-                       path = "";
-               }
-
-               if (path == "") {
-                       error << "FATAL ERROR! Could not find a " << endl;
-               }
-
-       }
-
-       return path;
-}
-
-string
-Session::midi_path_from_name (string name)
-{
-       string spath;
        uint32_t cnt;
        char buf[PATH_MAX+1];
        const uint32_t limit = 10000;
        string legalized;
 
        buf[0] = '\0';
-       legalized = legalize_for_path (name);
-
-       /* find a "version" of the file name that doesn't exist in
-          any of the possible directories.
-       */
+       legalized = legalize_for_path (base);
 
+       // Find a "version" of the file name that doesn't exist in any of the possible directories.
        for (cnt = 1; cnt <= limit; ++cnt) {
 
                vector<space_and_path>::iterator i;
@@ -3269,12 +3203,9 @@ Session::midi_path_from_name (string name)
                        SessionDirectory sdir((*i).path);
 
                        sys::path p = sdir.midi_path();
-
                        p /= legalized;
 
-                       spath = p.to_string();
-
-                       snprintf (buf, sizeof(buf), "%s-%u.mid", spath.c_str(), cnt);
+                       snprintf (buf, sizeof(buf), "%s-%u.mid", p.to_string().c_str(), cnt);
 
                        if (sys::exists (buf)) {
                                existing++;
@@ -3286,39 +3217,28 @@ Session::midi_path_from_name (string name)
                }
 
                if (cnt > limit) {
-                       error << string_compose(_("There are already %1 recordings for %2, which I consider too many."), limit, name) << endmsg;
+                       error << string_compose(
+                                       _("There are already %1 recordings for %2, which I consider too many."),
+                                       limit, base) << endmsg;
+                       destroy ();
                        throw failed_constructor();
                }
        }
 
-       /* we now have a unique name for the file, but figure out where to
-          actually put it.
-       */
-
-       string foo = buf;
-
-       SessionDirectory sdir(get_best_session_directory_for_new_source ());
-
-       spath = sdir.midi_path().to_string();
-       spath += '/';
-
-       string::size_type pos = foo.find_last_of ('/');
-
-       if (pos == string::npos) {
-               spath += foo;
-       } else {
-               spath += foo.substr (pos + 1);
-       }
-
-       return spath;
+       return Glib::path_get_basename(buf);
 }
 
+
+/** Create a new embedded MIDI source */
 boost::shared_ptr<MidiSource>
 Session::create_midi_source_for_session (MidiDiskstream& ds)
 {
-       string mpath = midi_path_from_name (ds.name());
+       const string name = new_midi_source_name (ds.name());
+       const string path = new_source_path_from_name (DataType::MIDI, name);
 
-       return boost::dynamic_pointer_cast<SMFSource> (SourceFactory::createWritable (DataType::MIDI, *this, mpath, false, frame_rate()));
+       return boost::dynamic_pointer_cast<SMFSource> (
+                       SourceFactory::createWritable (
+                                       DataType::MIDI, *this, path, true, false, frame_rate()));
 }
 
 
@@ -3761,8 +3681,9 @@ void
 Session::add_bundle (shared_ptr<Bundle> bundle)
 {
        {
-               Glib::Mutex::Lock guard (bundle_lock);
-               _bundles.push_back (bundle);
+               RCUWriter<BundleList> writer (_bundles);
+               boost::shared_ptr<BundleList> b = writer.get_copy ();
+               b->push_back (bundle);
        }
 
        BundleAdded (bundle); /* EMIT SIGNAL */
@@ -3776,11 +3697,12 @@ Session::remove_bundle (shared_ptr<Bundle> bundle)
        bool removed = false;
 
        {
-               Glib::Mutex::Lock guard (bundle_lock);
-               BundleList::iterator i = find (_bundles.begin(), _bundles.end(), bundle);
+               RCUWriter<BundleList> writer (_bundles);
+               boost::shared_ptr<BundleList> b = writer.get_copy ();
+               BundleList::iterator i = find (b->begin(), b->end(), bundle);
 
-               if (i != _bundles.end()) {
-                       _bundles.erase (i);
+               if (i != b->end()) {
+                       b->erase (i);
                        removed = true;
                }
        }
@@ -3795,9 +3717,9 @@ Session::remove_bundle (shared_ptr<Bundle> bundle)
 shared_ptr<Bundle>
 Session::bundle_by_name (string name) const
 {
-       Glib::Mutex::Lock lm (bundle_lock);
-
-       for (BundleList::const_iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
+       boost::shared_ptr<BundleList> b = _bundles.reader ();
+       
+       for (BundleList::const_iterator i = b->begin(); i != b->end(); ++i) {
                if ((*i)->name() == name) {
                        return* i;
                }
@@ -4095,7 +4017,7 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
 
                try {
                        fsource = boost::dynamic_pointer_cast<AudioFileSource> (
-                               SourceFactory::createWritable (DataType::AUDIO, *this, buf, false, frame_rate()));
+                               SourceFactory::createWritable (DataType::AUDIO, *this, buf, true, false, frame_rate()));
                }
 
                catch (failed_constructor& err) {
@@ -4165,8 +4087,9 @@ Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,
 
                /* construct a region to represent the bounced material */
 
-               result = RegionFactory::create (srcs, 0, srcs.front()->length(), 
-                                               region_name_from_path (srcs.front()->name(), true));
+               result = RegionFactory::create (srcs, 0,
+                               srcs.front()->length(srcs.front()->timeline_position()), 
+                               region_name_from_path (srcs.front()->name(), true));
        }
 
   out:
@@ -4290,12 +4213,4 @@ Session::sync_order_keys (const char* base)
        Route::SyncOrderKeys (base); // EMIT SIGNAL
 }
 
-void
-Session::foreach_bundle (sigc::slot<void, boost::shared_ptr<Bundle> > sl)
-{
-       Glib::Mutex::Lock lm (bundle_lock);
-       for (BundleList::iterator i = _bundles.begin(); i != _bundles.end(); ++i) {
-               sl (*i);
-       }
-}