Remove unnecessary 0 checks before delete; see http://www.parashift.com/c++-faq-lite...
[ardour.git] / libs / ardour / session.cc
index 1124b8960fbadc3e28b01aff867155219129642c..8efef136d1e1abf1802f7bcc70a646aa0c80179a 100644 (file)
@@ -47,6 +47,7 @@
 #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>
@@ -101,12 +102,6 @@ static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it mat
 
 bool Session::_disable_all_loaded_plugins = false;
 
-Session::compute_peak_t          Session::compute_peak          = 0;
-Session::find_peaks_t            Session::find_peaks            = 0;
-Session::apply_gain_to_buffer_t  Session::apply_gain_to_buffer  = 0;
-Session::mix_buffers_with_gain_t Session::mix_buffers_with_gain = 0;
-Session::mix_buffers_no_gain_t   Session::mix_buffers_no_gain   = 0;
-
 sigc::signal<void,std::string> Session::Dialog;
 sigc::signal<int> Session::AskAboutPendingState;
 sigc::signal<int,nframes_t,nframes_t> Session::AskAboutSampleRateMismatch;
@@ -115,9 +110,9 @@ sigc::signal<void> Session::SendFeedback;
 sigc::signal<void> Session::SMPTEOffsetChanged;
 sigc::signal<void> Session::StartTimeChanged;
 sigc::signal<void> Session::EndTimeChanged;
-
 sigc::signal<void> Session::AutoBindingOn;
 sigc::signal<void> Session::AutoBindingOff;
