use new method in MidiPatchManager to use MIDNAM data when setting a MidiTimeAxisView
[ardour.git] / gtk2_ardour / editor_ops.cc
index ea3e3ac74fffb67573ae900b3516f47f20708d6e..195d4d16436b6bbb41aa9e926eafbe0dcbd9abfc 100644 (file)
@@ -1,21 +1,32 @@
 /*
-    Copyright (C) 2000-2004 Paul Davis
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
+ * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
+ * Copyright (C) 2005-2009 Sampo Savolainen <v2@iki.fi>
+ * Copyright (C) 2005-2018 Paul Davis <paul@linuxaudiosystems.com>
+ * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
+ * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
+ * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
+ * Copyright (C) 2007-2017 Tim Mayberry <mojofunk@gmail.com>
+ * Copyright (C) 2013-2016 Colin Fletcher <colin.m.fletcher@googlemail.com>
+ * Copyright (C) 2013-2017 John Emmas <john@creativepost.co.uk>
+ * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
+ * Copyright (C) 2013-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2014-2019 Ben Loftis <ben@harrisonconsoles.com>
+ * Copyright (C) 2015 AndrĂ© Nusser <andre.nusser@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
 
 /* Note: public Editor methods are documented in public_editor.h */
 
 #include "ardour/legatize.h"
 #include "ardour/region_factory.h"
 #include "ardour/reverse.h"
+#include "ardour/selection.h"
 #include "ardour/session.h"
 #include "ardour/session_playlists.h"
+#include "ardour/source.h"
 #include "ardour/strip_silence.h"
 #include "ardour/transient_detector.h"
+#include "ardour/transport_master_manager.h"
 #include "ardour/transpose.h"
+#include "ardour/vca_manager.h"
 
 #include "canvas/canvas.h"
 
 #include "actions.h"
+#include "ardour_message.h"
+#include "ardour_ui.h"
 #include "audio_region_view.h"
 #include "audio_streamview.h"
 #include "audio_time_axis.h"
@@ -79,6 +96,7 @@
 #include "editor_cursors.h"
 #include "editor_drag.h"
 #include "editor_regions.h"
+#include "editor_sources.h"
 #include "editor_routes.h"
 #include "gui_thread.h"
 #include "insert_remove_time_dialog.h"
 #include "transpose_dialog.h"
 #include "transform_dialog.h"
 #include "ui_config.h"
+#include "utils.h"
+#include "vca_time_axis.h"
 
 #include "pbd/i18n.h"
 
@@ -135,6 +155,7 @@ Editor::undo (uint32_t n)
        if (_drags->active ()) {
                _drags->abort ();
        }