+sigc::signal<void, std::string, std::string> Session::Exported;
 
 Session::Session (AudioEngine &eng,
                  const string& fullpath,
@@ -128,21 +123,31 @@ Session::Session (AudioEngine &eng,
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
          _mix_buffers(new BufferSet()),
+         mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
          _midi_port (default_midi_port),
          _midi_clock_port (default_midi_clock_port),
          _session_dir (new SessionDirectory(fullpath)),
          pending_events (2048),
+         state_tree (0),
+         butler_mixdown_buffer (0),
+         butler_gain_buffer (0),
          post_transport_work((PostTransportWork)0),
          _send_smpte_update (false),
-         midi_requests (128),
+         midi_thread (pthread_t (0)),
+         midi_requests (128), // the size of this should match the midi request pool size
          diskstreams (new DiskstreamList),
          routes (new RouteList),
          auditioner ((Auditioner*) 0),
+         _total_free_4k_blocks (0),
          _bundle_xml_node (0),
          _click_io ((IO*) 0),
-         main_outs (0)
+         click_data (0),
+         click_emphasis_data (0),
+         main_outs (0),
+         _metadata (new SessionMetadata())
+
 {
        bool new_session;
 
@@ -152,8 +157,8 @@ Session::Session (AudioEngine &eng,
 
        cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (1)" << endl;
 
-       n_physical_outputs = _engine.n_physical_outputs();
-       n_physical_inputs =  _engine.n_physical_inputs();
+       n_physical_outputs = _engine.n_physical_outputs(DataType::AUDIO);
+       n_physical_inputs =  _engine.n_physical_inputs(DataType::AUDIO);
 
        first_stage_init (fullpath, snapshot_name);
 
@@ -199,20 +204,30 @@ Session::Session (AudioEngine &eng,
          _scratch_buffers(new BufferSet()),
          _silent_buffers(new BufferSet()),
          _mix_buffers(new BufferSet()),
+         mmc (0),
          _mmc_port (default_mmc_port),
          _mtc_port (default_mtc_port),
          _midi_port (default_midi_port),
          _midi_clock_port (default_midi_clock_port),
          _session_dir ( new SessionDirectory(fullpath)),
          pending_events (2048),
+         state_tree (0),
+         butler_mixdown_buffer (0),
+         butler_gain_buffer (0),
          post_transport_work((PostTransportWork)0),
          _send_smpte_update (false),
+         midi_thread (pthread_t (0)),
          midi_requests (16),
          diskstreams (new DiskstreamList),
          routes (new RouteList),
+         auditioner ((Auditioner *) 0),
+         _total_free_4k_blocks (0),
          _bundle_xml_node (0),
-         main_outs (0)
-
+         _click_io ((IO *) 0),
+         click_data (0),
+         click_emphasis_data (0),
+         main_outs (0),
+         _metadata (new SessionMetadata())
 {
        bool new_session;
 
@@ -222,8 +237,8 @@ Session::Session (AudioEngine &eng,
 
        cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
 
-       n_physical_outputs = _engine.n_physical_outputs();
-       n_physical_inputs = _engine.n_physical_inputs();
+       n_physical_outputs = _engine.n_physical_outputs (DataType::AUDIO);
+       n_physical_inputs = _engine.n_physical_inputs (DataType::AUDIO);
 
        if (n_physical_inputs) {
                n_physical_inputs = max (requested_physical_in, n_physical_inputs);
@@ -318,18 +333,16 @@ Session::destroy ()
 
        /* clear state tree so that no references to objects are held any more */
 
-       if (state_tree) {
-               delete state_tree;
-       }
+       delete state_tree;
 
        terminate_butler_thread ();
        //terminate_midi_thread ();
 
-       if (click_data && click_data != default_click) {
+       if (click_data != default_click) {
                delete [] click_data;
        }
 
-       if (click_emphasis_data && click_emphasis_data != default_click_emphasis) {
+       if (click_emphasis_data != default_click_emphasis) {
                delete [] click_emphasis_data;
        }
 
@@ -473,19 +486,12 @@ Session::destroy ()
                i = tmp;
        }
 
-       if (butler_mixdown_buffer) {
-               delete [] butler_mixdown_buffer;
-       }
-
-       if (butler_gain_buffer) {
-               delete [] butler_gain_buffer;
-       }
+       delete [] butler_mixdown_buffer;
+       delete [] butler_gain_buffer;
 
        Crossfade::set_buffer_size (0);
 
-       if (mmc) {
-               delete mmc;
-       }
+       delete mmc;
 }
 
 void
@@ -1086,6 +1092,12 @@ Session::handle_locations_changed (Locations::LocationList& locations)
                        set_loop = true;
                }
 
+               if (location->is_start()) {
+                       start_location = location;
+               }
+               if (location->is_end()) {
+                       end_location = location;
+               }
        }
 
        if (!set_loop) {
@@ -1209,6 +1221,10 @@ 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
@@ -1237,24 +1253,43 @@ Session::audible_frame () const
        } else {
                tf = _transport_frame;
        }
-
-       if (_transport_speed == 0) {
-               return tf;
-       }
-
-       if (tf < offset) {
-               return 0;
-       }
-
+       
        ret = tf;
 
        if (!non_realtime_work_pending()) {
 
                /* MOVING */
 
-               /* take latency into account */
+               /* 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
+                  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;
+                                       
+                               }
+                       } 
+                       
+
+                       /* forwards */
+                       ret -= offset;
 
-               ret -= offset;
+               } else if (_transport_speed < 0.0f) {
+
+                       /* XXX wot? no backward looping? */
+
+                       if (tf > last_stop_frame - offset) {
+                               return last_stop_frame;
+                       } else {
+                               /* backwards */
+                               ret += offset;
+                       }
+               }
        }
 
        return ret;
@@ -1301,9 +1336,7 @@ Session::set_block_size (nframes_t nframes)
 
                ensure_buffers(_scratch_buffers->available());
 
-               if (_gain_automation_buffer) {
-                       delete [] _gain_automation_buffer;
-               }
+               delete [] _gain_automation_buffer;
                _gain_automation_buffer = new gain_t[nframes];
 
                allocate_pan_automation_buffers (nframes, _npan_buffers, true);
@@ -1523,16 +1556,13 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
                }
        }
 
-       /*
        vector<string> physinputs;
        vector<string> physoutputs;
-       uint32_t nphysical_in;
-       uint32_t nphysical_out;
 
-       _engine.get_physical_outputs (physoutputs);
-       _engine.get_physical_inputs (physinputs);
-       control_id = ntracks() + nbusses() + 1;
-       */
+       _engine.get_physical_outputs (DataType::MIDI, physoutputs);
+       _engine.get_physical_inputs (DataType::MIDI, physinputs);
+
+       // control_id = ntracks() + nbusses();
 
        while (how_many) {
 
@@ -1554,20 +1584,6 @@ Session::new_midi_track (TrackMode mode, uint32_t how_many)
 
                } while (track_id < (UINT_MAX-1));
 
-               /*
-               if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                       nphysical_in = min (n_physical_inputs, (uint32_t) physinputs.size());
-               } else {
-                       nphysical_in = 0;
-               }
-
-               if (Config->get_output_auto_connect() & AutoConnectPhysical) {
-                       nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
-               } else {
-                       nphysical_out = 0;
-               }
-               */
-
                shared_ptr<MidiTrack> track;
 
                try {
@@ -1700,11 +1716,10 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
        vector<string> physinputs;
        vector<string> physoutputs;
-       uint32_t nphysical_in;
-       uint32_t nphysical_out;
 
-       _engine.get_physical_outputs (physoutputs);
-       _engine.get_physical_inputs (physinputs);
+       _engine.get_physical_outputs (DataType::AUDIO, physoutputs);
+       _engine.get_physical_inputs (DataType::AUDIO, physinputs);
+
        control_id = ntracks() + nbusses() + 1;
 
        while (how_many) {
@@ -1727,18 +1742,6 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
                } while (track_id < (UINT_MAX-1));
 
-               if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                       nphysical_in = min (n_physical_inputs, (uint32_t) physinputs.size());
-               } else {
-                       nphysical_in = 0;
-               }
-
-               if (Config->get_output_auto_connect() & AutoConnectPhysical) {
-                       nphysical_out = min (n_physical_outputs, (uint32_t) physinputs.size());
-               } else {
-                       nphysical_out = 0;
-               }
-
                shared_ptr<AudioTrack> track;
 
                try {
@@ -1751,7 +1754,9 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                goto failed;
                        }
 
-                       if (nphysical_in) {
+                       if (!physinputs.empty()) {
+                               uint32_t nphysical_in = physinputs.size();
+
                                for (uint32_t x = 0; x < track->n_inputs().n_audio() && x < nphysical_in; ++x) {
 
                                        port = "";
@@ -1766,20 +1771,24 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
                                }
                        }
 
-                       for (uint32_t x = 0; x < track->n_outputs().n_midi(); ++x) {
+                       if (!physoutputs.empty()) {
+                               uint32_t nphysical_out = physoutputs.size();
 
-                               port = "";
-
-                               if (nphysical_out && (Config->get_output_auto_connect() & AutoConnectPhysical)) {
-                                       port = physoutputs[(channels_used+x)%nphysical_out];
-                               } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
-                                       if (_master_out) {
-                                               port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
+                               for (uint32_t x = 0; x < track->n_outputs().n_audio(); ++x) {
+                                       
+                                       port = "";
+                                       
+                                       if (Config->get_output_auto_connect() & AutoConnectPhysical) {
+                                               port = physoutputs[(channels_used+x)%nphysical_out];
+                                       } else if (Config->get_output_auto_connect() & AutoConnectMaster) {
+                                               if (_master_out) {
+                                                       port = _master_out->input (x%_master_out->n_inputs().n_audio())->name();
+                                               }
+                                       }
+                                       
+                                       if (port.length() && track->connect_output (track->output (x), port, this)) {
+                                               break;
                                        }
-                               }
-
-                               if (port.length() && track->connect_output (track->output (x), port, this)) {
-                                       break;
                                }
                        }
 
@@ -1868,6 +1877,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
        char bus_name[32];
        uint32_t bus_id = 1;
        uint32_t n = 0;
+       uint32_t channels_used = 0;
        string port;
        RouteList ret;
        uint32_t control_id;
@@ -1878,9 +1888,12 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                shared_ptr<RouteList> r = routes.reader ();
 
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       if (dynamic_cast<AudioTrack*>((*i).get()) == 0) {
+                       if (boost::dynamic_pointer_cast<Track>(*i) == 0) {
+                               /* its a bus ? */
                                if (!(*i)->is_hidden() && (*i)->name() != _("master")) {
                                        bus_id++;
+                                       n++;
+                                       channels_used += (*i)->n_inputs().n_audio();
                                }
                        }
                }
@@ -1889,8 +1902,12 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
        vector<string> physinputs;
        vector<string> physoutputs;
 
-       _engine.get_physical_outputs (physoutputs);
-       _engine.get_physical_inputs (physinputs);
+       _engine.get_physical_outputs (DataType::AUDIO, physoutputs);
+       _engine.get_physical_inputs (DataType::AUDIO, physinputs);
+
+       n_physical_audio_outputs = physoutputs.size();
+       n_physical_audio_inputs = physinputs.size();
+
        control_id = ntracks() + nbusses() + 1;
 
        while (how_many) {
@@ -1916,21 +1933,24 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                goto failure;
                        }
 
-                       for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs().n_audio(); ++x) {
 
-                               port = "";
 
+                       /*
+                       for (uint32_t x = 0; n_physical_audio_inputs && x < bus->n_inputs(); ++x) {
+                                       
+                               port = "";
+                               
                                if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                               port = physinputs[((n+x)%n_physical_inputs)];
-                               }
-
+                                       port = physinputs[((n+x)%n_physical_audio_inputs)];
+                               } 
+                               
                                if (port.length() && bus->connect_input (bus->input (x), port, this)) {
                                        break;
                                }
                        }
+                       */
 
-                       for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs().n_audio(); ++x) {
-
+                       for (uint32_t x = 0; n_physical_audio_outputs && x < bus->n_outputs().n_audio(); ++x) {
                                port = "";
 
                                if (Config->get_output_auto_connect() & AutoConnectPhysical) {
@@ -1946,6 +1966,8 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                }
                        }
 
+                       channels_used += bus->n_inputs ().n_audio();
+
                        bus->set_remote_control_id (control_id);
                        ++control_id;
 
@@ -2003,8 +2025,12 @@ Session::add_routes (RouteList& new_routes, bool save)
                        _control_out = (*x);
                }
 
-               add_bundle ((*x)->bundle_for_inputs());
-               add_bundle ((*x)->bundle_for_outputs());
+               /* only busses get automatic bundles formed */
+
+               if (!boost::dynamic_pointer_cast<Track> (*x)) {
+                       add_bundle ((*x)->bundle_for_inputs());
+                       add_bundle ((*x)->bundle_for_outputs());
+               }
        }
 
        if (_control_out && IO::connecting_legal) {
@@ -2124,6 +2150,8 @@ Session::remove_route (shared_ptr<Route> route)
 
        route->drop_references ();
 
+       sync_order_keys (N_("session"));
+
        /* save the new state of the world */
 
        if (save_state (_current_snapshot_name)) {
@@ -2248,8 +2276,6 @@ Session::update_route_solo_state ()
        bool is_track = false;
        bool signal = false;
 
-       /* caller must hold RouteLock */
-
        /* this is where we actually implement solo by changing
           the solo mute setting of each track.
        */
@@ -2349,7 +2375,24 @@ Session::catch_up_on_solo ()
           has.
        */
        update_route_solo_state();
-}
+}      
+
+void
+Session::catch_up_on_solo_mute_override ()
+{
+       if (Config->get_solo_model() != InverseMute) {
+               return;
+       }
+
+       /* this is called whenever the param solo-mute-override is
+          changed.
+       */
+       shared_ptr<RouteList> r = routes.reader ();
+
+       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+               (*i)->catch_up_on_solo_mute_override ();
+       }
+}      
 
 shared_ptr<Route>
 Session::route_by_name (string name)
@@ -2418,6 +2461,8 @@ Session::get_maximum_extent () const
        boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
 
        for (DiskstreamList::const_iterator i = dsl->begin(); i != dsl->end(); ++i) {
+               if ((*i)->destructive())  //ignore tape tracks when getting max extents
+                       continue;
                boost::shared_ptr<Playlist> pl = (*i)->playlist();
                if ((me = pl->get_maximum_extent()) > max) {
                        max = me;
@@ -2509,7 +2554,7 @@ Session::new_region_name (string old)
 }
 
 int
-Session::region_name (string& result, string base, bool newlevel) const
+Session::region_name (string& result, string base, bool newlevel)
 {
        char buf[16];
        string subbase;
@@ -2521,15 +2566,11 @@ Session::region_name (string& result, string base, bool newlevel) const
                Glib::Mutex::Lock lm (region_lock);
 
                snprintf (buf, sizeof (buf), "%d", (int)regions.size() + 1);
-
-
                result = "region.";
                result += buf;
 
        } else {
 
-               /* XXX this is going to be slow. optimize me later */
-
                if (newlevel) {
                        subbase = base;
                } else {
@@ -2543,37 +2584,25 @@ Session::region_name (string& result, string base, bool newlevel) const
 
                }
 
-               bool name_taken = true;
-
                {
                        Glib::Mutex::Lock lm (region_lock);
 
-                       for (int n = 1; n < 5000; ++n) {
-
-                               result = subbase;
-                               snprintf (buf, sizeof (buf), ".%d", n);
-                               result += buf;
+                       map<string,uint32_t>::iterator x;
 
-                               name_taken = false;
+                       result = subbase;
 
-                               for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
-                                       if (i->second->name() == result) {
-                                               name_taken = true;
-                                               break;
-                                       }
-                               }
+                       if ((x = region_name_map.find (subbase)) == region_name_map.end()) {
+                               result += ".1";
+                               region_name_map[subbase] = 1;
+                       } else {
+                               x->second++;
+                               snprintf (buf, sizeof (buf), ".%d", x->second);
 
-                               if (!name_taken) {
-                                       break;
-                               }
+                               result += buf;
                        }
                }
-
-               if (name_taken) {
-                       fatal << string_compose(_("too many regions with names like %1"), base) << endmsg;
-                       /*NOTREACHED*/
-               }
        }
+
        return 0;
 }
 
@@ -2635,7 +2664,7 @@ Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
           add the region to the region list.
        */
 
-       set_dirty();
+       set_dirty ();
 
        if (added) {
 
@@ -2660,6 +2689,8 @@ Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
 
                        region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
                        region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
+
+                       update_region_name_map (region);
                }
 
                if (!v.empty()) {
@@ -2668,6 +2699,25 @@ Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
        }
 }
 
+void
+Session::update_region_name_map (boost::shared_ptr<Region> region)
+{
+       string::size_type last_period = region->name().find_last_of ('.');
+       
+       if (last_period != string::npos && last_period < region->name().length() - 1) {
+               
+               string base = region->name().substr (0, last_period);
+               string number = region->name().substr (last_period+1);
+               map<string,uint32_t>::iterator x;
+               
+               /* note that if there is no number, we get zero from atoi,
+                  which is just fine
+               */
+               
+               region_name_map[base] = atoi (number);
+       }
+}
+
 void
 Session::region_changed (Change what_changed, boost::weak_ptr<Region> weak_region)
 {
@@ -2681,6 +2731,10 @@ Session::region_changed (Change what_changed, boost::weak_ptr<Region> weak_regio
                /* relay hidden changes */
                RegionHiddenChange (region);
        }
+
+       if (what_changed & NameChanged) {
+               update_region_name_map (region);
+       }
 }
 
 void
@@ -3347,7 +3401,23 @@ Session::playlist_by_name (string name)
 }
 
 void
-Session::add_playlist (boost::shared_ptr<Playlist> playlist)
+Session::unassigned_playlists (std::list<boost::shared_ptr<Playlist> > & list)
+{
+       Glib::Mutex::Lock lm (playlist_lock);
+       for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+               if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) {
+                       list.push_back (*i);
+               }
+       }
+       for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+               if (!(*i)->get_orig_diskstream_id().to_s().compare ("0")) {
+                       list.push_back (*i);
+               }
+       }
+}
+
+void
+Session::add_playlist (boost::shared_ptr<Playlist> playlist, bool unused)
 {
        if (playlist->hidden()) {
                return;
@@ -3362,6 +3432,10 @@ Session::add_playlist (boost::shared_ptr<Playlist> playlist)
                }
        }
 
+       if (unused) {
+               playlist->release();
+       }
+
        set_dirty();
 
        PlaylistAdded (playlist); /* EMIT SIGNAL */
@@ -4022,11 +4096,11 @@ Session::freeze (InterThreadInfo& itt)
        return 0;
 }
 
-int
-Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t len,
-                              bool overwrite, vector<boost::shared_ptr<Source> >& srcs, InterThreadInfo& itt)
+boost::shared_ptr<Region>
+Session::write_one_track (AudioTrack& track, nframes_t start, nframes_t end,   
+                         bool overwrite, vector<boost::shared_ptr<Source> >& srcs, InterThreadInfo& itt)
 {
-       int ret = -1;
+       boost::shared_ptr<Region> result;
        boost::shared_ptr<Playlist> playlist;
        boost::shared_ptr<AudioFileSource> fsource;
        uint32_t x;
@@ -4038,6 +4112,13 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
        BufferSet buffers;
        SessionDirectory sdir(get_best_session_directory_for_new_source ());
        const string sound_dir = sdir.sound_path().to_string();
+       nframes_t len = end - start;
+
+       if (end <= start) {
+               error << string_compose (_("Cannot write a range where end <= start (e.g. %1 <= %2)"),
+                                        end, start) << endmsg;
+               return result;
+       }
 
        // any bigger than this seems to cause stack overflows in called functions
        const nframes_t chunk_size = (128 * 1024)/4;
@@ -4142,21 +4223,19 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
 
                /* construct a region to represent the bounced material */
 
-               boost::shared_ptr<Region> aregion = RegionFactory::create (srcs, 0, srcs.front()->length(),
-                                                                          region_name_from_path (srcs.front()->name(), true));
-
-               ret = 0;
+               result = RegionFactory::create (srcs, 0, srcs.front()->length(), 
+                                               region_name_from_path (srcs.front()->name(), true));
        }
 
   out:
-       if (ret) {
+       if (!result) {
                for (vector<boost::shared_ptr<Source> >::iterator src = srcs.begin(); src != srcs.end(); ++src) {
                        boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*src);
 
                        if (afs) {
                                afs->mark_for_remove ();
                        }
-
+                       
                        (*src)->drop_references ();
                }
 
@@ -4171,7 +4250,7 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
 
        g_atomic_int_set (&processing_prohibited, 0);
 
-       return ret;
+       return result;
 }
 
 BufferSet&
@@ -4192,8 +4271,13 @@ Session::get_silent_buffers (ChanCount count)
 BufferSet&
 Session::get_scratch_buffers (ChanCount count)
 {
-       assert(_scratch_buffers->available() >= count);
-       _scratch_buffers->set_count(count);
+       if (count != ChanCount::ZERO) {
+               assert(_scratch_buffers->available() >= count);
+               _scratch_buffers->set_count(count);
+       } else {
+               _scratch_buffers->set_count (_scratch_buffers->available());
+       }
+
        return *_scratch_buffers;
 }
 
@@ -4248,7 +4332,7 @@ Session::compute_initial_length ()
 }
 
 void
-Session::sync_order_keys ()
+Session::sync_order_keys (const char* base)
 {
        if (!Config->get_sync_all_route_ordering()) {
                /* leave order keys as they are */
@@ -4258,10 +4342,10 @@ Session::sync_order_keys ()
        boost::shared_ptr<RouteList> r = routes.reader ();
 
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               (*i)->sync_order_keys ();
+               (*i)->sync_order_keys (base);
        }
 
-       Route::SyncOrderKeys (); // EMIT SIGNAL
+       Route::SyncOrderKeys (base); // EMIT SIGNAL
 }
 
 void