+       paste_count = 0;
 
        if (_session) {
                _session->undo (n);
@@ -159,6 +180,7 @@ Editor::redo (uint32_t n)
        if (_drags->active ()) {
                _drags->abort ();
        }
+       paste_count = 0;
 
        if (_session) {
        _session->redo (n);
@@ -171,13 +193,10 @@ Editor::redo (uint32_t n)
 }
 
 void
-Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_frame)
+Editor::split_regions_at (MusicSample where, RegionSelection& regions)
 {
        bool frozen = false;
 
-       RegionSelection pre_selected_regions = selection->regions;
-       bool working_on_selection = !pre_selected_regions.empty();
-
        list<boost::shared_ptr<Playlist> > used_playlists;
        list<RouteTimeAxisView*> used_trackviews;
 
@@ -187,25 +206,11 @@ Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_
 
        begin_reversible_command (_("split"));
 
-       // if splitting a single region, and snap-to is using
-       // region boundaries, don't pay attention to them
 
        if (regions.size() == 1) {
-               switch (_snap_type) {
-               case SnapToRegionStart:
-               case SnapToRegionSync:
-               case SnapToRegionEnd:
-                       break;
-               default:
-                       if (snap_frame) {
-                               snap_to (where);
-                       }
-               }
+               /* TODO:  if splitting a single region, and snap-to is using
+                region boundaries, mabye we shouldn't pay attention to them? */
        } else {
-               if (snap_frame) {
-                       snap_to (where);
-               }
-
                frozen = true;
                EditorFreeze(); /* Emit Signal */
        }
@@ -218,7 +223,7 @@ Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_
                   have something to split.
                */
 
-               if (!(*a)->region()->covers (where.frame)) {
+               if (!(*a)->region()->covers (where.sample)) {
                        ++a;
                        continue;
                }
@@ -279,24 +284,25 @@ Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_
                EditorThaw(); /* Emit Signal */
        }
 
-       if (working_on_selection) {
-               // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
-
-               RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
-               /* There are three classes of regions that we might want selected after
-                  splitting selected regions:
-                   - regions selected before the split operation, and unaffected by it
-                   - newly-created regions before the split
-                   - newly-created regions after the split
-                */
-
-               if (rsas & Existing) {
-                       // region selections that existed before the split.
-                       selection->add ( pre_selected_regions );
-               }
+       RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
 
+       //if the user has "Clear Selection" as their post-split behavior, then clear the selection
+       if (!latest_regionviews.empty() && (rsas == None)) {
+               selection->clear_objects();
+               selection->clear_time();
+               //but leave track selection intact
+       }
+       
+       //if the user doesn't want to preserve the "Existing" selection, then clear the selection
+       if (!(rsas & Existing)) {
+               selection->clear_objects();
+               selection->clear_time();
+       }
+       
+       //if the user wants newly-created regions to be selected, then select them:
+       if (mouse_mode == MouseObject) {
                for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
-                       if ((*ri)->region()->position() < where.frame) {
+                       if ((*ri)->region()->position() < where.sample) {
                                // new regions created before the split
                                if (rsas & NewlyCreatedLeft) {
                                        selection->add (*ri);
@@ -308,10 +314,6 @@ Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_
                                }
                        }
                }
-       } else {
-               if( working_on_selection ) {
-                       selection->add (latest_regionviews);  //these are the new regions created after the split
-               }
        }
 
        commit_reversible_command ();
@@ -328,15 +330,15 @@ Editor::split_regions_at (MusicFrame where, RegionSelection& regions, bool snap_
 void
 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
 {
-       if (selection->time.start() == selection->time.end_frame()) {
+       if (selection->time.start() == selection->time.end_sample()) {
                return;
        }
 
-       framepos_t start = selection->time.start ();
-       framepos_t end = selection->time.end_frame ();
+       samplepos_t start = selection->time.start ();
+       samplepos_t end = selection->time.end_sample ();
 
        /* the position of the thing we may move */
-       framepos_t pos = move_end ? end : start;
+       samplepos_t pos = move_end ? end : start;
        int dir = next ? 1 : -1;
 
        /* so we don't find the current region again */
@@ -344,7 +346,7 @@ Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, boo
                pos += dir;
        }
 
-       framepos_t const target = get_region_boundary (pos, dir, true, false);
+       samplepos_t const target = get_region_boundary (pos, dir, true, false);
        if (target < 0) {
                return;
        }
@@ -390,8 +392,8 @@ Editor::nudge_backward_release (GdkEventButton* ev)
 void
 Editor::nudge_forward (bool next, bool force_playhead)
 {
-       framepos_t distance;
-       framepos_t next_distance;
+       samplepos_t distance;
+       samplepos_t next_distance;
 
        if (!_session) {
                return;
@@ -439,23 +441,23 @@ Editor::nudge_forward (bool next, bool force_playhead)
                                        if (next) {
                                                distance = next_distance;
                                        }
-                                       if (max_framepos - distance > loc->start() + loc->length()) {
+                                       if (max_samplepos - distance > loc->start() + loc->length()) {
                                                loc->set_start (loc->start() + distance, false, true, divisions);
                                        } else {
-                                               loc->set_start (max_framepos - loc->length(), false, true, divisions);
+                                               loc->set_start (max_samplepos - loc->length(), false, true, divisions);
                                        }
                                } else {
                                        distance = get_nudge_distance (loc->end(), next_distance);
                                        if (next) {
                                                distance = next_distance;
                                        }
-                                       if (max_framepos - distance > loc->end()) {
+                                       if (max_samplepos - distance > loc->end()) {
                                                loc->set_end (loc->end() + distance, false, true, divisions);
                                        } else {
-                                               loc->set_end (max_framepos, false, true, divisions);
+                                               loc->set_end (max_samplepos, false, true, divisions);
                                        }
                                        if (loc->is_session_range()) {
-                                               _session->set_end_is_free (false);
+                                               _session->set_session_range_is_free (false);
                                        }
                                }
                                if (!in_command) {
@@ -471,16 +473,16 @@ Editor::nudge_forward (bool next, bool force_playhead)
                        commit_reversible_command ();
                }
        } else {
-               distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
-               _session->request_locate (playhead_cursor->current_frame () + distance);
+               distance = get_nudge_distance (playhead_cursor->current_sample (), next_distance);
+               _session->request_locate (playhead_cursor->current_sample () + distance);
        }
 }
 
 void
 Editor::nudge_backward (bool next, bool force_playhead)
 {
-       framepos_t distance;
-       framepos_t next_distance;
+       samplepos_t distance;
+       samplepos_t next_distance;
 
        if (!_session) {
                return;
@@ -549,7 +551,7 @@ Editor::nudge_backward (bool next, bool force_playhead)
                                                loc->set_end (loc->length(), false, true, get_grid_music_divisions(0));
                                        }
                                        if (loc->is_session_range()) {
-                                               _session->set_end_is_free (false);
+                                               _session->set_session_range_is_free (false);
                                        }
                                }
                                if (!in_command) {
@@ -566,10 +568,10 @@ Editor::nudge_backward (bool next, bool force_playhead)
 
        } else {
 
-               distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
+               distance = get_nudge_distance (playhead_cursor->current_sample (), next_distance);
 
-               if (playhead_cursor->current_frame () > distance) {
-                       _session->request_locate (playhead_cursor->current_frame () - distance);
+               if (playhead_cursor->current_sample () > distance) {
+                       _session->request_locate (playhead_cursor->current_sample () - distance);
                } else {
                        _session->goto_start();
                }
@@ -587,7 +589,7 @@ Editor::nudge_forward_capture_offset ()
 
        begin_reversible_command (_("nudge forward"));
 
-       framepos_t const distance = _session->worst_output_latency();
+       samplepos_t const distance = _session->worst_output_latency();
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                boost::shared_ptr<Region> r ((*i)->region());
@@ -611,7 +613,7 @@ Editor::nudge_backward_capture_offset ()
 
        begin_reversible_command (_("nudge backward"));
 
-       framepos_t const distance = _session->worst_output_latency();
+       samplepos_t const distance = _session->worst_output_latency();
 
        for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
                boost::shared_ptr<Region> r ((*i)->region());
@@ -638,8 +640,8 @@ struct RegionSelectionPositionSorter {
 void
 Editor::sequence_regions ()
 {
-       framepos_t r_end;
-       framepos_t r_end_prev;
+       samplepos_t r_end;
+       samplepos_t r_end_prev;
 
        int iCount=0;
 
@@ -703,13 +705,20 @@ void
 Editor::move_to_end ()
 {
 
-       _session->request_locate (_session->current_end_frame());
+       _session->request_locate (_session->current_end_sample());
 }
 
 void
 Editor::build_region_boundary_cache ()
 {
-       framepos_t pos = 0;
+
+       /* TODO:  maybe set a timer so we don't recalutate when lots of changes are coming in */
+       /* TODO:  maybe somehow defer this until session is fully loaded.  */
+
+       if (!_region_boundary_cache_dirty)
+               return;
+
+       samplepos_t pos = 0;
        vector<RegionPoint> interesting_points;
        boost::shared_ptr<Region> r;
        TrackViewList tracks;
@@ -721,39 +730,55 @@ Editor::build_region_boundary_cache ()
                return;
        }
 
-       switch (_snap_type) {
-       case SnapToRegionStart:
+       bool maybe_first_sample = false;
+
+       if (UIConfiguration::instance().get_snap_to_region_start()) {
                interesting_points.push_back (Start);
-               break;
-       case SnapToRegionEnd:
+               maybe_first_sample = true;
+       }
+
+       if (UIConfiguration::instance().get_snap_to_region_end()) {
                interesting_points.push_back (End);
-               break;
-       case SnapToRegionSync:
+       }
+
+       if (UIConfiguration::instance().get_snap_to_region_sync()) {
                interesting_points.push_back (SyncPoint);
-               break;
-       case SnapToRegionBoundary:
-               interesting_points.push_back (Start);
-               interesting_points.push_back (End);
-               break;
-       default:
-               fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
-               abort(); /*NOTREACHED*/
+       }
+
+       /* if no snap selections are set, boundary cache should be left empty */
+       if ( interesting_points.empty() ) {
+               _region_boundary_cache_dirty = false;
                return;
        }
 
        TimeAxisView *ontrack = 0;
        TrackViewList tlist;
 
-       if (!selection->tracks.empty()) {
-               tlist = selection->tracks.filter_to_unique_playlists ();
-       } else {
-               tlist = track_views.filter_to_unique_playlists ();
+       tlist = track_views.filter_to_unique_playlists ();
+
+       if (maybe_first_sample) {
+               TrackViewList::const_iterator i;
+               for (i = tlist.begin(); i != tlist.end(); ++i) {
+                       boost::shared_ptr<Playlist> pl = (*i)->playlist();
+                       if (pl && pl->count_regions_at (0)) {
+                               region_boundary_cache.push_back (0);
+                               break;
+                       }
+               }
+       }
+
+       //allow regions to snap to the video start (if any) as if it were a "region"
+       if (ARDOUR_UI::instance()->video_timeline) {
+               region_boundary_cache.push_back (ARDOUR_UI::instance()->video_timeline->get_video_start_offset());
        }
 
-       while (pos < _session->current_end_frame() && !at_end) {
+       std::pair<samplepos_t, samplepos_t> ext = session_gui_extents (false);
+       samplepos_t session_end = ext.second;
 
-               framepos_t rpos;
-               framepos_t lpos = max_framepos;
+       while (pos < session_end && !at_end) {
+
+               samplepos_t rpos;
+               samplepos_t lpos = session_end;
 
                for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
 
@@ -767,11 +792,11 @@ Editor::build_region_boundary_cache ()
 
                        switch (*p) {
                        case Start:
-                               rpos = r->first_frame();
+                               rpos = r->first_sample();
                                break;
 
                        case End:
-                               rpos = r->last_frame();
+                               rpos = r->last_sample();
                                break;
 
                        case SyncPoint:
@@ -782,17 +807,6 @@ Editor::build_region_boundary_cache ()
                                break;
                        }
 
-                       float speed = 1.0f;
-                       RouteTimeAxisView *rtav;
-
-                       if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
-                               if (rtav->track() != 0) {
-                                       speed = rtav->track()->speed();
-                               }
-                       }
-
-                       rpos = track_frame_to_session_frame (rpos, speed);
-
                        if (rpos < lpos) {
                                lpos = rpos;
                        }
@@ -801,7 +815,7 @@ Editor::build_region_boundary_cache ()
                           to sort later.
                        */
 
-                       vector<framepos_t>::iterator ri;
+                       vector<samplepos_t>::iterator ri;
 
                        for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
                                if (*ri == rpos) {
@@ -820,44 +834,38 @@ Editor::build_region_boundary_cache ()
        /* finally sort to be sure that the order is correct */
 
        sort (region_boundary_cache.begin(), region_boundary_cache.end());
+
+       _region_boundary_cache_dirty = false;
 }
 
 boost::shared_ptr<Region>
-Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
+Editor::find_next_region (samplepos_t sample, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
 {
        TrackViewList::iterator i;
-       framepos_t closest = max_framepos;
+       samplepos_t closest = max_samplepos;
        boost::shared_ptr<Region> ret;
-       framepos_t rpos = 0;
+       samplepos_t rpos = 0;
 
-       float track_speed;
-       framepos_t track_frame;
-       RouteTimeAxisView *rtav;
+       samplepos_t track_sample;
 
        for (i = tracks.begin(); i != tracks.end(); ++i) {
 
-               framecnt_t distance;
+               samplecnt_t distance;
                boost::shared_ptr<Region> r;
 
-               track_speed = 1.0f;
-               if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
-                       if (rtav->track()!=0)
-                               track_speed = rtav->track()->speed();
-               }
-
-               track_frame = session_frame_to_track_frame(frame, track_speed);
+               track_sample = sample;
 
-               if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
+               if ((r = (*i)->find_next_region (track_sample, point, dir)) == 0) {
                        continue;
                }
 
                switch (point) {
                case Start:
-                       rpos = r->first_frame ();
+                       rpos = r->first_sample ();
                        break;
 
                case End:
-                       rpos = r->last_frame ();
+                       rpos = r->last_sample ();
                        break;
 
                case SyncPoint:
@@ -865,13 +873,10 @@ Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, Trac
                        break;
                }
 
-               // rpos is a "track frame", converting it to "_session frame"
-               rpos = track_frame_to_session_frame(rpos, track_speed);
-
-               if (rpos > frame) {
-                       distance = rpos - frame;
+               if (rpos > sample) {
+                       distance = rpos - sample;
                } else {
-                       distance = frame - rpos;
+                       distance = sample - rpos;
                }
 
                if (distance < closest) {
@@ -885,15 +890,15 @@ Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, Trac
        return ret;
 }
 
-framepos_t
-Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
+samplepos_t
+Editor::find_next_region_boundary (samplepos_t pos, int32_t dir, const TrackViewList& tracks)
 {
-       framecnt_t distance = max_framepos;
-       framepos_t current_nearest = -1;
+       samplecnt_t distance = max_samplepos;
+       samplepos_t current_nearest = -1;
 
        for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
-               framepos_t contender;
-               framecnt_t d;
+               samplepos_t contender;
+               samplecnt_t d;
 
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
 
@@ -916,10 +921,10 @@ Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewL
        return current_nearest;
 }
 
-framepos_t
-Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
+samplepos_t
+Editor::get_region_boundary (samplepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
 {
-       framepos_t target;
+       samplepos_t target;
        TrackViewList tvl;
 
        if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
@@ -954,8 +959,8 @@ Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, b
 void
 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
 {
-       framepos_t pos = playhead_cursor->current_frame ();
-       framepos_t target;
+       samplepos_t pos = playhead_cursor->current_sample ();
+       samplepos_t target;
 
        if (!_session) {
                return;
@@ -989,7 +994,7 @@ void
 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
 {
        boost::shared_ptr<Region> r;
-       framepos_t pos = cursor->current_frame ();
+       samplepos_t pos = cursor->current_sample ();
 
        if (!_session) {
                return;
@@ -1023,11 +1028,11 @@ Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t
 
        switch (point) {
        case Start:
-               pos = r->first_frame ();
+               pos = r->first_sample ();
                break;
 
        case End:
-               pos = r->last_frame ();
+               pos = r->last_sample ();
                break;
 
        case SyncPoint:
@@ -1035,17 +1040,6 @@ Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t
                break;
        }
 
-       float speed = 1.0f;
-       RouteTimeAxisView *rtav;
-
-       if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
-               if (rtav->track() != 0) {
-                       speed = rtav->track()->speed();
-               }
-       }
-
-       pos = track_frame_to_session_frame(pos, speed);
-
        if (cursor == playhead_cursor) {
                _session->request_locate (pos);
        } else {
@@ -1068,7 +1062,7 @@ Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point
 void
 Editor::cursor_to_selection_start (EditorCursor *cursor)
 {
-       framepos_t pos = 0;
+       samplepos_t pos = 0;
 
        switch (mouse_mode) {
        case MouseObject:
@@ -1097,18 +1091,18 @@ Editor::cursor_to_selection_start (EditorCursor *cursor)
 void
 Editor::cursor_to_selection_end (EditorCursor *cursor)
 {
-       framepos_t pos = 0;
+       samplepos_t pos = 0;
 
        switch (mouse_mode) {
        case MouseObject:
                if (!selection->regions.empty()) {
-                       pos = selection->regions.end_frame();
+                       pos = selection->regions.end_sample();
                }
                break;
 
        case MouseRange:
                if (!selection->time.empty()) {
-                       pos = selection->time.end_frame ();
+                       pos = selection->time.end_sample ();
                }
                break;
 
@@ -1126,7 +1120,7 @@ Editor::cursor_to_selection_end (EditorCursor *cursor)
 void
 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
 {
-       framepos_t target;
+       samplepos_t target;
        Location* loc;
        bool ignored;
 
@@ -1135,10 +1129,10 @@ Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
        }
 
        if (selection->markers.empty()) {
-               framepos_t mouse;
+               samplepos_t mouse;
                bool ignored;
 
-               if (!mouse_frame (mouse, ignored)) {
+               if (!mouse_sample (mouse, ignored)) {
                        return;
                }
 
@@ -1149,7 +1143,7 @@ Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
                return;
        }
 
-       framepos_t pos = loc->start();
+       samplepos_t pos = loc->start();
 
        // so we don't find the current region again..
        if (dir > 0 || pos > 0) {
@@ -1179,7 +1173,7 @@ void
 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
 {
        boost::shared_ptr<Region> r;
-       framepos_t pos;
+       samplepos_t pos;
        Location* loc;
        bool ignored;
 
@@ -1214,29 +1208,18 @@ Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
 
        switch (point) {
        case Start:
-               pos = r->first_frame ();
+               pos = r->first_sample ();
                break;
 
        case End:
-               pos = r->last_frame ();
+               pos = r->last_sample ();
                break;
 
        case SyncPoint:
-               pos = r->adjust_to_sync (r->first_frame());
+               pos = r->adjust_to_sync (r->first_sample());
                break;
        }
 
-       float speed = 1.0f;
-       RouteTimeAxisView *rtav;
-
-       if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
-               if (rtav->track() != 0) {
-                       speed = rtav->track()->speed();
-               }
-       }
-
-       pos = track_frame_to_session_frame(pos, speed);
-
        loc->move_to (pos, 0);
 }
 
@@ -1255,7 +1238,7 @@ Editor::selected_marker_to_previous_region_point (RegionPoint point)
 void
 Editor::selected_marker_to_selection_start ()
 {
-       framepos_t pos = 0;
+       samplepos_t pos = 0;
        Location* loc;
        bool ignored;
 
@@ -1290,7 +1273,7 @@ Editor::selected_marker_to_selection_start ()
 void
 Editor::selected_marker_to_selection_end ()
 {
-       framepos_t pos = 0;
+       samplepos_t pos = 0;
        Location* loc;
        bool ignored;
 
@@ -1305,13 +1288,13 @@ Editor::selected_marker_to_selection_end ()
        switch (mouse_mode) {
        case MouseObject:
                if (!selection->regions.empty()) {
-                       pos = selection->regions.end_frame();
+                       pos = selection->regions.end_sample();
                }
                break;
 
        case MouseRange:
                if (!selection->time.empty()) {
-                       pos = selection->time.end_frame ();
+                       pos = selection->time.end_sample ();
                }
                break;
 
@@ -1325,18 +1308,18 @@ Editor::selected_marker_to_selection_end ()
 void
 Editor::scroll_playhead (bool forward)
 {
-       framepos_t pos = playhead_cursor->current_frame ();
-       framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
+       samplepos_t pos = playhead_cursor->current_sample ();
+       samplecnt_t delta = (samplecnt_t) floor (current_page_samples() / 0.8);
 
        if (forward) {
-               if (pos == max_framepos) {
+               if (pos == max_samplepos) {
                        return;
                }
 
-               if (pos < max_framepos - delta) {
+               if (pos < max_samplepos - delta) {
                        pos += delta ;
                } else {
-                       pos = max_framepos;
+                       pos = max_samplepos;
                }
 
        } else {
@@ -1380,10 +1363,10 @@ Editor::cursor_align (bool playhead_to_edit)
                        Location* loc = find_location_from_marker (*i, ignored);
 
                        if (loc->is_mark()) {
-                               loc->set_start (playhead_cursor->current_frame (), false, true, divisions);
+                               loc->set_start (playhead_cursor->current_sample (), false, true, divisions);
                        } else {
-                               loc->set (playhead_cursor->current_frame (),
-                                         playhead_cursor->current_frame () + loc->length(), true, divisions);
+                               loc->set (playhead_cursor->current_sample (),
+                                         playhead_cursor->current_sample () + loc->length(), true, divisions);
                        }
                }
        }
@@ -1392,33 +1375,33 @@ Editor::cursor_align (bool playhead_to_edit)
 void
 Editor::scroll_backward (float pages)
 {
-       framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
-       framepos_t const cnt = (framepos_t) floor (pages * one_page);
+       samplepos_t const one_page = (samplepos_t) rint (_visible_canvas_width * samples_per_pixel);
+       samplepos_t const cnt = (samplepos_t) floor (pages * one_page);
 
-       framepos_t frame;
-       if (leftmost_frame < cnt) {
-               frame = 0;
+       samplepos_t sample;
+       if (_leftmost_sample < cnt) {
+               sample = 0;
        } else {
-               frame = leftmost_frame - cnt;
+               sample = _leftmost_sample - cnt;
        }
 
-       reset_x_origin (frame);
+       reset_x_origin (sample);
 }
 
 void
 Editor::scroll_forward (float pages)
 {
-       framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
-       framepos_t const cnt = (framepos_t) floor (pages * one_page);
+       samplepos_t const one_page = (samplepos_t) rint (_visible_canvas_width * samples_per_pixel);
+       samplepos_t const cnt = (samplepos_t) floor (pages * one_page);
 
-       framepos_t frame;
-       if (max_framepos - cnt < leftmost_frame) {
-               frame = max_framepos - cnt;
+       samplepos_t sample;
+       if (max_samplepos - cnt < _leftmost_sample) {
+               sample = max_samplepos - cnt;
        } else {
-               frame = leftmost_frame + cnt;
+               sample = _leftmost_sample + cnt;
        }
 
-       reset_x_origin (frame);
+       reset_x_origin (sample);
 }
 
 void
@@ -1637,10 +1620,10 @@ Editor::scroll_up_one_track (bool skip_child_views)
 void
 Editor::scroll_left_step ()
 {
-       framepos_t xdelta = (current_page_samples() / 8);
+       samplepos_t xdelta = (current_page_samples() / 8);
 
-       if (leftmost_frame > xdelta) {
-               reset_x_origin (leftmost_frame - xdelta);
+       if (_leftmost_sample > xdelta) {
+               reset_x_origin (_leftmost_sample - xdelta);
        } else {
                reset_x_origin (0);
        }
@@ -1650,21 +1633,21 @@ Editor::scroll_left_step ()
 void
 Editor::scroll_right_step ()
 {
-       framepos_t xdelta = (current_page_samples() / 8);
+       samplepos_t xdelta = (current_page_samples() / 8);
 
-       if (max_framepos - xdelta > leftmost_frame) {
-               reset_x_origin (leftmost_frame + xdelta);
+       if (max_samplepos - xdelta > _leftmost_sample) {
+               reset_x_origin (_leftmost_sample + xdelta);
        } else {
-               reset_x_origin (max_framepos - current_page_samples());
+               reset_x_origin (max_samplepos - current_page_samples());
        }
 }
 
 void
 Editor::scroll_left_half_page ()
 {
-       framepos_t xdelta = (current_page_samples() / 2);
-       if (leftmost_frame > xdelta) {
-               reset_x_origin (leftmost_frame - xdelta);
+       samplepos_t xdelta = (current_page_samples() / 2);
+       if (_leftmost_sample > xdelta) {
+               reset_x_origin (_leftmost_sample - xdelta);
        } else {
                reset_x_origin (0);
        }
@@ -1673,11 +1656,11 @@ Editor::scroll_left_half_page ()
 void
 Editor::scroll_right_half_page ()
 {
-       framepos_t xdelta = (current_page_samples() / 2);
-       if (max_framepos - xdelta > leftmost_frame) {
-               reset_x_origin (leftmost_frame + xdelta);
+       samplepos_t xdelta = (current_page_samples() / 2);
+       if (max_samplepos - xdelta > _leftmost_sample) {
+               reset_x_origin (_leftmost_sample + xdelta);
        } else {
-               reset_x_origin (max_framepos - current_page_samples());
+               reset_x_origin (max_samplepos - current_page_samples());
        }
 }
 
@@ -1758,7 +1741,7 @@ Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
 {
        ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, zoom_out, scale)
 
-       framecnt_t nspp = samples_per_pixel;
+       samplecnt_t nspp = samples_per_pixel;
 
        if (zoom_out) {
                nspp *= scale;
@@ -1772,27 +1755,34 @@ Editor::temporal_zoom_step_scale (bool zoom_out, double scale)
                }
        }
 
+       //zoom-behavior-tweaks
+       //limit our maximum zoom to the session gui extents value
+       std::pair<samplepos_t, samplepos_t> ext = session_gui_extents();
+       samplecnt_t session_extents_pp = (ext.second - ext.first)  / _visible_canvas_width;
+       if (nspp > session_extents_pp)
+               nspp = session_extents_pp;
+
        temporal_zoom (nspp);
 }
 
 void
-Editor::temporal_zoom (framecnt_t fpp)
+Editor::temporal_zoom (samplecnt_t fpp)
 {
        if (!_session) {
                return;
        }
 
-       framepos_t current_page = current_page_samples();
-       framepos_t current_leftmost = leftmost_frame;
-       framepos_t current_rightmost;
-       framepos_t current_center;
-       framepos_t new_page_size;
-       framepos_t half_page_size;
-       framepos_t leftmost_after_zoom = 0;
-       framepos_t where;
+       samplepos_t current_page = current_page_samples();
+       samplepos_t current_leftmost = _leftmost_sample;
+       samplepos_t current_rightmost;
+       samplepos_t current_center;
+       samplepos_t new_page_size;
+       samplepos_t half_page_size;
+       samplepos_t leftmost_after_zoom = 0;
+       samplepos_t where;
        bool in_track_canvas;
-       bool use_mouse_frame = true;
-       framecnt_t nfpp;
+       bool use_mouse_sample = true;
+       samplecnt_t nfpp;
        double l;
 
        if (fpp == samples_per_pixel) {
@@ -1807,19 +1797,25 @@ Editor::temporal_zoom (framecnt_t fpp)
        // all of which is used for the editor track displays. The whole day
        // would be 4147200000 samples, so 2592000 samples per pixel.
 
-       nfpp = min (fpp, (framecnt_t) 2592000);
-       nfpp = max ((framecnt_t) 1, nfpp);
+       nfpp = min (fpp, (samplecnt_t) 2592000);
+       nfpp = max ((samplecnt_t) 1, nfpp);
 
-       new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
+       new_page_size = (samplepos_t) floor (_visible_canvas_width * nfpp);
        half_page_size = new_page_size / 2;
 
-       switch (zoom_focus) {
+       Editing::ZoomFocus zf = zoom_focus;
+
+       if (zf == ZoomFocusEdit && _edit_point == EditAtMouse) {
+               zf = ZoomFocusMouse;
+       }
+
+       switch (zf) {
        case ZoomFocusLeft:
                leftmost_after_zoom = current_leftmost;
                break;
 
        case ZoomFocusRight:
-               current_rightmost = leftmost_frame + current_page;
+               current_rightmost = _leftmost_sample + current_page;
                if (current_rightmost < new_page_size) {
                        leftmost_after_zoom = 0;
                } else {
@@ -1838,14 +1834,14 @@ Editor::temporal_zoom (framecnt_t fpp)
 
        case ZoomFocusPlayhead:
                /* centre playhead */
-               l = playhead_cursor->current_frame () - (new_page_size * 0.5);
+               l = playhead_cursor->current_sample () - (new_page_size * 0.5);
 
                if (l < 0) {
                        leftmost_after_zoom = 0;
-               } else if (l > max_framepos) {
-                       leftmost_after_zoom = max_framepos - new_page_size;
+               } else if (l > max_samplepos) {
+                       leftmost_after_zoom = max_samplepos - new_page_size;
                } else {
-                       leftmost_after_zoom = (framepos_t) l;
+                       leftmost_after_zoom = (samplepos_t) l;
                }
                break;
 
@@ -1853,24 +1849,24 @@ Editor::temporal_zoom (framecnt_t fpp)
                /* try to keep the mouse over the same point in the display */
 
                if (_drags->active()) {
-                       where = _drags->current_pointer_frame ();
-               } else if (!mouse_frame (where, in_track_canvas)) {
-                       use_mouse_frame = false;
+                       where = _drags->current_pointer_sample ();
+               } else if (!mouse_sample (where, in_track_canvas)) {
+                       use_mouse_sample = false;
                }
 
-               if (use_mouse_frame) {
+               if (use_mouse_sample) {
                        l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
 
                        if (l < 0) {
                                leftmost_after_zoom = 0;
-                       } else if (l > max_framepos) {
-                               leftmost_after_zoom = max_framepos - new_page_size;
+                       } else if (l > max_samplepos) {
+                               leftmost_after_zoom = max_samplepos - new_page_size;
                        } else {
-                               leftmost_after_zoom = (framepos_t) l;
+                               leftmost_after_zoom = (samplepos_t) l;
                        }
                } else {
                        /* use playhead instead */
-                       where = playhead_cursor->current_frame ();
+                       where = playhead_cursor->current_sample ();
 
                        if (where < half_page_size) {
                                leftmost_after_zoom = 0;
@@ -1883,34 +1879,28 @@ Editor::temporal_zoom (framecnt_t fpp)
        case ZoomFocusEdit:
                /* try to keep the edit point in the same place */
                where = get_preferred_edit_position ();
-
-               if (where > 0) {
-
+               {
                        double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
 
                        if (l < 0) {
                                leftmost_after_zoom = 0;
-                       } else if (l > max_framepos) {
-                               leftmost_after_zoom = max_framepos - new_page_size;
+                       } else if (l > max_samplepos) {
+                               leftmost_after_zoom = max_samplepos - new_page_size;
                        } else {
-                               leftmost_after_zoom = (framepos_t) l;
+                               leftmost_after_zoom = (samplepos_t) l;
                        }
-
-               } else {
-                       /* edit point not defined */
-                       return;
                }
                break;
 
        }
 
-       // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
+       // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_sample());
 
        reposition_and_zoom (leftmost_after_zoom, nfpp);
 }
 
 void
-Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
+Editor::calc_extra_zoom_edges(samplepos_t &start, samplepos_t &end)
 {
        /* this func helps make sure we leave a little space
           at each end of the editor so that the zoom doesn't fit the region
@@ -1923,9 +1913,9 @@ Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
        const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
        const double one_centimeter_in_pixels = pix_per_mm * 10.0;
 
-       const framepos_t range = end - start;
-       const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
-       const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
+       const samplepos_t range = end - start;
+       const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
+       const samplepos_t extra_samples = (samplepos_t) floor (one_centimeter_in_pixels * new_fpp);
 
        if (start > extra_samples) {
                start -= extra_samples;
@@ -1933,17 +1923,17 @@ Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
                start = 0;
        }
 
-       if (max_framepos - extra_samples > end) {
+       if (max_samplepos - extra_samples > end) {
                end += extra_samples;
        } else {
-               end = max_framepos;
+               end = max_samplepos;
        }
 }
 
 bool
-Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
+Editor::get_selection_extents (samplepos_t &start, samplepos_t &end) const
 {
-       start = max_framepos;
+       start = max_samplepos;
        end = 0;
        bool ret = true;
 
@@ -1951,7 +1941,7 @@ Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
 
        //ToDo:  if control points are selected, set extents to that selection
 
-       if ( !selection->regions.empty() ) {
+       if (!selection->regions.empty()) {
                RegionSelection rs = get_regions_from_selection_and_entered ();
 
                for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
@@ -1960,14 +1950,14 @@ Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
                                start = (*i)->region()->position();
                        }
 
-                       if ((*i)->region()->last_frame() + 1 > end) {
-                               end = (*i)->region()->last_frame() + 1;
+                       if ((*i)->region()->last_sample() + 1 > end) {
+                               end = (*i)->region()->last_sample() + 1;
                        }
                }
 
        } else if (!selection->time.empty()) {
                start = selection->time.start();
-               end = selection->time.end_frame();
+               end = selection->time.end_sample();
        } else
                ret = false;  //no selection found
 
@@ -1985,22 +1975,51 @@ Editor::temporal_zoom_selection (Editing::ZoomAxis axes)
 {
        if (!selection) return;
 
+       if (selection->regions.empty() && selection->time.empty()) {
+               if (axes == Horizontal || axes == Both) {
+                       temporal_zoom_step(true);
+               }
+               if (axes == Vertical || axes == Both) {
+                       if (!track_views.empty()) {
+
+                               TrackViewList tvl;
+
+                               //implicit hack: by extending the top & bottom check outside the current view limits, we include the trackviews immediately above & below what is visible
+                               const double top = vertical_adjustment.get_value() - 10;
+                               const double btm = top + _visible_canvas_height + 10;
+
+                               for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
+                                       if ((*iter)->covered_by_y_range (top, btm)) {
+                                               tvl.push_back(*iter);
+                                       }
+                               }
+
+                               fit_tracks (tvl);
+                       }
+               }
+               return;
+       }
+
        //ToDo:  if notes are selected, zoom to that
 
        //ToDo:  if control points are selected, zoom to that
 
        if (axes == Horizontal || axes == Both) {
 
-               framepos_t start, end;
+               samplepos_t start, end;
                if (get_selection_extents (start, end)) {
                        calc_extra_zoom_edges (start, end);
-                       temporal_zoom_by_frame (start, end);
+                       temporal_zoom_by_sample (start, end);
                }
        }
 
        if (axes == Vertical || axes == Both) {
                fit_selection ();
        }
+
+       //normally, we don't do anything "automatic" to the user's selection.
+       //but in this case, we will clear the selection after a zoom-to-selection.
+       selection->clear();
 }
 
 void
@@ -2009,18 +2028,18 @@ Editor::temporal_zoom_session ()
        ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
 
        if (_session) {
-               framecnt_t start = _session->current_start_frame();
-               framecnt_t end = _session->current_end_frame();
+               samplecnt_t start = _session->current_start_sample();
+               samplecnt_t end = _session->current_end_sample();
 
-               if (_session->actively_recording () ) {
-                       framepos_t cur = playhead_cursor->current_frame ();
+               if (_session->actively_recording ()) {
+                       samplepos_t cur = playhead_cursor->current_sample ();
                        if (cur > end) {
                                /* recording beyond the end marker; zoom out
                                 * by 5 seconds more so that if 'follow
                                 * playhead' is active we don't immediately
                                 * scroll.
                                 */
-                               end = cur + _session->frame_rate() * 5;
+                               end = cur + _session->sample_rate() * 5;
                        }
                }
 
@@ -2030,12 +2049,45 @@ Editor::temporal_zoom_session ()
 
                calc_extra_zoom_edges(start, end);
 
-               temporal_zoom_by_frame (start, end);
+               temporal_zoom_by_sample (start, end);
        }
 }
 
 void
-Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
+Editor::temporal_zoom_extents ()
+{
+       ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_extents)
+
+       if (_session) {
+               std::pair<samplepos_t, samplepos_t> ext = session_gui_extents (false);  //in this case we want to zoom to the extents explicitly; ignore the users prefs for extra padding
+
+               samplecnt_t start = ext.first;
+               samplecnt_t end = ext.second;
+
+               if (_session->actively_recording ()) {
+                       samplepos_t cur = playhead_cursor->current_sample ();
+                       if (cur > end) {
+                               /* recording beyond the end marker; zoom out
+                                * by 5 seconds more so that if 'follow
+                                * playhead' is active we don't immediately
+                                * scroll.
+                                */
+                               end = cur + _session->sample_rate() * 5;
+                       }
+               }
+
+               if ((start == 0 && end == 0) || end < start) {
+                       return;
+               }
+
+               calc_extra_zoom_edges(start, end);
+
+               temporal_zoom_by_sample (start, end);
+       }
+}
+
+void
+Editor::temporal_zoom_by_sample (samplepos_t start, samplepos_t end)
 {
        if (!_session) return;
 
@@ -2043,13 +2095,13 @@ Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
                return;
        }
 
-       framepos_t range = end - start;
+       samplepos_t range = end - start;
 
-       const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
+       const samplecnt_t new_fpp = (samplecnt_t) ceil ((double) range / (double) _visible_canvas_width);
 
-       framepos_t new_page = range;
-       framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
-       framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
+       samplepos_t new_page = range;
+       samplepos_t middle = (samplepos_t) floor ((double) start + ((double) range / 2.0f));
+       samplepos_t new_leftmost = (samplepos_t) floor ((double) middle - ((double) new_page / 2.0f));
 
        if (new_leftmost > middle) {
                new_leftmost = 0;
@@ -2063,14 +2115,14 @@ Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
 }
 
 void
-Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
+Editor::temporal_zoom_to_sample (bool coarser, samplepos_t sample)
 {
        if (!_session) {
                return;
        }
 
-       framecnt_t range_before = frame - leftmost_frame;
-       framecnt_t new_spp;
+       samplecnt_t range_before = sample - _leftmost_sample;
+       samplecnt_t new_spp;
 
        if (coarser) {
                if (samples_per_pixel <= 1) {
@@ -2096,13 +2148,13 @@ Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
                return;
        }
 
-       /* zoom focus is automatically taken as @param frame when this
+       /* zoom focus is automatically taken as @param sample when this
           method is used.
        */
 
-       framepos_t new_leftmost = frame - (framepos_t)range_before;
+       samplepos_t new_leftmost = sample - (samplepos_t)range_before;
 
-       if (new_leftmost > frame) {
+       if (new_leftmost > sample) {
                new_leftmost = 0;
        }
 
@@ -2115,7 +2167,7 @@ Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
 
 
 bool
-Editor::choose_new_marker_name(string &name) {
+Editor::choose_new_marker_name(string &name, bool is_range) {
 
        if (!UIConfiguration::instance().get_name_new_markers()) {
                /* don't prompt user for a new name */
@@ -2126,7 +2178,11 @@ Editor::choose_new_marker_name(string &name) {
 
        dialog.set_prompt (_("New Name:"));
 
-       dialog.set_title (_("New Location Marker"));
+       if (is_range) {
+               dialog.set_title(_("New Range"));
+       } else {
+               dialog.set_title (_("New Location Marker"));
+       }
 
        dialog.set_name ("MarkNameWindow");
        dialog.set_size_request (250, -1);
@@ -2163,10 +2219,13 @@ Editor::add_location_from_selection ()
                return;
        }
 
-       framepos_t start = selection->time[clicked_selection].start;
-       framepos_t end = selection->time[clicked_selection].end;
+       samplepos_t start = selection->time[clicked_selection].start;
+       samplepos_t end = selection->time[clicked_selection].end;
 
        _session->locations()->next_available_name(rangename,"selection");
+       if (!choose_new_marker_name(rangename, true)) {
+               return;
+       }
        Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker, get_grid_music_divisions(0));
 
        begin_reversible_command (_("add marker"));
@@ -2180,7 +2239,7 @@ Editor::add_location_from_selection ()
 }
 
 void
-Editor::add_location_mark (framepos_t where)
+Editor::add_location_mark (samplepos_t where)
 {
        string markername;
 
@@ -2209,11 +2268,11 @@ Editor::set_session_start_from_playhead ()
 
        Location* loc;
        if ((loc = _session->locations()->session_range_location()) == 0) {  //should never happen
-               _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
+               _session->set_session_extents (_session->audible_sample(), _session->audible_sample());
        } else {
                XMLNode &before = loc->get_state();
 
-               _session->set_session_extents ( _session->audible_frame(), loc->end() );
+               _session->set_session_extents (_session->audible_sample(), loc->end());
 
                XMLNode &after = loc->get_state();
 
@@ -2223,6 +2282,8 @@ Editor::set_session_start_from_playhead ()
 
                commit_reversible_command ();
        }
+
+       _session->set_session_range_is_free (false);
 }
 
 void
@@ -2233,11 +2294,11 @@ Editor::set_session_end_from_playhead ()
 
        Location* loc;
        if ((loc = _session->locations()->session_range_location()) == 0) {  //should never happen
-               _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
+               _session->set_session_extents (_session->audible_sample(), _session->audible_sample());
        } else {
                XMLNode &before = loc->get_state();
 
-               _session->set_session_extents ( loc->start(), _session->audible_frame() );
+               _session->set_session_extents (loc->start(), _session->audible_sample());
 
                XMLNode &after = loc->get_state();
 
@@ -2248,7 +2309,7 @@ Editor::set_session_end_from_playhead ()
                commit_reversible_command ();
        }
 
-       _session->set_end_is_free (false);
+       _session->set_session_range_is_free (false);
 }
 
 
@@ -2264,7 +2325,7 @@ Editor::toggle_location_at_playhead_cursor ()
 void
 Editor::add_location_from_playhead_cursor ()
 {
-       add_location_mark (_session->audible_frame());
+       add_location_mark (_session->audible_sample());
 }
 
 bool
@@ -2277,7 +2338,7 @@ Editor::do_remove_location_at_playhead_cursor ()
 
                //find location(s) at this time
                Locations::LocationList locs;
-               _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
+               _session->locations()->find_all_between (_session->audible_sample(), _session->audible_sample()+1, locs, Location::Flags(0));
                for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
                        if ((*i)->is_mark()) {
                                _session->locations()->remove (*i);
@@ -2319,7 +2380,7 @@ Editor::add_locations_from_region ()
 
                boost::shared_ptr<Region> region = (*i)->region ();
 
-               Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker, 0);
+               Location *location = new Location (*_session, region->position(), region->last_sample(), region->name(), Location::IsRangeMarker, 0);
 
                _session->locations()->add (location, true);
                commit = true;
@@ -2360,7 +2421,7 @@ Editor::add_location_from_region ()
        }
 
        // single range spanning all selected
-       Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker, 0);
+       Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_sample(), markername, Location::IsRangeMarker, 0);
        _session->locations()->add (location, true);
 
        begin_reversible_command (_("add marker"));
@@ -2378,7 +2439,7 @@ Editor::jump_forward_to_mark ()
                return;
        }
 
-       framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
+       samplepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_sample());
 
        if (pos < 0) {
                return;
@@ -2394,12 +2455,12 @@ Editor::jump_backward_to_mark ()
                return;
        }
 
-       framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
+       samplepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_sample());
 
        //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
-       if ( _session->transport_rolling() ) {
-               if ( (playhead_cursor->current_frame() - pos) < _session->frame_rate()/2 ) {
-                       framepos_t prior = _session->locations()->first_mark_before ( pos );
+       if (_session->transport_rolling()) {
+               if ((playhead_cursor->current_sample() - pos) < _session->sample_rate()/2) {
+                       samplepos_t prior = _session->locations()->first_mark_before (pos);
                        pos = prior;
                }
        }
@@ -2414,7 +2475,7 @@ Editor::jump_backward_to_mark ()
 void
 Editor::set_mark ()
 {
-       framepos_t const pos = _session->audible_frame ();
+       samplepos_t const pos = _session->audible_sample ();
 
        string markername;
        _session->locations()->next_available_name (markername, "mark");
@@ -2496,7 +2557,7 @@ Editor::unhide_ranges ()
 /* INSERT/REPLACE */
 
 void
-Editor::insert_region_list_selection (float times)
+Editor::insert_source_list_selection (float times)
 {
        RouteTimeAxisView *tv = 0;
        boost::shared_ptr<Playlist> playlist;
@@ -2519,7 +2580,7 @@ Editor::insert_region_list_selection (float times)
                return;
        }
 
-       boost::shared_ptr<Region> region = _regions->get_single_selection ();
+       boost::shared_ptr<Region> region = _sources->get_single_selection ();
        if (region == 0) {
                return;
        }
@@ -2559,7 +2620,7 @@ Editor::transition_to_rolling (bool fwd)
        }
 
        if (_session->config.get_external_sync()) {
-               switch (Config->get_sync_source()) {
+               switch (TransportMasterManager::instance().current()->type()) {
                case Engine:
                        break;
                default:
@@ -2579,7 +2640,7 @@ Editor::transition_to_rolling (bool fwd)
 void
 Editor::play_from_start ()
 {
-       _session->request_locate (_session->current_start_frame(), true);
+       _session->request_locate (_session->current_start_sample(), true);
 }
 
 void
@@ -2591,32 +2652,32 @@ Editor::play_from_edit_point ()
 void
 Editor::play_from_edit_point_and_return ()
 {
-       framepos_t start_frame;
-       framepos_t return_frame;
+       samplepos_t start_sample;
+       samplepos_t return_sample;
 
-       start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
+       start_sample = get_preferred_edit_position (EDIT_IGNORE_PHEAD);
 
        if (_session->transport_rolling()) {
-               _session->request_locate (start_frame, false);
+               _session->request_locate (start_sample, false);
                return;
        }
 
-       /* don't reset the return frame if its already set */
+       /* don't reset the return sample if its already set */
 
-       if ((return_frame = _session->requested_return_frame()) < 0) {
-               return_frame = _session->audible_frame();
+       if ((return_sample = _session->requested_return_sample()) < 0) {
+               return_sample = _session->audible_sample();
        }
 
-       if (start_frame >= 0) {
-               _session->request_roll_at_and_return (start_frame, return_frame);
+       if (start_sample >= 0) {
+               _session->request_roll_at_and_return (start_sample, return_sample);
        }
 }
 
 void
 Editor::play_selection ()
 {
-       framepos_t start, end;
-       if (!get_selection_extents ( start, end))
+       samplepos_t start, end;
+       if (!get_selection_extents (start, end))
                return;
 
        AudioRange ar (start, end, 0);
@@ -2628,9 +2689,9 @@ Editor::play_selection ()
 
 
 void
-Editor::maybe_locate_with_edit_preroll (framepos_t location)
+Editor::maybe_locate_with_edit_preroll (samplepos_t location)
 {
-       if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync() )
+       if (_session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _session->config.get_external_sync())
                return;
 
        location -= _session->preroll_samples (location);
@@ -2641,21 +2702,21 @@ Editor::maybe_locate_with_edit_preroll (framepos_t location)
        }
 
        //if follow_playhead is on, keep the playhead on the screen
-       if ( _follow_playhead )
-               if ( location < leftmost_frame )
-                       location = leftmost_frame;
+       if (_follow_playhead)
+               if (location < _leftmost_sample)
+                       location = _leftmost_sample;
 
-       _session->request_locate( location );
+       _session->request_locate (location);
 }
 
 void
 Editor::play_with_preroll ()
 {
-       framepos_t start, end;
-       if ( UIConfiguration::instance().get_follow_edits() && get_selection_extents ( start, end) ) {
-               const framepos_t preroll = _session->preroll_samples (start);
+       samplepos_t start, end;
+       if (UIConfiguration::instance().get_follow_edits() && get_selection_extents (start, end)) {
+               const samplepos_t preroll = _session->preroll_samples (start);
 
-               framepos_t ret = start;
+               samplepos_t ret = start;
 
                if (start > preroll) {
                        start = start - preroll;
@@ -2668,26 +2729,26 @@ Editor::play_with_preroll ()
                lar.push_back (ar);
 
                _session->request_play_range (&lar, true);
-               _session->set_requested_return_frame (ret);  //force auto-return to return to range start, without the preroll
+               _session->set_requested_return_sample (ret);  //force auto-return to return to range start, without the preroll
        } else {
-               framepos_t ph = playhead_cursor->current_frame ();
-               const framepos_t preroll = _session->preroll_samples (ph);
-               framepos_t start;
+               samplepos_t ph = playhead_cursor->current_sample ();
+               const samplepos_t preroll = _session->preroll_samples (ph);
+               samplepos_t start;
                if (ph > preroll) {
                        start = ph - preroll;
                } else {
                        start = 0;
                }
                _session->request_locate (start, true);
-               _session->set_requested_return_frame (ph);  //force auto-return to return to playhead location, without the preroll
+               _session->set_requested_return_sample (ph);  //force auto-return to return to playhead location, without the preroll
        }
 }
 
 void
 Editor::rec_with_preroll ()
 {
-       framepos_t ph = playhead_cursor->current_frame ();
-       framepos_t preroll = _session->preroll_samples (ph);
+       samplepos_t ph = playhead_cursor->current_sample ();
+       samplepos_t preroll = _session->preroll_samples (ph);
        _session->request_preroll_record_trim (ph, preroll);
 }
 
@@ -2891,7 +2952,7 @@ Editor::rename_region ()
 void
 Editor::play_edit_range ()
 {
-       framepos_t start, end;
+       samplepos_t start, end;
 
        if (get_edit_op_range (start, end)) {
                _session->request_bounded_roll (start, end);
@@ -2901,8 +2962,8 @@ Editor::play_edit_range ()
 void
 Editor::play_selected_region ()
 {
-       framepos_t start = max_framepos;
-       framepos_t end = 0;
+       samplepos_t start = max_samplepos;
+       samplepos_t end = 0;
 
        RegionSelection rs = get_regions_from_selection_and_entered ();
 
@@ -2914,8 +2975,8 @@ Editor::play_selected_region ()
                if ((*i)->region()->position() < start) {
                        start = (*i)->region()->position();
                }
-               if ((*i)->region()->last_frame() + 1 > end) {
-                       end = (*i)->region()->last_frame() + 1;
+               if ((*i)->region()->last_sample() + 1 > end) {
+                       end = (*i)->region()->last_sample() + 1;
                }
        }
 
@@ -2939,17 +3000,17 @@ Editor::region_from_selection ()
                return;
        }
 
-       framepos_t start = selection->time[clicked_selection].start;
-       framepos_t end = selection->time[clicked_selection].end;
+       samplepos_t start = selection->time[clicked_selection].start;
+       samplepos_t end = selection->time[clicked_selection].end;
 
        TrackViewList tracks = get_tracks_for_range_action ();
 
-       framepos_t selection_cnt = end - start + 1;
+       samplepos_t selection_cnt = end - start + 1;
 
        for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
                boost::shared_ptr<Region> current;
                boost::shared_ptr<Playlist> pl;
-               framepos_t internal_start;
+               samplepos_t internal_start;
                string new_name;
 
                if ((pl = (*i)->playlist()) == 0) {
@@ -2981,13 +3042,13 @@ Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_re
                return;
        }
 
-       framepos_t start, end;
+       samplepos_t start, end;
        if (clicked_selection) {
                start = selection->time[clicked_selection].start;
                end = selection->time[clicked_selection].end;
        } else {
                start = selection->time.start();
-               end = selection->time.end_frame();
+               end = selection->time.end_sample();
        }
 
        TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
@@ -2996,7 +3057,7 @@ Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_re
        for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
                boost::shared_ptr<Region> current;
                boost::shared_ptr<Playlist> playlist;
-               framepos_t internal_start;
+               samplepos_t internal_start;
                string new_name;
 
                if ((playlist = (*i)->playlist()) == 0) {
@@ -3032,7 +3093,7 @@ Editor::split_multichannel_region ()
        vector< boost::shared_ptr<Region> > v;
 
        for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
-               (*x)->region()->separate_by_channel (*_session, v);
+               (*x)->region()->separate_by_channel (v);
        }
 }
 
@@ -3127,8 +3188,6 @@ Editor::separate_regions_between (const TimeSelection& ts)
 
                        /* XXX need to consider musical time selections here at some point */
 
-                       double speed = rtv->track()->speed();
-
                        for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
 
                                sigc::connection c = rtv->view()->RegionViewAdded.connect (
@@ -3136,8 +3195,7 @@ Editor::separate_regions_between (const TimeSelection& ts)
 
                                latest_regionviews.clear ();
 
-                               playlist->partition ((framepos_t)((*t).start * speed),
-                                                    (framepos_t)((*t).end * speed), false);
+                               playlist->partition ((*t).start, (*t).end, false);
 
                                c.disconnect ();
 
@@ -3167,8 +3225,18 @@ Editor::separate_regions_between (const TimeSelection& ts)
                }
        }
 
-       if (in_command) {
-//             selection->set (new_selection);
+       if (in_command) {
+
+               RangeSelectionAfterSplit rsas = Config->get_range_selection_after_split();
+
+               //if our config preference says to clear the selection, clear the Range selection
+               if (rsas == ClearSel) {
+                       selection->clear_time();
+                       //but leave track selection intact
+               } else if (rsas == ForceSel) {
+                       //note: forcing the regions to be selected *might* force a tool-change to Object here
+                       selection->set(new_selection);  
+               }
 
                commit_reversible_command ();
        }
@@ -3197,8 +3265,8 @@ Editor::separate_region_from_selection ()
 
        } else {
 
-               framepos_t start;
-               framepos_t end;
+               samplepos_t start;
+               samplepos_t end;
 
                if (get_edit_op_range (start, end)) {
 
@@ -3298,16 +3366,16 @@ Editor::separate_under_selected_regions ()
                        PlaylistState before;
                        before.playlist = playlist;
                        before.before = &playlist->get_state();
-
+                       playlist->clear_changes ();
                        playlist->freeze ();
                        playlists.push_back(before);
                }
 
                //Partition on the region bounds
-               playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
+               playlist->partition ((*rl)->first_sample() - 1, (*rl)->last_sample() + 1, true);
 
                //Re-add region that was just removed due to the partition operation
-               playlist->add_region( (*rl), (*rl)->first_frame() );
+               playlist->add_region ((*rl), (*rl)->first_sample());
        }
 
        vector<PlaylistState>::iterator pl;
@@ -3325,22 +3393,29 @@ Editor::crop_region_to_selection ()
 {
        if (!selection->time.empty()) {
 
-               crop_region_to (selection->time.start(), selection->time.end_frame());
-
+               begin_reversible_command (_("Crop Regions to Time Selection"));
+               for (std::list<AudioRange>::iterator i = selection->time.begin(); i != selection->time.end(); ++i) {
+                       crop_region_to ((*i).start, (*i).end);
+               }
+               commit_reversible_command();
        } else {
 
-               framepos_t start;
-               framepos_t end;
+               samplepos_t start;
+               samplepos_t end;
 
                if (get_edit_op_range (start, end)) {
+                       begin_reversible_command (_("Crop Regions to Edit Range"));
+
                        crop_region_to (start, end);
+
+                       commit_reversible_command();
                }
        }
 
 }
 
 void
-Editor::crop_region_to (framepos_t start, framepos_t end)
+Editor::crop_region_to (samplepos_t start, samplepos_t end)
 {
        vector<boost::shared_ptr<Playlist> > playlists;
        boost::shared_ptr<Playlist> playlist;
@@ -3376,11 +3451,10 @@ Editor::crop_region_to (framepos_t start, framepos_t end)
                return;
        }
 
-       framepos_t pos;
-       framepos_t new_start;
-       framepos_t new_end;
-       framecnt_t new_length;
-       bool in_command = false;
+       samplepos_t pos;
+       samplepos_t new_start;
+       samplepos_t new_end;
+       samplecnt_t new_length;
 
        for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
 
@@ -3402,27 +3476,19 @@ Editor::crop_region_to (framepos_t start, framepos_t end)
 
                        pos = (*i)->position();
                        new_start = max (start, pos);
-                       if (max_framepos - pos > (*i)->length()) {
+                       if (max_samplepos - pos > (*i)->length()) {
                                new_end = pos + (*i)->length() - 1;
                        } else {
-                               new_end = max_framepos;
+                               new_end = max_samplepos;
                        }
                        new_end = min (end, new_end);
                        new_length = new_end - new_start + 1;
 
-                       if(!in_command) {
-                               begin_reversible_command (_("trim to selection"));
-                               in_command = true;
-                       }
                        (*i)->clear_changes ();
                        (*i)->trim_to (new_start, new_length);
                        _session->add_command (new StatefulDiffCommand (*i));
                }
        }
-
-       if (in_command) {
-               commit_reversible_command ();
-       }
 }
 
 void
@@ -3432,15 +3498,15 @@ Editor::region_fill_track ()
        RegionSelection regions = get_regions_from_selection_and_entered ();
        RegionSelection foo;
 
-       framepos_t const end = _session->current_end_frame ();
+       samplepos_t const end = _session->current_end_sample ();
 
-       if (regions.empty () || regions.end_frame () + 1 >= end) {
+       if (regions.empty () || regions.end_sample () + 1 >= end) {
                return;
        }
 
-       framepos_t const start_frame = regions.start ();
-       framepos_t const end_frame = regions.end_frame ();
-       framecnt_t const gap = end_frame - start_frame + 1;
+       samplepos_t const start_sample = regions.start ();
+       samplepos_t const end_sample = regions.end_sample ();
+       samplecnt_t const gap = end_sample - start_sample + 1;
 
        begin_reversible_command (Operations::region_fill);
 
@@ -3455,7 +3521,7 @@ Editor::region_fill_track ()
                latest_regionviews.clear ();
                sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
 
-               framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
+               samplepos_t const position = end_sample + (r->first_sample() - start_sample + 1);
                playlist = (*i)->region()->playlist();
                playlist->clear_changes ();
                playlist->duplicate_until (r, position, gap, end);
@@ -3480,7 +3546,7 @@ Editor::set_region_sync_position ()
 }
 
 void
-Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
+Editor::set_sync_point (samplepos_t where, const RegionSelection& rs)
 {
        bool in_command = false;
 
@@ -3564,7 +3630,7 @@ Editor::align_regions (RegionPoint what)
 
        begin_reversible_command (_("align selection"));
 
-       framepos_t const position = get_preferred_edit_position ();
+       samplepos_t const position = get_preferred_edit_position ();
 
        for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
                align_region_internal ((*i)->region(), what, position);
@@ -3588,10 +3654,10 @@ Editor::align_regions_relative (RegionPoint point)
                return;
        }
 
-       framepos_t const position = get_preferred_edit_position ();
+       samplepos_t const position = get_preferred_edit_position ();
 
-       framepos_t distance = 0;
-       framepos_t pos = 0;
+       samplepos_t distance = 0;
+       samplepos_t pos = 0;
        int dir = 1;
 
        list<RegionView*> sorted;
@@ -3611,11 +3677,11 @@ Editor::align_regions_relative (RegionPoint point)
                break;
 
        case End:
-               if (position > r->last_frame()) {
-                       distance = position - r->last_frame();
+               if (position > r->last_sample()) {
+                       distance = position - r->last_sample();
                        pos = r->position() + distance;
                } else {
-                       distance = r->last_frame() - position;
+                       distance = r->last_sample() - position;
                        pos = r->position() - distance;
                        dir = -1;
                }
@@ -3668,7 +3734,7 @@ Editor::align_regions_relative (RegionPoint point)
 }
 
 void
-Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
+Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, samplepos_t position)
 {
        begin_reversible_command (_("align region"));
        align_region_internal (region, point, position);
@@ -3676,7 +3742,7 @@ Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, frame
 }
 
 void
-Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
+Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, samplepos_t position)
 {
        region->clear_changes ();
 
@@ -3714,7 +3780,7 @@ Editor::trim_region_back ()
 void
 Editor::trim_region (bool front)
 {
-       framepos_t where = get_preferred_edit_position();
+       samplepos_t where = get_preferred_edit_position();
        RegionSelection rs = get_regions_from_selection_and_edit_point ();
 
        if (rs.empty()) {
@@ -3784,16 +3850,11 @@ Editor::trim_region_to_location (const Location& loc, const char* str)
                        return;
                }
 
-               float speed = 1.0;
-               framepos_t start;
-               framepos_t end;
+               samplepos_t start;
+               samplepos_t end;
 
-               if (tav->track() != 0) {
-                       speed = tav->track()->speed();
-               }
-
-               start = session_frame_to_track_frame (loc.start(), speed);
-               end = session_frame_to_track_frame (loc.end(), speed);
+               start = loc.start();
+               end = loc.end();
 
                rv->region()->clear_changes ();
                rv->region()->trim_to (start, (end - start));
@@ -3844,13 +3905,6 @@ Editor::trim_to_region(bool forward)
                        continue;
                }
 
-               float speed = 1.0;
-
-               if (atav->track() != 0) {
-                       speed = atav->track()->speed();
-               }
-
-
                boost::shared_ptr<Region> region = arv->region();
                boost::shared_ptr<Playlist> playlist (region->playlist());
 
@@ -3858,25 +3912,24 @@ Editor::trim_to_region(bool forward)
 
                if (forward) {
 
-                       next_region = playlist->find_next_region (region->first_frame(), Start, 1);
+                       next_region = playlist->find_next_region (region->first_sample(), Start, 1);
 
                        if (!next_region) {
                                continue;
                        }
 
-                       region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
-                       arv->region_changed (PropertyChange (ARDOUR::Properties::length));
+                   region->trim_end (next_region->first_sample() - 1);
+                   arv->region_changed (PropertyChange (ARDOUR::Properties::length));
                }
                else {
 
-                       next_region = playlist->find_next_region (region->first_frame(), Start, 0);
+                       next_region = playlist->find_next_region (region->first_sample(), Start, 0);
 
-                       if(!next_region){
+                       if (!next_region) {
                                continue;
                        }
 
-                       region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
-
+                       region->trim_front (next_region->last_sample() + 1);
                        arv->region_changed (ARDOUR::bounds_change);
                }
 
@@ -3939,7 +3992,7 @@ Editor::freeze_route ()
        }
 
        if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
-               MessageDialog d (
+               ArdourMessageDialog d (
                        _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
                          "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
                        );
@@ -3949,9 +4002,9 @@ Editor::freeze_route ()
        }
 
        if (clicked_routeview->track()->has_external_redirects()) {
-               MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
-                                                  "Freezing will only process the signal as far as the first send/insert/return."),
-                                                clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
+               ArdourMessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
+                                                        "Freezing will only process the signal as far as the first send/insert/return."),
+                                                      clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
 
                d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
                d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
@@ -4000,7 +4053,7 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
 
                        if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
-                               MessageDialog d (
+                               ArdourMessageDialog d (
                                        _("You can't perform this operation because the processing of the signal "
                                          "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
                                          "You can do this without processing, which is a different operation.")
@@ -4012,9 +4065,9 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
                }
        }
 
-       framepos_t start = selection->time[clicked_selection].start;
-       framepos_t end = selection->time[clicked_selection].end;
-       framepos_t cnt = end - start + 1;
+       samplepos_t start = selection->time[clicked_selection].start;
+       samplepos_t end = selection->time[clicked_selection].end;
+       samplepos_t cnt = end - start + 1;
        bool in_command = false;
 
        for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
@@ -4078,7 +4131,7 @@ Editor::delete_ ()
        //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
        //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
        bool deleted = false;
-       if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
+       if (current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip())
                deleted = current_mixer_strip->delete_processors ();
 
        if (!deleted)
@@ -4148,8 +4201,9 @@ Editor::cut_copy (CutCopyOp op)
                }
        }
 
-       if ( op != Delete )  //"Delete" doesn't change copy/paste buf
+       if (op != Delete) { //"Delete" doesn't change copy/paste buf
                cut_buffer->clear ();
+       }
 
        if (entered_marker) {
 
@@ -4200,7 +4254,7 @@ Editor::cut_copy (CutCopyOp op)
                        }
                }
        } else if (selection->time.empty()) {
-               framepos_t start, end;
+               samplepos_t start, end;
                /* no time selection, see if we can get an edit range
                   and use that.
                */
@@ -4221,7 +4275,7 @@ Editor::cut_copy (CutCopyOp op)
        if (did_edit) {
                /* reset repeated paste state */
                paste_count    = 0;
-               last_paste_pos = 0;
+               last_paste_pos = -1;
                commit_reversible_command ();
        }
 
@@ -4250,7 +4304,7 @@ struct PointsSelectionPositionSorter {
  *  @param op Operation (Cut, Copy or Clear)
  */
 void
-Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
+Editor::cut_copy_points (Editing::CutCopyOp op, Temporal::Beats earliest, bool midi)
 {
        if (selection->points.empty ()) {
                return;
@@ -4287,7 +4341,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid
                }
 
                /* Add all selected points to the relevant copy ControlLists */
-               MusicFrame start (std::numeric_limits<framepos_t>::max(), 0);
+               MusicSample start (std::numeric_limits<samplepos_t>::max(), 0);
                for (PointSelection::iterator sel_point = selection->points.begin(); sel_point != selection->points.end(); ++sel_point) {
                        boost::shared_ptr<AutomationList>    al = (*sel_point)->line().the_list();
                        AutomationList::const_iterator ctrl_evt = (*sel_point)->model ();
@@ -4295,27 +4349,27 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid
                        lists[al].copy->fast_simple_add ((*ctrl_evt)->when, (*ctrl_evt)->value);
                        if (midi) {
                                /* Update earliest MIDI start time in beats */
-                               earliest = std::min(earliest, Evoral::Beats((*ctrl_evt)->when));
+                               earliest = std::min(earliest, Temporal::Beats((*ctrl_evt)->when));
                        } else {
-                               /* Update earliest session start time in frames */
-                               start.frame = std::min(start.frame, (*sel_point)->line().session_position(ctrl_evt));
+                               /* Update earliest session start time in samples */
+                               start.sample = std::min(start.sample, (*sel_point)->line().session_position(ctrl_evt));
                        }
                }
 
                /* Snap start time backwards, so copy/paste is snap aligned. */
                if (midi) {
-                       if (earliest == Evoral::Beats::max()) {
-                               earliest = Evoral::Beats();  // Weird... don't offset
+                       if (earliest == std::numeric_limits<Temporal::Beats>::max()) {
+                               earliest = Temporal::Beats();  // Weird... don't offset
                        }
                        earliest.round_down_to_beat();
                } else {
-                       if (start.frame == std::numeric_limits<double>::max()) {
-                               start.frame = 0;  // Weird... don't offset
+                       if (start.sample == std::numeric_limits<double>::max()) {
+                               start.sample = 0;  // Weird... don't offset
                        }
                        snap_to(start, RoundDownMaybe);
                }
 
-               const double line_offset = midi ? earliest.to_double() : start.frame;
+               const double line_offset = midi ? earliest.to_double() : start.sample;
                for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
                        /* Correct this copy list so that it is relative to the earliest
                           start time, so relative ordering between points is preserved
@@ -4372,7 +4426,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool mid
 void
 Editor::cut_copy_midi (CutCopyOp op)
 {
-       Evoral::Beats earliest = Evoral::Beats::max();
+       Temporal::Beats earliest = std::numeric_limits<Temporal::Beats>::max();
        for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
                MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
                if (mrv) {
@@ -4418,12 +4472,15 @@ Editor::remove_clicked_region ()
        begin_reversible_command (_("remove region"));
 
        boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
+       boost::shared_ptr<Region> region = clicked_regionview->region();
 
        playlist->clear_changes ();
        playlist->clear_owned_changes ();
-       playlist->remove_region (clicked_regionview->region());
-       if (Config->get_edit_mode() == Ripple)
-               playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
+       playlist->remove_region (region);
+
+       if (Config->get_edit_mode() == Ripple) {
+               playlist->ripple (region->position(), - region->length(), boost::shared_ptr<Region>());
+       }
 
        /* We might have removed regions, which alters other regions' layering_index,
           so we need to do a recursive diff here.
@@ -4437,6 +4494,32 @@ Editor::remove_clicked_region ()
 }
 
 
+void
+Editor::recover_regions (ARDOUR::RegionList regions)
+{
+#ifdef RECOVER_REGIONS_IS_WORKING
+       begin_reversible_command (_("recover regions"));
+
+       for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
+               boost::shared_ptr<ARDOUR::Source> source = (*i)->source();
+
+               RouteList routes = _session->get_routelist();
+               for (RouteList::iterator it = routes.begin(); it != routes.end(); ++it) {
+                       boost::shared_ptr<ARDOUR::Track> track = boost::dynamic_pointer_cast<Track>(*it);
+                       if (track) {
+                               //ToDo
+                               if (source->captured_for() == track->) {
+                                       //_session->add_command(new StatefulDiffCommand (playlist));    
+                               }
+                       }
+               }
+       }
+
+       commit_reversible_command ();
+#endif
+}
+
+
 /** Remove the selected regions */
 void
 Editor::remove_selected_regions ()
@@ -4527,7 +4610,7 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
 
        vector<PlaylistMapping> pmap;
 
-       framepos_t first_position = max_framepos;
+       samplepos_t first_position = max_samplepos;
 
        typedef set<boost::shared_ptr<Playlist> > FreezeList;
        FreezeList freezelist;
@@ -4538,7 +4621,7 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
 
        for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
 
-               first_position = min ((framepos_t) (*x)->region()->position(), first_position);
+               first_position = min ((samplepos_t) (*x)->region()->position(), first_position);
 
                if (op == Cut || op == Clear || op == Delete) {
                        boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
@@ -4718,25 +4801,25 @@ void
 Editor::paste (float times, bool from_context)
 {
        DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
-       MusicFrame where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
-       paste_internal (where.frame, times, 0);
+       MusicSample where (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), 0);
+       paste_internal (where.sample, times, 0);
 }
 
 void
 Editor::mouse_paste ()
 {
-       MusicFrame where (0, 0);
+       MusicSample where (0, 0);
        bool ignored;
-       if (!mouse_frame (where.frame, ignored)) {
+       if (!mouse_sample (where.sample, ignored)) {
                return;
        }
 
        snap_to (where);
-       paste_internal (where.frame, 1, where.division);
+       paste_internal (where.sample, 1, where.division);
 }
 
 void
-Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
+Editor::paste_internal (samplepos_t position, float times, const int32_t sub_num)
 {
        DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
 
@@ -4744,15 +4827,12 @@ Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
                return;
        }
 
-       if (position == max_framepos) {
+       if (position == max_samplepos) {
                position = get_preferred_edit_position();
                DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
        }
 
-       if (position == last_paste_pos) {
-               /* repeated paste in the same position */
-               ++paste_count;
-       } else {
+       if (position != last_paste_pos) {
                /* paste in new location, reset repeated paste state */
                paste_count = 0;
                last_paste_pos = position;
@@ -4841,6 +4921,8 @@ Editor::paste_internal (framepos_t position, float times, const int32_t sub_num)
                }
        }
 
+       ++paste_count;
+
        commit_reversible_command ();
 }
 
@@ -4859,17 +4941,40 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times)
        }
 
        boost::shared_ptr<Playlist> playlist;
+       std::set<boost::shared_ptr<Playlist> > playlists; // list of unique playlists affected by duplication
        RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
        RegionSelection foo;
 
-       framepos_t const start_frame = regions.start ();
-       framepos_t const end_frame = regions.end_frame ();
-       framecnt_t const gap = end_frame - start_frame + 1;
+       samplepos_t const start_sample = regions.start ();
+       samplepos_t const end_sample = regions.end_sample ();
+       samplecnt_t const span = end_sample - start_sample + 1;
 
        begin_reversible_command (Operations::duplicate_region);
 
        selection->clear_regions ();
 
+       /* ripple first so that we don't move the duplicates that will be added */
+
+       if (Config->get_edit_mode() == Ripple) {
+
+               /* convert RegionSelection into RegionList so that we can pass it to ripple and exclude the regions we will duplicate */
+
+               RegionList exclude;
+
+               for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
+                       exclude.push_back ((*i)->region());
+                       playlist = (*i)->region()->playlist();
+                       if (playlists.insert (playlist).second) {
+                               /* successfully inserted into set, so it's the first time we've seen this playlist */
+                               playlist->clear_changes ();
+                       }
+               }
+
+               for (set<boost::shared_ptr<Playlist> >::iterator p = playlists.begin(); p != playlists.end(); ++p) {
+                       (*p)->ripple (start_sample, span * times, &exclude);
+               }
+       }
+
        for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
 
                boost::shared_ptr<Region> r ((*i)->region());
@@ -4879,17 +4984,29 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times)
                latest_regionviews.clear ();
                sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
 
-               framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
+               samplepos_t const position = end_sample + (r->first_sample() - start_sample + 1);
                playlist = (*i)->region()->playlist();
-               playlist->clear_changes ();
-               playlist->duplicate (r, position, gap, times);
-               _session->add_command(new StatefulDiffCommand (playlist));
+
+               if (Config->get_edit_mode() != Ripple) {
+                       if (playlists.insert (playlist).second) {
+                               playlist->clear_changes ();
+                       }
+               }
+
+               playlist->duplicate (r, position, span, times);
 
                c.disconnect ();
 
                foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
        }
 
+       for (set<boost::shared_ptr<Playlist> >::iterator p = playlists.begin(); p != playlists.end(); ++p) {
+               _session->add_command (new StatefulDiffCommand (*p));
+               vector<Command*> cmds;
+               (*p)->rdiff (cmds);
+               _session->add_commands (cmds);
+       }
+
        if (!foo.empty()) {
                selection->set (foo);
        }
@@ -4933,13 +5050,13 @@ Editor::duplicate_selection (float times)
        if (in_command) {
                if (times == 1.0f) {
                        // now "move" range selection to after the current range selection
-                       framecnt_t distance = 0;
+                       samplecnt_t distance = 0;
 
                        if (clicked_selection) {
                                distance =
                                    selection->time[clicked_selection].end - selection->time[clicked_selection].start;
                        } else {
-                               distance = selection->time.end_frame () - selection->time.start ();
+                               distance = selection->time.end_sample () - selection->time.start ();
                        }
 
                        selection->move_time (distance);
@@ -4962,7 +5079,7 @@ void
 Editor::center_playhead ()
 {
        float const page = _visible_canvas_width * samples_per_pixel;
-       center_screen_internal (playhead_cursor->current_frame (), page);
+       center_screen_internal (playhead_cursor->current_sample (), page);
 }
 
 void
@@ -4985,9 +5102,9 @@ void
 Editor::nudge_track (bool use_edit, bool forwards)
 {
        boost::shared_ptr<Playlist> playlist;
-       framepos_t distance;
-       framepos_t next_distance;
-       framepos_t start;
+       samplepos_t distance;
+       samplepos_t next_distance;
+       samplepos_t start;
 
        if (use_edit) {
                start = get_preferred_edit_position();
@@ -5064,6 +5181,95 @@ Editor::remove_last_capture ()
        }
 }
 
+void
+Editor::tag_regions (RegionList regions)
+{
+       ArdourDialog d (_("Tag Last Capture"), true, false);
+       Entry entry;
+       Label label (_("Tag:"));
+       HBox hbox;
+
+       hbox.set_spacing (6);
+       hbox.pack_start (label, false, false);
+       hbox.pack_start (entry, true, true);
+
+       d.get_vbox()->set_border_width (12);
+       d.get_vbox()->pack_start (hbox, false, false);
+
+       d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+       d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
+
+       d.set_size_request (300, -1);
+
+       entry.set_text (_("Good"));
+       entry.select_region (0, -1);
+
+       entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
+
+       d.show_all ();
+
+       entry.grab_focus();
+
+       int const ret = d.run();
+
+       d.hide ();
+
+       if (ret != RESPONSE_OK) {
+               return;
+       }
+
+       std::string tagstr = entry.get_text();
+       strip_whitespace_edges (tagstr);
+       
+       if (!tagstr.empty()) {
+               for (RegionList::iterator r = regions.begin(); r != regions.end(); r++) {
+                       (*r)->set_tags(tagstr);
+               }
+                       
+               _regions->redisplay ();
+       }
+}
+
+void
+Editor::tag_selected_region ()
+{
+       std::list<boost::shared_ptr<Region> > rlist;
+
+       RegionSelection rs = get_regions_from_selection_and_entered ();
+       for (RegionSelection::iterator r = rs.begin(); r != rs.end(); r++) {
+               rlist.push_back((*r)->region());
+       }
+
+       tag_regions(rlist);
+}
+
+void
+Editor::tag_last_capture ()
+{
+       if (!_session) {
+               return;
+       }
+
+       std::list<boost::shared_ptr<Region> > rlist;
+
+       std::list<boost::shared_ptr<Source> > srcs;
+       _session->get_last_capture_sources (srcs);
+       for (std::list<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+               boost::shared_ptr<ARDOUR::Source> source = (*i);
+               if (source) {
+
+                       set<boost::shared_ptr<Region> > regions;
+                       RegionFactory::get_regions_using_source (source, regions);
+                       for (set<boost::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); r++) {
+                               rlist.push_back(*r);
+                       }
+
+               }
+       }
+       
+       tag_regions(rlist);
+}
+
 void
 Editor::normalize_region ()
 {
@@ -5325,13 +5531,13 @@ Editor::strip_region_silence ()
 Command*
 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
 {
-       Evoral::Sequence<Evoral::Beats>::Notes selected;
+       Evoral::Sequence<Temporal::Beats>::Notes selected;
        mrv.selection_as_notelist (selected, true);
 
-       vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
+       vector<Evoral::Sequence<Temporal::Beats>::Notes> v;
        v.push_back (selected);
 
-       Evoral::Beats pos_beats  = Evoral::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
+       Temporal::Beats pos_beats  = Temporal::Beats (mrv.midi_region()->beat()) - mrv.midi_region()->start_beats();
 
        return op (mrv.midi_region()->model(), pos_beats, v);
 }
@@ -5368,6 +5574,7 @@ Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
 
        if (in_command) {
                commit_reversible_command ();
+               _session->set_dirty ();
        }
 }
 
@@ -5537,7 +5744,7 @@ Editor::insert_patch_change (bool from_context)
                return;
        }
 
-       const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
+       const samplepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
 
        /* XXX: bit of a hack; use the MIDNAM from the first selected region;
           there may be more than one, but the PatchChangeDialog can only offer
@@ -5545,7 +5752,7 @@ Editor::insert_patch_change (bool from_context)
        */
        MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
 
-       Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
+       Evoral::PatchChange<Temporal::Beats> empty (Temporal::Beats(), 0, 0, 0);
        PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
 
        if (d.run() == RESPONSE_CANCEL) {
@@ -5555,7 +5762,7 @@ Editor::insert_patch_change (bool from_context)
        for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
                MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
                if (mrv) {
-                       if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
+                       if (p >= mrv->region()->first_sample() && p <= mrv->region()->last_sample()) {
                                mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
                        }
                }
@@ -5866,6 +6073,54 @@ Editor::toggle_record_enable ()
        }
 }
 
+StripableList
+tracklist_to_stripables (TrackViewList list)
+{
+       StripableList ret;
+
+       for (TrackSelection::iterator i = list.begin(); i != list.end(); ++i) {
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> ((*i));
+
+               if (rtv && rtv->is_track()) {
+                       ret.push_back (rtv->track());
+               }
+       }
+
+       return ret;
+}
+
+void
+Editor::play_solo_selection (bool restart)
+{
+       //note: session::solo_selection takes care of invalidating the region playlist
+
+       if ((!selection->tracks.empty()) && selection->time.length() > 0) {  //a range is selected; solo the tracks and roll
+
+               StripableList sl = tracklist_to_stripables (selection->tracks);
+               _session->solo_selection (sl, true);
+
+               if (restart) {
+                       samplepos_t start = selection->time.start();
+                       samplepos_t end = selection->time.end_sample();
+                       _session->request_bounded_roll (start, end);
+               }
+       } else if (! selection->tracks.empty()) {  //no range is selected, but tracks are selected; solo the tracks and roll
+               StripableList sl = tracklist_to_stripables (selection->tracks);
+               _session->solo_selection (sl, true);
+               _session->request_cancel_play_range();
+               transition_to_rolling (true);
+
+       } else if (! selection->regions.empty()) {  //solo any tracks with selected regions, and roll
+               StripableList sl = tracklist_to_stripables (get_tracks_for_range_action());
+               _session->solo_selection (sl, true);
+               _session->request_cancel_play_range();
+               transition_to_rolling (true);
+       } else {
+               _session->request_cancel_play_range();
+               transition_to_rolling (true);  //no selection.  just roll.
+       }
+}
+
 void
 Editor::toggle_solo ()
 {
@@ -5874,18 +6129,18 @@ Editor::toggle_solo ()
        boost::shared_ptr<ControlList> cl (new ControlList);
 
        for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
-               RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
+               StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
 
-               if (!rtav) {
+               if (!stav || !stav->stripable()->solo_control()) {
                        continue;
                }
 
                if (first) {
-                       new_state = !rtav->route()->soloed ();
+                       new_state = !stav->stripable()->solo_control()->soloed ();
                        first = false;
                }
 
-               cl->push_back (rtav->route()->solo_control());
+               cl->push_back (stav->stripable()->solo_control());
        }
 
        _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
@@ -5896,24 +6151,26 @@ Editor::toggle_mute ()
 {
        bool new_state = false;
        bool first = true;
-       boost::shared_ptr<RouteList> rl (new RouteList);
+       boost::shared_ptr<ControlList> cl (new ControlList);
 
        for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
-               RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
+               StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
 
-               if (!rtav) {
+               if (!stav || !stav->stripable()->mute_control()) {
                        continue;
                }
 
                if (first) {
-                       new_state = !rtav->route()->muted();
+                       new_state = !stav->stripable()->mute_control()->muted();
                        first = false;
                }
 
-               rl->push_back (rtav->route());
+               boost::shared_ptr<MuteControl> mc = stav->stripable()->mute_control();
+               cl->push_back (mc);
+               mc->start_touch (_session->audible_sample ());
        }
 
-       _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
+       _session->set_controls (cl, new_state, Controllable::UseGroup);
 }
 
 void
@@ -5950,11 +6207,11 @@ Editor::set_fade_length (bool in)
 
        RegionView* rv = rs.front ();
 
-       framepos_t pos = get_preferred_edit_position();
-       framepos_t len;
+       samplepos_t pos = get_preferred_edit_position();
+       samplepos_t len;
        char const * cmd;
 
-       if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
+       if (pos > rv->region()->last_sample() || pos < rv->region()->first_sample()) {
                /* edit point is outside the relevant region */
                return;
        }
@@ -5967,11 +6224,11 @@ Editor::set_fade_length (bool in)
                len = pos - rv->region()->position();
                cmd = _("set fade in length");
        } else {
-               if (pos >= rv->region()->last_frame()) {
+               if (pos >= rv->region()->last_sample()) {
                        /* can't do it */
                        return;
                }
-               len = rv->region()->last_frame() - pos;
+               len = rv->region()->last_sample() - pos;
                cmd = _("set fade out length");
        }
 
@@ -6236,9 +6493,9 @@ void
 Editor::set_edit_point ()
 {
        bool ignored;
-       MusicFrame where (0, 0);
+       MusicSample where (0, 0);
 
-       if (!mouse_frame (where.frame, ignored)) {
+       if (!mouse_sample (where.sample, ignored)) {
                return;
        }
 
@@ -6246,7 +6503,7 @@ Editor::set_edit_point ()
 
        if (selection->markers.empty()) {
 
-               mouse_add_new_marker (where.frame);
+               mouse_add_new_marker (where.sample);
 
        } else {
                bool ignored;
@@ -6254,7 +6511,7 @@ Editor::set_edit_point ()
                Location* loc = find_location_from_marker (selection->markers.front(), ignored);
 
                if (loc) {
-                       loc->move_to (where.frame, where.division);
+                       loc->move_to (where.sample, where.division);
                }
        }
 }
@@ -6265,17 +6522,17 @@ Editor::set_playhead_cursor ()
        if (entered_marker) {
                _session->request_locate (entered_marker->position(), _session->transport_rolling());
        } else {
-               MusicFrame where (0, 0);
+               MusicSample where (0, 0);
                bool ignored;
 
-               if (!mouse_frame (where.frame, ignored)) {
+               if (!mouse_sample (where.sample, ignored)) {
                        return;
                }
 
                snap_to (where);
 
                if (_session) {
-                       _session->request_locate (where.frame, _session->transport_rolling());
+                       _session->request_locate (where.sample, _session->transport_rolling());
                }
        }
 
@@ -6289,99 +6546,69 @@ Editor::set_playhead_cursor ()
 void
 Editor::split_region ()
 {
-       if (_drags->active ()) {
+       if (_dragging_playhead) {
+               /*continue*/
+       } else if (_drags->active ()) {
+               /*any other kind of drag, bail out so we avoid Undo snafu*/
                return;
        }
 
        //if a range is selected, separate it
-       if ( !selection->time.empty()) {
+       if (!selection->time.empty()) {
                separate_regions_between (selection->time);
                return;
        }
 
        //if no range was selected, try to find some regions to split
-       if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
+       if (current_mouse_mode() == MouseObject || current_mouse_mode() == MouseRange ) {  //don't try this for Internal Edit, Stretch, Draw, etc.
+
+               RegionSelection rs;
+
+               //new behavior:  the Split action will prioritize the entered_regionview rather than selected regions.
+               //this fixes the unexpected case where you point at a region, but
+               //  * nothing happens OR
+               //  * some other region (maybe off-screen) is split.
+               //NOTE:  if the entered_regionview is /part of the selection/ then we should operate on the selection as usual
+               if (_edit_point == EditAtMouse && entered_regionview && !entered_regionview->selected()) {
+                       rs.add (entered_regionview);
+               } else {
+                       rs = selection->regions;   //might be empty
+               }
+
+               if (rs.empty()) {
+                       TrackViewList tracks = selection->tracks;
+
+                       if (!tracks.empty()) {
+                               /* no region selected or entered, but some selected tracks:
+                                * act on all regions on the selected tracks at the edit point
+                                */
+                               samplepos_t const where = get_preferred_edit_position (Editing::EDIT_IGNORE_NONE, false, false);
+                               get_regions_at(rs, where, tracks);
+                       }
+               }
 
-               RegionSelection rs = get_regions_from_selection_and_edit_point ();
-               const framepos_t pos = get_preferred_edit_position();
+               const samplepos_t pos = get_preferred_edit_position();
                const int32_t division = get_grid_music_divisions (0);
-               MusicFrame where (pos, division);
+               MusicSample where (pos, division);
 
                if (rs.empty()) {
                        return;
                }
 
                split_regions_at (where, rs);
-
        }
 }
 
 void
-Editor::select_next_route()
+Editor::select_next_stripable (bool routes_only)
 {
-       if (selection->tracks.empty()) {
-               selection->set (track_views.front());
-               return;
-       }
-
-       TimeAxisView* current = selection->tracks.front();
-
-       RouteUI *rui;
-       do {
-               for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
-
-                       if (*i == current) {
-                               ++i;
-                               if (i != track_views.end()) {
-                                       current = (*i);
-                               } else {
-                                       current = (*(track_views.begin()));
-                                       //selection->set (*(track_views.begin()));
-                               }
-                               break;
-                       }
-               }
-
-               rui = dynamic_cast<RouteUI *>(current);
-
-       } while (current->hidden() || (rui == NULL) || !rui->route()->active());
-
-       selection->set (current);
-
-       ensure_time_axis_view_is_visible (*current, false);
+       _session->selection().select_next_stripable (false, routes_only);
 }
 
 void
-Editor::select_prev_route()
+Editor::select_prev_stripable (bool routes_only)
 {
-       if (selection->tracks.empty()) {
-               selection->set (track_views.front());
-               return;
-       }
-
-       TimeAxisView* current = selection->tracks.front();
-
-       RouteUI *rui;
-       do {
-               for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
-
-                       if (*i == current) {
-                               ++i;
-                               if (i != track_views.rend()) {
-                                       current = (*i);
-                               } else {
-                                       current = *(track_views.rbegin());
-                               }
-                               break;
-                       }
-               }
-               rui = dynamic_cast<RouteUI *>(current);
-
-       } while (current->hidden() || (rui == NULL) || !rui->route()->active());
-
-       selection->set (current);
-
-       ensure_time_axis_view_is_visible (*current, false);
+       _session->selection().select_prev_stripable (false, routes_only);
 }
 
 void
@@ -6391,8 +6618,8 @@ Editor::set_loop_from_selection (bool play)
                return;
        }
 
-       framepos_t start, end;
-       if (!get_selection_extents ( start, end))
+       samplepos_t start, end;
+       if (!get_selection_extents (start, end))
                return;
 
        set_loop_range (start, end,  _("set loop range from selection"));
@@ -6405,8 +6632,8 @@ Editor::set_loop_from_selection (bool play)
 void
 Editor::set_loop_from_region (bool play)
 {
-       framepos_t start, end;
-       if (!get_selection_extents ( start, end))
+       samplepos_t start, end;
+       if (!get_selection_extents (start, end))
                return;
 
        set_loop_range (start, end, _("set loop range from region"));
@@ -6424,8 +6651,8 @@ Editor::set_punch_from_selection ()
                return;
        }
 
-       framepos_t start, end;
-       if (!get_selection_extents ( start, end))
+       samplepos_t start, end;
+       if (!get_selection_extents (start, end))
                return;
 
        set_punch_range (start, end,  _("set punch range from selection"));
@@ -6446,9 +6673,9 @@ Editor::set_auto_punch_range ()
        }
 
        Location* tpl = transport_punch_location();
-       framepos_t now = playhead_cursor->current_frame();
-       framepos_t begin = now;
-       framepos_t end = _session->current_end_frame();
+       samplepos_t now = playhead_cursor->current_sample();
+       samplepos_t begin = now;
+       samplepos_t end = _session->current_end_sample();
 
        if (!_session->config.get_punch_in()) {
                // First Press - set punch in and create range from here to eternity
@@ -6462,11 +6689,11 @@ Editor::set_auto_punch_range ()
                        set_punch_range (begin, end, _("Auto Punch In/Out"));
                } else {
                        // normal case for 2nd press - set the punch out
-                       end = playhead_cursor->current_frame ();
+                       end = playhead_cursor->current_sample ();
                        set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
                        _session->config.set_punch_out(true);
                }
-       } else  {
+       } else {
                if (_session->config.get_punch_out()) {
                        _session->config.set_punch_out(false);
                }
@@ -6491,8 +6718,8 @@ Editor::set_session_extents_from_selection ()
                return;
        }
 
-       framepos_t start, end;
-       if (!get_selection_extents ( start, end))
+       samplepos_t start, end;
+       if (!get_selection_extents (start, end))
                return;
 
        Location* loc;
@@ -6512,7 +6739,7 @@ Editor::set_session_extents_from_selection ()
                commit_reversible_command ();
        }
 
-       _session->set_end_is_free (false);
+       _session->set_session_range_is_free (false);
 }
 
 void
@@ -6520,8 +6747,8 @@ Editor::set_punch_start_from_edit_point ()
 {
        if (_session) {
 
-               MusicFrame start (0, 0);
-               framepos_t end = max_framepos;
+               MusicSample start (0, 0);
+               samplepos_t end = max_samplepos;
 
                //use the existing punch end, if any
                Location* tpl = transport_punch_location();
@@ -6530,20 +6757,17 @@ Editor::set_punch_start_from_edit_point ()
                }
 
                if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
-                       start.frame = _session->audible_frame();
+                       start.sample = _session->audible_sample();
                } else {
-                       start.frame = get_preferred_edit_position();
+                       start.sample = get_preferred_edit_position();
                }
 
-               //snap the selection start/end
-               snap_to(start);
-
                //if there's not already a sensible selection endpoint, go "forever"
-               if (start.frame > end ) {
-                       end = max_framepos;
+               if (start.sample > end) {
+                       end = max_samplepos;
                }
 
-               set_punch_range (start.frame, end, _("set punch start from EP"));
+               set_punch_range (start.sample, end, _("set punch start from EP"));
        }
 
 }
@@ -6553,8 +6777,8 @@ Editor::set_punch_end_from_edit_point ()
 {
        if (_session) {
 
-               framepos_t start = 0;
-               MusicFrame end (max_framepos, 0);
+               samplepos_t start = 0;
+               MusicSample end (max_samplepos, 0);
 
                //use the existing punch start, if any
                Location* tpl = transport_punch_location();
@@ -6563,15 +6787,12 @@ Editor::set_punch_end_from_edit_point ()
                }
 
                if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
-                       end.frame = _session->audible_frame();
+                       end.sample = _session->audible_sample();
                } else {
-                       end.frame = get_preferred_edit_position();
+                       end.sample = get_preferred_edit_position();
                }
 
-               //snap the selection start/end
-               snap_to (end);
-
-               set_punch_range (start, end.frame, _("set punch end from EP"));
+               set_punch_range (start, end.sample, _("set punch end from EP"));
 
        }
 }
@@ -6581,8 +6802,8 @@ Editor::set_loop_start_from_edit_point ()
 {
        if (_session) {
 
-               MusicFrame start (0, 0);
-               framepos_t end = max_framepos;
+               MusicSample start (0, 0);
+               samplepos_t end = max_samplepos;
 
                //use the existing loop end, if any
                Location* tpl = transport_loop_location();
@@ -6591,20 +6812,17 @@ Editor::set_loop_start_from_edit_point ()
                }
 
                if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
-                       start.frame = _session->audible_frame();
+                       start.sample = _session->audible_sample();
                } else {
-                       start.frame = get_preferred_edit_position();
+                       start.sample = get_preferred_edit_position();
                }
 
-               //snap the selection start/end
-               snap_to (start);
-
                //if there's not already a sensible selection endpoint, go "forever"
-               if (start.frame > end ) {
-                       end = max_framepos;
+               if (start.sample > end) {
+                       end = max_samplepos;
                }
 
-               set_loop_range (start.frame, end, _("set loop start from EP"));
+               set_loop_range (start.sample, end, _("set loop start from EP"));
        }
 
 }
@@ -6614,8 +6832,8 @@ Editor::set_loop_end_from_edit_point ()
 {
        if (_session) {
 
-               framepos_t start = 0;
-               MusicFrame end (max_framepos, 0);
+               samplepos_t start = 0;
+               MusicSample end (max_samplepos, 0);
 
                //use the existing loop start, if any
                Location* tpl = transport_loop_location();
@@ -6624,23 +6842,20 @@ Editor::set_loop_end_from_edit_point ()
                }
 
                if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
-                       end.frame = _session->audible_frame();
+                       end.sample = _session->audible_sample();
                } else {
-                       end.frame = get_preferred_edit_position();
+                       end.sample = get_preferred_edit_position();
                }
 
-               //snap the selection start/end
-               snap_to(end);
-
-               set_loop_range (start, end.frame, _("set loop end from EP"));
+               set_loop_range (start, end.sample, _("set loop end from EP"));
        }
 }
 
 void
 Editor::set_punch_from_region ()
 {
-       framepos_t start, end;
-       if (!get_selection_extents ( start, end))
+       samplepos_t start, end;
+       if (!get_selection_extents (start, end))
                return;
 
        set_punch_range (start, end, _("set punch range from region"));
@@ -6676,40 +6891,40 @@ Editor::set_tempo_from_region ()
 
        RegionView* rv = rs.front();
 
-       define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
+       define_one_bar (rv->region()->position(), rv->region()->last_sample() + 1);
 }
 
 void
 Editor::use_range_as_bar ()
 {
-       framepos_t start, end;
+       samplepos_t start, end;
        if (get_edit_op_range (start, end)) {
                define_one_bar (start, end);
        }
 }
 
 void
-Editor::define_one_bar (framepos_t start, framepos_t end)
+Editor::define_one_bar (samplepos_t start, samplepos_t end)
 {
-       framepos_t length = end - start;
+       samplepos_t length = end - start;
 
-       const Meter& m (_session->tempo_map().meter_at_frame (start));
+       const Meter& m (_session->tempo_map().meter_at_sample (start));
 
        /* length = 1 bar */
 
        /* We're going to deliver a constant tempo here,
-          so we can use frames per beat to determine length.
-          now we want frames per beat.
-          we have frames per bar, and beats per bar, so ...
+          so we can use samples per beat to determine length.
+          now we want samples per beat.
+          we have samples per bar, and beats per bar, so ...
        */
 
        /* XXXX METER MATH */
 
-       double frames_per_beat = length / m.divisions_per_bar();
+       double samples_per_beat = length / m.divisions_per_bar();
 
        /* beats per minute = */
 
-       double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
+       double beats_per_minute = (_session->sample_rate() * 60.0) / samples_per_beat;
 
        /* now decide whether to:
 
@@ -6718,7 +6933,7 @@ Editor::define_one_bar (framepos_t start, framepos_t end)
 
        */
 
-       const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
+       const TempoSection& t (_session->tempo_map().tempo_section_at_sample (start));
 
        bool do_global = false;
 
@@ -6766,7 +6981,7 @@ Editor::define_one_bar (framepos_t start, framepos_t end)
 
        if (do_global) {
                _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
-       } else if (t.frame() == start) {
+       } else if (t.sample() == start) {
                _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
        } else {
                /* constant tempo */
@@ -6834,10 +7049,10 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
        if (positions.size() > 20 && can_ferret) {
                std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
-               MessageDialog msg (msgstr,
-                                  false,
-                                  Gtk::MESSAGE_INFO,
-                                  Gtk::BUTTONS_OK_CANCEL);
+               ArdourMessageDialog msg (msgstr,
+                                        false,
+                                        Gtk::MESSAGE_INFO,
+                                        Gtk::BUTTONS_OK_CANCEL);
 
                if (can_ferret) {
                        msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
@@ -6847,8 +7062,6 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
                }
 
                msg.set_title (_("Excessive split?"));
-               msg.present ();
-
                int response = msg.run();
                msg.hide ();
 
@@ -6882,10 +7095,10 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
        pl->freeze ();
        pl->remove_region (r);
 
-       framepos_t pos = 0;
+       samplepos_t pos = 0;
 
-       framepos_t rstart = r->first_frame ();
-       framepos_t rend = r->last_frame ();
+       samplepos_t rstart = r->first_sample ();
+       samplepos_t rend = r->last_sample ();
 
        while (x != positions.end()) {
 
@@ -6897,11 +7110,11 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
 
                /* file start = original start + how far we from the initial position ?  */
 
-               framepos_t file_start = r->start() + pos;
+               samplepos_t file_start = r->start() + pos;
 
                /* length = next position - current position */
 
-               framepos_t len = (*x) - pos - rstart;
+               samplepos_t len = (*x) - pos - rstart;
 
                /* XXX we do we really want to allow even single-sample regions?
                 * shouldn't we have some kind of lower limit on region size?
@@ -6951,7 +7164,7 @@ Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList
        PropertyList plist;
 
        plist.add (ARDOUR::Properties::start, r->start() + pos);
-       plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
+       plist.add (ARDOUR::Properties::length, r->last_sample() - (r->position() + pos) + 1);
        plist.add (ARDOUR::Properties::name, new_name);
        plist.add (ARDOUR::Properties::layer, 0);
 
@@ -6998,7 +7211,7 @@ Editor::place_transient()
                return;
        }
 
-       framepos_t where = get_preferred_edit_position();
+       samplepos_t where = get_preferred_edit_position();
 
        begin_reversible_command (_("place transient"));
 
@@ -7049,9 +7262,9 @@ Editor::snap_regions_to_grid ()
                }
                (*r)->region()->clear_changes ();
 
-               MusicFrame start ((*r)->region()->first_frame (), 0);
-               snap_to (start);
-               (*r)->region()->set_position (start.frame, start.division);
+               MusicSample start ((*r)->region()->first_sample (), 0);
+               snap_to (start, RoundNearest, SnapToGrid_Unscaled, true);
+               (*r)->region()->set_position (start.sample, start.division);
                _session->add_command(new StatefulDiffCommand ((*r)->region()));
        }
 
@@ -7111,11 +7324,11 @@ Editor::close_region_gaps ()
                return;
        }
 
-       framepos_t crossfade_len = spin_crossfade.get_value();
-       framepos_t pull_back_frames = spin_pullback.get_value();
+       samplepos_t crossfade_len = spin_crossfade.get_value();
+       samplepos_t pull_back_samples = spin_pullback.get_value();
 
-       crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
-       pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
+       crossfade_len = lrintf (crossfade_len * _session->sample_rate()/1000);
+       pull_back_samples = lrintf (pull_back_samples * _session->sample_rate()/1000);
 
        /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
 
@@ -7138,7 +7351,7 @@ Editor::close_region_gaps ()
                        pl->freeze();
                }
 
-               framepos_t position = (*r)->region()->position();
+               samplepos_t position = (*r)->region()->position();
 
                if (idx == 0 || position < last_region->position()){
                        last_region = (*r)->region();
@@ -7147,10 +7360,10 @@ Editor::close_region_gaps ()
                }
 
                (*r)->region()->clear_changes ();
-               (*r)->region()->trim_front( (position - pull_back_frames));
+               (*r)->region()->trim_front((position - pull_back_samples));
 
                last_region->clear_changes ();
-               last_region->trim_end( (position - pull_back_frames + crossfade_len));
+               last_region->trim_end ((position - pull_back_samples + crossfade_len));
 
                _session->add_command (new StatefulDiffCommand ((*r)->region()));
                _session->add_command (new StatefulDiffCommand (last_region));
@@ -7179,7 +7392,7 @@ Editor::tab_to_transient (bool forward)
                return;
        }
 
-       framepos_t pos = _session->audible_frame ();
+       samplepos_t pos = _session->audible_sample ();
 
        if (!selection->tracks.empty()) {
 
@@ -7197,7 +7410,7 @@ Editor::tab_to_transient (bool forward)
                                if (tr) {
                                        boost::shared_ptr<Playlist> pl = tr->playlist ();
                                        if (pl) {
-                                               framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
+                                               samplepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
 
                                                if (result >= 0) {
                                                        positions.push_back (result);
@@ -7218,7 +7431,7 @@ Editor::tab_to_transient (bool forward)
                }
        }
 
-       TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
+       TransientDetector::cleanup_transients (positions, _session->sample_rate(), 3.0);
 
        if (forward) {
                AnalysisFeatureList::iterator x;
@@ -7255,12 +7468,28 @@ Editor::playhead_forward_to_grid ()
                return;
        }
 
-       MusicFrame pos (playhead_cursor->current_frame (), 0);
+       MusicSample pos  (playhead_cursor->current_sample (), 0);
+
+       if ( _grid_type == GridTypeNone) {
+               if (pos.sample < max_samplepos - current_page_samples()*0.1) {
+                       pos.sample += current_page_samples()*0.1;
+                       _session->request_locate (pos.sample);
+               } else {
+                       _session->request_locate (0);
+               }
+       } else {
+
+               if (pos.sample < max_samplepos - 1) {
+                       pos.sample += 2;
+                       pos = snap_to_grid (pos, RoundUpAlways, SnapToGrid_Scaled);
+                       _session->request_locate (pos.sample);
+               }
+       }
+
 
-       if (pos.frame < max_framepos - 1) {
-               pos.frame += 2;
-               snap_to_internal (pos, RoundUpAlways, false);
-               _session->request_locate (pos.frame);
+       /* keep PH visible in window */
+       if (pos.sample > (_leftmost_sample + current_page_samples() *0.9)) {
+               reset_x_origin (pos.sample - (current_page_samples()*0.9));
        }
 }
 
@@ -7272,12 +7501,36 @@ Editor::playhead_backward_to_grid ()
                return;
        }
 
-       MusicFrame pos  (playhead_cursor->current_frame (), 0);
+       MusicSample pos  (playhead_cursor->current_sample (), 0);
+
+       if ( _grid_type == GridTypeNone) {
+               if ( pos.sample > current_page_samples()*0.1 ) {
+                       pos.sample -= current_page_samples()*0.1;
+                       _session->request_locate (pos.sample);
+               } else {
+                       _session->request_locate (0);
+               }
+       } else {
+
+               if (pos.sample > 2) {
+                       pos.sample -= 2;
+                       pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled);
+               }
 
-       if (pos.frame > 2) {
-               pos.frame -= 2;
-               snap_to_internal (pos, RoundDownAlways, false);
-               _session->request_locate (pos.frame);
+               //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark...
+               //also see:  jump_backward_to_mark
+               if (_session->transport_rolling()) {
+                       if ((playhead_cursor->current_sample() - pos.sample) < _session->sample_rate()/2) {
+                               pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled);
+                       }
+               }
+
+               _session->request_locate (pos.sample, _session->transport_rolling());
+       }
+
+       /* keep PH visible in window */
+       if (pos.sample < (_leftmost_sample + current_page_samples() *0.1)) {
+               reset_x_origin (pos.sample - (current_page_samples()*0.1));
        }
 }
 
@@ -7342,24 +7595,37 @@ Editor::_remove_tracks ()
                return;
        }
 
+       if (!ARDOUR_UI_UTILS::engine_is_running ()) {
+               return;
+       }
+
        vector<string> choices;
        string prompt;
        int ntracks = 0;
        int nbusses = 0;
+       int nvcas = 0;
        const char* trackstr;
        const char* busstr;
+       const char* vcastr;
        vector<boost::shared_ptr<Route> > routes;
+       vector<boost::shared_ptr<VCA> > vcas;
        bool special_bus = false;
 
        for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
+               VCATimeAxisView* vtv = dynamic_cast<VCATimeAxisView*> (*x);
+               if (vtv) {
+                       vcas.push_back (vtv->vca());
+                       ++nvcas;
+                       continue;
+               }
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
                if (!rtv) {
                        continue;
                }
                if (rtv->is_track()) {
-                       ntracks++;
+                       ++ntracks;
                } else {
-                       nbusses++;
+                       ++nbusses;
                }
                routes.push_back (rtv->_route);
 
@@ -7369,62 +7635,83 @@ Editor::_remove_tracks ()
        }
 
        if (special_bus && !Config->get_allow_special_bus_removal()) {
-               MessageDialog msg (_("That would be bad news ...."),
-                                  false,
-                                  Gtk::MESSAGE_INFO,
-                                  Gtk::BUTTONS_OK);
-               msg.set_secondary_text (string_compose (_(
-                                                               "Removing the master or monitor bus is such a bad idea\n\
+               ArdourMessageDialog msg (_("That would be bad news ...."),
+                                        false,
+                                        Gtk::MESSAGE_INFO,
+                                        Gtk::BUTTONS_OK);
+               msg.set_secondary_text (string_compose (_("Removing the master or monitor bus is such a bad idea\n\
 that %1 is not going to allow it.\n\
 \n\
 If you really want to do this sort of thing\n\
 edit your ardour.rc file to set the\n\
 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
 
-               msg.present ();
                msg.run ();
                return;
        }
 
-       if (ntracks + nbusses == 0) {
+       if (ntracks + nbusses + nvcas == 0) {
                return;
        }
 
+       string title;
+
        trackstr = P_("track", "tracks", ntracks);
        busstr = P_("bus", "busses", nbusses);
+       vcastr = P_("VCA", "VCAs", nvcas);
 
-       if (ntracks) {
-               if (nbusses) {
-                       prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
-                                                   "(You may also lose the playlists associated with the %2)\n\n"
-                                                   "This action cannot be undone, and the session file will be overwritten!"),
-                                                 ntracks, trackstr, nbusses, busstr);
-               } else {
-                       prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
-                                                   "(You may also lose the playlists associated with the %2)\n\n"
-                                                   "This action cannot be undone, and the session file will be overwritten!"),
-                                                 ntracks, trackstr);
-               }
-       } else if (nbusses) {
-               prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
-                                           "This action cannot be undone, and the session file will be overwritten"),
-                                         nbusses, busstr);
+       if (ntracks > 0 && nbusses > 0 && nvcas > 0) {
+               title = _("Remove various strips");
+               prompt = string_compose (_("Do you really want to remove %1 %2, %3 %4 and %5 %6?"),
+                                                 ntracks, trackstr, nbusses, busstr, nvcas, vcastr);
+       }
+       else if (ntracks > 0 && nbusses > 0) {
+               title = string_compose (_("Remove %1 and %2"), trackstr, busstr);
+               prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
+                               ntracks, trackstr, nbusses, busstr);
+       }
+       else if (ntracks > 0 && nvcas > 0) {
+               title = string_compose (_("Remove %1 and %2"), trackstr, vcastr);
+               prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
+                               ntracks, trackstr, nvcas, vcastr);
+       }
+       else if (nbusses > 0 && nvcas > 0) {
+               title = string_compose (_("Remove %1 and %2"), busstr, vcastr);
+               prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
+                               nbusses, busstr, nvcas, vcastr);
+       }
+       else if (ntracks > 0) {
+               title = string_compose (_("Remove %1"), trackstr);
+               prompt  = string_compose (_("Do you really want to remove %1 %2?"),
+                               ntracks, trackstr);
+       }
+       else if (nbusses > 0) {
+               title = string_compose (_("Remove %1"), busstr);
+               prompt  = string_compose (_("Do you really want to remove %1 %2?"),
+                               nbusses, busstr);
+       }
+       else if (nvcas > 0) {
+               title = string_compose (_("Remove %1"), vcastr);
+               prompt  = string_compose (_("Do you really want to remove %1 %2?"),
+                               nvcas, vcastr);
+       }
+       else {
+               assert (0);
+       }
+
+       if (ntracks > 0) {
+                       prompt += "\n" + string_compose ("(You may also lose the playlists associated with the %1)", trackstr) + "\n";
        }
 
+       prompt += "\n" + string(_("This action cannot be undone, and the session file will be overwritten!"));
+
        choices.push_back (_("No, do nothing."));
-       if (ntracks + nbusses > 1) {
+       if (ntracks + nbusses + nvcas > 1) {
                choices.push_back (_("Yes, remove them."));
        } else {
                choices.push_back (_("Yes, remove it."));
        }
 
-       string title;
-       if (ntracks) {
-               title = string_compose (_("Remove %1"), trackstr);
-       } else {
-               title = string_compose (_("Remove %1"), busstr);
-       }
-
        Choice prompter (title, prompt, choices);
 
        if (prompter.run () != 1) {
@@ -7435,7 +7722,7 @@ edit your ardour.rc file to set the\n\
                /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
                 * route). If the deleted route is currently displayed in the Editor-Mixer (highly
                 * likely because deletion requires selection) this will call
-                * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
+                * Editor::set_selected_mixer_strip () which is expensive (MixerStrip::set_route()).
                 * It's likewise likely that the route that has just been displayed in the
                 * Editor-Mixer will be next in line for deletion.
                 *
@@ -7458,6 +7745,11 @@ edit your ardour.rc file to set the\n\
                        rl->push_back (*x);
                }
                _session->remove_routes (rl);
+
+               for (vector<boost::shared_ptr<VCA> >::iterator x = vcas.begin(); x != vcas.end(); ++x) {
+                       _session->vca_manager().remove_vca (*x);
+               }
+
        }
        /* TrackSelection and RouteList leave scope,
         * destructors are called,
@@ -7469,6 +7761,16 @@ void
 Editor::do_insert_time ()
 {
        if (selection->tracks.empty()) {
+               ArdourMessageDialog msg (_("You must first select some tracks to Insert Time."),
+                                  true, MESSAGE_INFO, BUTTONS_OK, true);
+               msg.run ();
+               return;
+       }
+
+       if (Config->get_edit_mode() == Lock) {
+               ArdourMessageDialog msg (_("You cannot insert time in Lock Edit mode."),
+                                        true, MESSAGE_INFO, BUTTONS_OK, true);
+               msg.run ();
                return;
        }
 
@@ -7498,7 +7800,7 @@ Editor::do_insert_time ()
 
 void
 Editor::insert_time (
-       framepos_t pos, framecnt_t frames, InsertTimeOption opt,
+       samplepos_t pos, samplecnt_t samples, InsertTimeOption opt,
        bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
        )
 {
@@ -7524,7 +7826,7 @@ Editor::insert_time (
                if (all_playlists) {
                        RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
                        if (rtav && rtav->track ()) {
-                               vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
+                               vector<boost::shared_ptr<Playlist> > all = _session->playlists()->playlists_for_track (rtav->track ());
                                for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
                                        pl.insert (*p);
                                }
@@ -7547,10 +7849,10 @@ Editor::insert_time (
 
                        if (opt == SplitIntersected) {
                                /* non musical split */
-                               (*i)->split (MusicFrame (pos, 0));
+                               (*i)->split (MusicSample (pos, 0));
                        }
 
-                       (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
+                       (*i)->shift (pos, samples, (opt == MoveIntersected), ignore_music_glue);
 
                        vector<Command*> cmds;
                        (*i)->rdiff (cmds);
@@ -7566,7 +7868,7 @@ Editor::insert_time (
                                begin_reversible_command (_("insert time"));
                                in_command = true;
                        }
-                       rtav->route ()->shift (pos, frames);
+                       rtav->route ()->shift (pos, samples);
                }
        }
 
@@ -7590,9 +7892,9 @@ Editor::insert_time (
                                if ((*i)->start() >= pos) {
                                        // move end first, in case we're moving by more than the length of the range
                                        if (!(*i)->is_mark()) {
-                                               (*i)->set_end ((*i)->end() + frames, false, true, divisions);
+                                               (*i)->set_end ((*i)->end() + samples, false, true, divisions);
                                        }
-                                       (*i)->set_start ((*i)->start() + frames, false, true, divisions);
+                                       (*i)->set_start ((*i)->start() + samples, false, true, divisions);
                                        moved = true;
                                }
 
@@ -7618,7 +7920,7 @@ Editor::insert_time (
                        in_command = true;
                }
                XMLNode& before (_session->tempo_map().get_state());
-               _session->tempo_map().insert_time (pos, frames);
+               _session->tempo_map().insert_time (pos, samples);
                XMLNode& after (_session->tempo_map().get_state());
                _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
        }
@@ -7632,6 +7934,16 @@ void
 Editor::do_remove_time ()
 {
        if (selection->tracks.empty()) {
+               ArdourMessageDialog msg (_("You must first select some tracks to Remove Time."),
+                                        true, MESSAGE_INFO, BUTTONS_OK, true);
+               msg.run ();
+               return;
+       }
+
+       if (Config->get_edit_mode() == Lock) {
+               ArdourMessageDialog msg (_("You cannot remove time in Lock Edit mode."),
+                                        true, MESSAGE_INFO, BUTTONS_OK, true);
+               msg.run ();
                return;
        }
 
@@ -7643,7 +7955,7 @@ Editor::do_remove_time ()
                return;
        }
 
-       framecnt_t distance = d.distance();
+       samplecnt_t distance = d.distance();
 
        if (distance == 0) {
                return;
@@ -7662,7 +7974,7 @@ Editor::do_remove_time ()
 }
 
 void
-Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
+Editor::remove_time (samplepos_t pos, samplecnt_t samples, InsertTimeOption opt,
                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
 {
        if (Config->get_edit_mode() == Lock) {
@@ -7685,10 +7997,10 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
                        }
 
                        std::list<AudioRange> rl;
-                       AudioRange ar(pos, pos+frames, 0);
+                       AudioRange ar(pos, pos+samples, 0);
                        rl.push_back(ar);
                        pl->cut (rl);
-                       pl->shift (pos, -frames, true, ignore_music_glue);
+                       pl->shift (pos, -samples, true, ignore_music_glue);
 
                        XMLNode &after = pl->get_state();
 
@@ -7702,7 +8014,7 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
                                begin_reversible_command (_("remove time"));
                                in_command = true;
                        }
-                       rtav->route ()->shift (pos, -frames);
+                       rtav->route ()->shift (pos, -samples);
                }
        }
 
@@ -7725,39 +8037,39 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
 
                                if (!(*i)->is_mark()) {  // it's a range;  have to handle both start and end
                                        if ((*i)->end() >= pos
-                                       && (*i)->end() < pos+frames
+                                       && (*i)->end() < pos+samples
                                        && (*i)->start() >= pos
-                                       && (*i)->end() < pos+frames) {  // range is completely enclosed;  kill it
+                                       && (*i)->end() < pos+samples) {  // range is completely enclosed;  kill it
                                                moved = true;
                                                loc_kill_list.push_back(*i);
                                        } else {  // only start or end is included, try to do the right thing
                                                // move start before moving end, to avoid trying to move the end to before the start
                                                // if we're removing more time than the length of the range
-                                               if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
+                                               if ((*i)->start() >= pos && (*i)->start() < pos+samples) {
                                                        // start is within cut
                                                        (*i)->set_start (pos, false, true,divisions);  // bring the start marker to the beginning of the cut
                                                        moved = true;
-                                               } else if ((*i)->start() >= pos+frames) {
+                                               } else if ((*i)->start() >= pos+samples) {
                                                        // start (and thus entire range) lies beyond end of cut
-                                                       (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
+                                                       (*i)->set_start ((*i)->start() - samples, false, true, divisions); // slip the start marker back
                                                        moved = true;
                                                }
-                                               if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
+                                               if ((*i)->end() >= pos && (*i)->end() < pos+samples) {
                                                        // end is inside cut
                                                        (*i)->set_end (pos, false, true, divisions);  // bring the end to the cut
                                                        moved = true;
-                                               } else if ((*i)->end() >= pos+frames) {
+                                               } else if ((*i)->end() >= pos+samples) {
                                                        // end is beyond end of cut
-                                                       (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
+                                                       (*i)->set_end ((*i)->end() - samples, false, true, divisions); // slip the end marker back
                                                        moved = true;
                                                }
 
                                        }
-                               } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
+                               } else if ((*i)->start() >= pos && (*i)->start() < pos+samples) {
                                        loc_kill_list.push_back(*i);
                                        moved = true;
                                } else if ((*i)->start() >= pos) {
-                                       (*i)->set_start ((*i)->start() -frames, false, true, divisions);
+                                       (*i)->set_start ((*i)->start() -samples, false, true, divisions);
                                        moved = true;
                                }
 
@@ -7768,7 +8080,7 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
                }
 
                for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
-                       _session->locations()->remove( *i );
+                       _session->locations()->remove (*i);
                }
 
                if (moved) {
@@ -7784,7 +8096,7 @@ Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
        if (tempo_too) {
                XMLNode& before (_session->tempo_map().get_state());
 
-               if (_session->tempo_map().remove_time (pos, frames) ) {
+               if (_session->tempo_map().remove_time (pos, samples)) {
                        if (!in_command) {
                                begin_reversible_command (_("remove time"));
                                in_command = true;
@@ -7859,7 +8171,8 @@ Editor::fit_tracks (TrackViewList & tracks)
        double first_y_pos = DBL_MAX;
 
        if (h < TimeAxisView::preset_height (HeightSmall)) {
-               MessageDialog msg (_("There are too many tracks to fit in the current window"));
+               ArdourMessageDialog msg (_("There are too many tracks to fit in the current window"));
+               msg.run ();
                /* too small to be displayed */
                return;
        }