use syntactic sugar
[ardour.git] / gtk2_ardour / editor.cc
index be2e6b719d4ea6b46e6ea0bba1ea8bd64b719652..3f78e49ca775802169b9a9398056c12850737952 100644 (file)
@@ -79,6 +79,7 @@
 #include "ardour/vca.h"
 
 #include "canvas/debug.h"
+#include "canvas/note.h"
 #include "canvas/text.h"
 
 #include "widgets/ardour_spacer.h"
@@ -181,7 +182,7 @@ static const gchar *_grid_type_strings[] = {
        N_("1/28 (32nd septuplet)"),
        N_("Timecode"),
        N_("MinSec"),
-       N_("Samples"),
+       N_("CD Frames"),
        0
 };
 
@@ -223,7 +224,7 @@ static const gchar *_rb_opt_strings[] = {
 };
 #endif
 
-//Robin says: this should be odd to accomodate cairo drawing offset ( width/2 rounds up to pixel boundary )
+/* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
 #ifdef __APPLE__
 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
 #else
@@ -447,7 +448,6 @@ Editor::Editor ()
        , _stepping_axis_view (0)
        , quantize_dialog (0)
        , _main_menu_disabler (0)
-       , myactions (X_("editor"))
 {
        /* we are a singleton */
 
@@ -611,7 +611,7 @@ Editor::Editor ()
        pad_line_1->set_outline_color (0xFF0000FF);
        pad_line_1->show();
 
-       // CAIROCANVAS
+       /* CAIROCANVAS */
        time_pad->show();
 
        edit_packer.set_col_spacings (0);
@@ -624,12 +624,19 @@ Editor::Editor ()
        time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
        time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
 
+       ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
+       axis_view_shadow->set_size_request (4, -1);
+       axis_view_shadow->set_name("EditorWindow");
+       axis_view_shadow->show();
+
+       edit_packer.attach (*axis_view_shadow,     0, 1, 0, 2,    FILL,        FILL|EXPAND, 0, 0);
+
        /* labels for the time bars */
-       edit_packer.attach (time_bars_event_box,     0, 1, 0, 1,    FILL,        SHRINK, 0, 0);
+       edit_packer.attach (time_bars_event_box,     1, 2, 0, 1,    FILL,        SHRINK, 0, 0);
        /* track controls */
-       edit_packer.attach (controls_layout,         0, 1, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
+       edit_packer.attach (controls_layout,         1, 2, 1, 2,    FILL,        FILL|EXPAND, 0, 0);
        /* canvas */
-       edit_packer.attach (*_track_canvas_viewport,  1, 2, 0, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
+       edit_packer.attach (*_track_canvas_viewport,  2, 3, 0, 2,    FILL|EXPAND, FILL|EXPAND, 0, 0);
 
        bottom_hbox.set_border_width (2);
        bottom_hbox.set_spacing (3);
@@ -691,14 +698,14 @@ Editor::Editor ()
        VBox* summary_arrows_right = manage (new VBox);
        summary_arrows_right->pack_start (*summary_arrow_right);
 
-       Frame* summary_sample = manage (new Frame);
-       summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
+       Frame* summary_frame = manage (new Frame);
+       summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
 
-       summary_sample->add (*_summary);
-       summary_sample->show ();
+       summary_frame->add (*_summary);
+       summary_frame->show ();
 
        _summary_hbox.pack_start (*summary_arrows_left, false, false);
-       _summary_hbox.pack_start (*summary_sample, true, true);
+       _summary_hbox.pack_start (*summary_frame, true, true);
        _summary_hbox.pack_start (*summary_arrows_right, false, false);
 
        if (!ARDOUR::Profile->get_trx()) {
@@ -730,23 +737,30 @@ Editor::Editor ()
        }
        editor_summary_pane.set_divider (0, fract);
 
-       global_vpacker.set_spacing (2);
+       global_vpacker.set_spacing (0);
        global_vpacker.set_border_width (0);
 
-       //the next three EventBoxes provide the ability for their child widgets to have a background color.  That is all.
+       /* the next three EventBoxes provide the ability for their child widgets to have a background color.  That is all. */
 
-       Gtk::EventBox* ebox = manage (new Gtk::EventBox);  //a themeable box
+       Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
        ebox->set_name("EditorWindow");
-       ebox->add (toolbar_hbox);
+       ebox->add (ebox_hpacker);
 
-       Gtk::EventBox* epane_box = manage (new EventBoxExt);  //a themeable box
+       Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
        epane_box->set_name("EditorWindow");
        epane_box->add (edit_pane);
 
-       Gtk::EventBox* epane_box2 = manage (new EventBoxExt);  //a themeable box
+       Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
        epane_box2->set_name("EditorWindow");
        epane_box2->add (global_vpacker);
 
+       ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
+       toolbar_shadow->set_size_request (-1, 4);
+       toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
+       toolbar_shadow->set_name("EditorWindow");
+       toolbar_shadow->show();
+
+       global_vpacker.pack_start (*toolbar_shadow, false, false);
        global_vpacker.pack_start (*ebox, false, false);
        global_vpacker.pack_start (*epane_box, true, true);
        global_hpacker.pack_start (*epane_box2, true, true);
@@ -755,11 +769,13 @@ Editor::Editor ()
         */
 
        global_hpacker.show ();
+       ebox_hpacker.show();
+       ebox->show();
 
        /* register actions now so that set_state() can find them and set toggles/checks etc */
 
-       register_actions ();
        load_bindings ();
+       register_actions ();
 
        setup_toolbar ();
 
@@ -844,8 +860,6 @@ Editor::Editor ()
        setup_fade_images ();
 
        set_grid_to (GridTypeNone);
-
-       instant_save ();
 }
 
 Editor::~Editor()
@@ -967,15 +981,11 @@ Editor::set_entered_track (TimeAxisView* tav)
 void
 Editor::instant_save ()
 {
-       if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
+       if (!constructed || !_session || no_save_instant) {
                return;
        }
 
-       if (_session) {
-               _session->add_instant_xml(get_state());
-       } else {
-               Config->add_instant_xml(get_state());
-       }
+       _session->add_instant_xml(get_state());
 }
 
 void
@@ -1116,7 +1126,7 @@ bool
 Editor::deferred_control_scroll (samplepos_t /*target*/)
 {
        _session->request_locate (*_control_scroll_target, _session->transport_rolling());
-       // reset for next stream
+       /* reset for next stream */
        _control_scroll_target = boost::none;
        _dragging_playhead = false;
        return false;
@@ -1132,7 +1142,7 @@ Editor::access_action (const std::string& action_group, const std::string& actio
        ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
 
        RefPtr<Action> act;
-       act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
+       act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
 
        if (act) {
                act->activate();
@@ -1310,10 +1320,11 @@ Editor::set_session (Session *t)
                return;
        }
 
-       //initialize _leftmost_sample to the extents of the session
-       //this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample before the visible state has been loaded from instant.xml
+       /* initialize _leftmost_sample to the extents of the session
+        * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
+        * before the visible state has been loaded from instant.xml */
        _leftmost_sample = session_gui_extents().first;
-       
+
        _playlist_selector->set_session (_session);
        nudge_clock->set_session (_session);
        _summary->set_session (_session);
@@ -1348,15 +1359,15 @@ Editor::set_session (Session *t)
 
        loc = _session->locations()->auto_punch_location();
        if (loc != 0) {
-               // force name
+               /* force name */
                loc->set_name (_("Punch"));
        }
 
        refresh_location_display ();
 
        /* This must happen after refresh_location_display(), as (amongst other things) we restore
-          the selected Marker; this needs the LocationMarker list to be available.
-       */
+        * the selected Marker; this needs the LocationMarker list to be available.
+        */
        XMLNode* node = ARDOUR_UI::instance()->editor_settings();
        set_state (*node, Stateful::loading_state_version);
 
@@ -2145,9 +2156,9 @@ Editor::grid_musical() const
        case GridTypeBar:
                return true;
        case GridTypeNone:
-       case GridTypeSmpte:
+       case GridTypeTimecode:
        case GridTypeMinSec:
-       case GridTypeSamples:
+       case GridTypeCDFrame:
                return false;
        }
        return false;
@@ -2157,9 +2168,9 @@ bool
 Editor::grid_nonmusical() const
 {
        switch (_grid_type) {
-       case GridTypeSmpte:
+       case GridTypeTimecode:
        case GridTypeMinSec:
-       case GridTypeSamples:
+       case GridTypeCDFrame:
                return true;
        case GridTypeBeatDiv32:
        case GridTypeBeatDiv28:
@@ -2189,16 +2200,64 @@ Editor::snap_mode() const
        return _snap_mode;
 }
 
+void
+Editor::show_rulers_for_grid ()
+{
+       /* show appropriate rulers for this grid setting. */
+       if (grid_musical()) {
+               ruler_tempo_action->set_active(true);
+               ruler_meter_action->set_active(true);
+               ruler_bbt_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_timecode_action->set_active(false);
+                       ruler_minsec_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       } else if (_grid_type == GridTypeTimecode) {
+               ruler_timecode_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_tempo_action->set_active(false);
+                       ruler_meter_action->set_active(false);
+                       ruler_bbt_action->set_active(false);
+                       ruler_minsec_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       } else if (_grid_type == GridTypeMinSec) {
+               ruler_minsec_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_tempo_action->set_active(false);
+                       ruler_meter_action->set_active(false);
+                       ruler_bbt_action->set_active(false);
+                       ruler_timecode_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       } else if (_grid_type == GridTypeCDFrame) {
+               ruler_cd_marker_action->set_active(true);
+               ruler_minsec_action->set_active(true);
+
+               if (UIConfiguration::instance().get_rulers_follow_grid()) {
+                       ruler_tempo_action->set_active(false);
+                       ruler_meter_action->set_active(false);
+                       ruler_bbt_action->set_active(false);
+                       ruler_timecode_action->set_active(false);
+                       ruler_samples_action->set_active(false);
+               }
+       }
+}
+
 void
 Editor::set_grid_to (GridType gt)
 {
-       if (_grid_type == gt) {  //already set
+       if (_grid_type == gt) { // already set
                return;
        }
 
        unsigned int grid_ind = (unsigned int)gt;
 
-       if (internal_editing()) {
+       if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
                internal_grid_type = gt;
        } else {
                pre_internal_grid_type = gt;
@@ -2217,45 +2276,13 @@ Editor::set_grid_to (GridType gt)
                grid_type_selector.set_text (str);
        }
 
-       //show appropriate rulers for this grid setting.  (ToDo:  perhaps make this optional)
-       //Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines 
-       if ( grid_musical() ) {
-               ruler_tempo_action->set_active(true);
-               ruler_meter_action->set_active(true);
-
-               ruler_bbt_action->set_active(true);
-               ruler_timecode_action->set_active(false);
-               ruler_minsec_action->set_active(false);
-               ruler_samples_action->set_active(false);
-       } else if (_grid_type == GridTypeSmpte ) {
-               ruler_tempo_action->set_active(false);
-               ruler_meter_action->set_active(false);
-
-               ruler_bbt_action->set_active(false);
-               ruler_timecode_action->set_active(true);
-               ruler_minsec_action->set_active(false);
-               ruler_samples_action->set_active(false);
-       } else if (_grid_type == GridTypeMinSec ) {
-               ruler_tempo_action->set_active(false);
-               ruler_meter_action->set_active(false);
-
-               ruler_bbt_action->set_active(false);
-               ruler_timecode_action->set_active(false);
-               ruler_minsec_action->set_active(true);
-               ruler_samples_action->set_active(false);
-       } else if (_grid_type == GridTypeSamples ) {
-               ruler_tempo_action->set_active(false);
-               ruler_meter_action->set_active(false);
-
-               ruler_bbt_action->set_active(false);
-               ruler_timecode_action->set_active(false);
-               ruler_minsec_action->set_active(false);
-               ruler_samples_action->set_active(true);
+       if (UIConfiguration::instance().get_show_grids_ruler()) {
+               show_rulers_for_grid ();
        }
 
        instant_save ();
 
-       if ( grid_musical() ) {
+       if (grid_musical()) {
                compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
                update_tempo_based_rulers ();
        }
@@ -2277,8 +2304,8 @@ Editor::set_snap_mode (SnapMode mode)
        }
 
        _snap_mode = mode;
-       
-       if (_snap_mode == SnapOff ) {
+
+       if (_snap_mode == SnapOff) {
                snap_mode_button.set_active_state (Gtkmm2ext::Off);
        } else {
                snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
@@ -2544,7 +2571,7 @@ Editor::set_state (const XMLNode& node, int version)
                }
        }
 
-       return LuaInstance::instance()->set_state(node);
+       return 0;
 }
 
 XMLNode&
@@ -2612,8 +2639,6 @@ Editor::get_state ()
 
        node->set_property ("nudge-clock-value", nudge_clock->current_duration());
 
-       node->add_child_nocopy (LuaInstance::instance()->get_action_state());
-       node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
        node->add_child_nocopy (_locations->get_state ());
 
        return *node;
@@ -2635,7 +2660,7 @@ Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
        }
 
        if (y < 0) {
-               return std::make_pair ( (TimeAxisView *) 0, 0);
+               return std::make_pair ((TimeAxisView *) 0, 0);
        }
 
        for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
@@ -2647,13 +2672,13 @@ Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
                }
        }
 
-       return std::make_pair ( (TimeAxisView *) 0, 0);
+       return std::make_pair ((TimeAxisView *) 0, 0);
 }
 
 void
 Editor::set_snapped_cursor_position (samplepos_t pos)
 {
-       if ( _edit_point == EditAtMouse ) {
+       if (_edit_point == EditAtMouse) {
                snapped_cursor->set_position(pos);
        }
 }
@@ -2665,7 +2690,7 @@ Editor::set_snapped_cursor_position (samplepos_t pos)
  *  @param event Event to get current key modifier information from, or 0.
  */
 void
-Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
+Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
 {
        if (!_session || !event) {
                return;
@@ -2673,16 +2698,16 @@ Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, Round
 
        if (ArdourKeyboard::indicates_snap (event->button.state)) {
                if (_snap_mode == SnapOff) {
-                       snap_to_internal (start, direction, pref, for_mark);
+                       snap_to_internal (start, direction, pref);
                } else {
                        start.set (start.sample, 0);
                }
        } else {
                if (_snap_mode != SnapOff) {
-                       snap_to_internal (start, direction, pref, for_mark);
+                       snap_to_internal (start, direction, pref);
                } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
                        /* SnapOff, but we pressed the snap_delta modifier */
-                       snap_to_internal (start, direction, pref, for_mark);
+                       snap_to_internal (start, direction, pref);
                } else {
                        start.set (start.sample, 0);
                }
@@ -2690,83 +2715,261 @@ Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, Round
 }
 
 void
-Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
+Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
 {
        if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
                start.set (start.sample, 0);
                return;
        }
 
-       snap_to_internal (start, direction, pref, for_mark, ensure_snap);
+       snap_to_internal (start, direction, pref, ensure_snap);
 }
 
 void
-check_best_snap ( samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best  )
+check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
 {
-       samplepos_t diff = abs( test - presnap );
-       if ( diff < dist ) {
+       samplepos_t diff = abs (test - presnap);
+       if (diff < dist) {
                dist = diff;
                best = test;
        }
 
-       test = max_samplepos; //reset this so it doesn't get accidentally reused
+       test = max_samplepos; // reset this so it doesn't get accidentally reused
 }
 
-samplepos_t
-Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
+MusicSample
+Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
 {
-       if  (marks.empty() ) return presnap;
+       samplepos_t start = presnap.sample;
+       const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
+       samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
 
-       samplepos_t before;
-       samplepos_t after;
-       samplepos_t test = presnap;
+       TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
+
+       switch (scale) {
+       case timecode_show_bits:
+       case timecode_show_samples:
+               if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                   fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
+                       /* start is already on a whole timecode frame, do nothing */
+               } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
+                       start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
+               } else {
+                       start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) *  _session->samples_per_timecode_frame());
+               }
+               break;
+
+       case timecode_show_seconds:
+               if (_session->config.get_timecode_offset_negative()) {
+                       start += _session->config.get_timecode_offset ();
+               } else {
+                       start -= _session->config.get_timecode_offset ();
+               }
+               if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                   (start % one_timecode_second == 0)) {
+                       /* start is already on a whole second, do nothing */
+               } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
+                       start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
+               } else {
+                       start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
+               }
 
-       before = after = max_samplepos;
+               if (_session->config.get_timecode_offset_negative()) {
+                       start -= _session->config.get_timecode_offset ();
+               } else {
+                       start += _session->config.get_timecode_offset ();
+               }
+               break;
 
-       //get marks to either side of presnap
-       vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
-       while ( m != marks.end() && (m->position < presnap) ) {
-               ++m;
+       case timecode_show_minutes:
+       case timecode_show_hours:
+       case timecode_show_many_hours:
+               if (_session->config.get_timecode_offset_negative()) {
+                       start += _session->config.get_timecode_offset ();
+               } else {
+                       start -= _session->config.get_timecode_offset ();
+               }
+               if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                   (start % one_timecode_minute == 0)) {
+                       /* start is already on a whole minute, do nothing */
+               } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
+                       start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
+               } else {
+                       start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
+               }
+               if (_session->config.get_timecode_offset_negative()) {
+                       start -= _session->config.get_timecode_offset ();
+               } else {
+                       start += _session->config.get_timecode_offset ();
+               }
+               break;
+       default:
+               fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
        }
 
-       if (m == marks.end ()) {
-               /* ran out of marks */
-               before = marks.back().position;
+       MusicSample ret(start,0);
+       return ret;
+}
+
+MusicSample
+Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       MusicSample ret(presnap);
+       
+       const samplepos_t one_second = _session->sample_rate();
+       const samplepos_t one_minute = one_second * 60;
+       const samplepos_t one_hour = one_minute * 60;
+
+       MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
+
+       switch (scale) {
+               case minsec_show_msecs:
+               case minsec_show_seconds: {
+                       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                               presnap.sample % one_second == 0) {
+                               /* start is already on a whole second, do nothing */
+                       } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
+                               ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
+                       } else {
+                               ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
+                       }
+               } break;
+
+               case minsec_show_minutes: {
+                       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                               presnap.sample % one_minute == 0) {
+                               /* start is already on a whole minute, do nothing */
+                       } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
+                               ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
+                       } else {
+                               ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
+                       }
+               } break;
+
+               default: {
+                       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+                               presnap.sample % one_hour == 0) {
+                               /* start is already on a whole hour, do nothing */
+                       } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
+                               ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
+                       } else {
+                               ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
+                       }
+               } break;
        }
+       
+       return ret;
+}
 
-       after = m->position;
+MusicSample
+Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
+               return snap_to_minsec (presnap, direction, gpref);
+       }       
+       
+       const samplepos_t one_second = _session->sample_rate();
 
-       if (m != marks.begin ()) {
-               --m;
-               before = m->position;
+       MusicSample ret(presnap);
+       
+       if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
+               presnap.sample % (one_second/75) == 0) {
+               /* start is already on a whole CD sample, do nothing */
+       } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
+               ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
+       } else {
+               ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
        }
 
-       if (before == max_samplepos && after == max_samplepos) {
-               /* No grid to snap to, so just don't snap */
-               return presnap;
-       } else if (before == max_samplepos) {
-               test = after;
-       } else if (after == max_samplepos) {
-               test = before;
-       } else  {
-               if ((direction == RoundUpMaybe || direction == RoundUpAlways))
-                       test = after;
-               else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
-                       test = before;
-               else if (direction ==  0 ) {
-                       if ((presnap - before) < (after - presnap)) {
-                               test = before;
-                       } else {
-                               test = after;
-                       }
+       return ret;
+}
+
+MusicSample
+Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       MusicSample ret(presnap);
+       
+       if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
+
+               int divisor = 2;
+               switch (_grid_type) {
+               case GridTypeBeatDiv3:
+               case GridTypeBeatDiv6:
+               case GridTypeBeatDiv12:
+               case GridTypeBeatDiv24:
+                       divisor = 3;
+                       break;
+               case GridTypeBeatDiv5:
+               case GridTypeBeatDiv10:
+               case GridTypeBeatDiv20:
+                       divisor = 5;
+                       break;
+               case GridTypeBeatDiv7:
+               case GridTypeBeatDiv14:
+               case GridTypeBeatDiv28:
+                       divisor = 7;
+                       break;
+               default:
+                       divisor = 2;
+               };
+
+               BBTRulerScale scale = bbt_ruler_scale;
+               switch (scale) {
+                       case bbt_show_many:
+                       case bbt_show_64:
+                       case bbt_show_16:
+                       case bbt_show_4:
+                       case bbt_show_1:
+                               ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
+                               break;
+                       case bbt_show_quarters:
+                               ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
+                               break;
+                       case bbt_show_eighths:
+                               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
+                               break;
+                       case bbt_show_sixteenths:
+                               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
+                               break;
+                       case bbt_show_thirtyseconds:
+                               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
+                               break;
                }
+       } else {
+               ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
        }
+       
+       return ret;
+}
 
-       return test;
+ARDOUR::MusicSample
+Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
+{
+       MusicSample ret(presnap);
+       
+       if (grid_musical()) {
+               ret = snap_to_bbt (presnap, direction, gpref);
+       }
+       
+       switch (_grid_type) {
+               case GridTypeTimecode:
+                       ret = snap_to_timecode(presnap, direction, gpref);
+                       break;
+               case GridTypeMinSec:
+                       ret = snap_to_minsec(presnap, direction, gpref);
+                       break;
+               case GridTypeCDFrame:
+                       ret = snap_to_cd_frames(presnap, direction, gpref);
+                       break;
+               default:
+                       {}
+       };
+
+       return ret;
 }
 
 samplepos_t
-Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
+Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
 {
        samplepos_t before;
        samplepos_t after;
@@ -2786,7 +2989,7 @@ Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
                        test = after;
                } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
                        test = before;
-               } else if (direction ==  0 ) {
+               } else if (direction ==  0) {
                        if ((presnap - before) < (after - presnap)) {
                                test = before;
                        } else {
@@ -2799,69 +3002,62 @@ Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
 }
 
 void
-Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
+Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
 {
        const samplepos_t presnap = start.sample;
 
-       samplepos_t test = max_samplepos;  //for each snap, we'll use this value
-       samplepos_t dist = max_samplepos;  //this records the distance of the best snap result we've found so far
-       samplepos_t best = max_samplepos;  //this records the best snap-result we've found so far
-
-       //check snap-to-marker
-       if ( UIConfiguration::instance().get_snap_to_marks() ) {
-               if (for_mark) {
-                       return;
-               }
+       samplepos_t test = max_samplepos; // for each snap, we'll use this value
+       samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
+       samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
 
-               test = marker_snap_to_internal ( presnap, direction );
+       /* check snap-to-marker */
+       if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
+               test = snap_to_marker (presnap, direction);
                check_best_snap(presnap, test, dist, best);
        }
 
-       //check snap-to-region-{start/end/sync}
-       if ( UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync() ) {
+       /* check snap-to-region-{start/end/sync} */
+       if (
+               (pref == SnapToAny_Visual) &&
+               (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
+               ) {
                if (!region_boundary_cache.empty()) {
 
-                       vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
-                       vector<samplepos_t>::iterator next = region_boundary_cache.end ();
-
-                       if (direction > 0) {
-                               next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
-                       } else {
-                               next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
-                       }
-
+                       vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
+                       vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
                        if (next != region_boundary_cache.begin ()) {
                                prev = next;
                                prev--;
                        }
 
-                       samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
-                       samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
-
-                       if (presnap > (p + n) / 2) {
-                               test = n;
-                       } else {
-                               test = p;
+                       if ((direction == RoundUpMaybe || direction == RoundUpAlways))
+                               test = *next;
+                       else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
+                               test = *prev;
+                       else if (direction ==  0) {
+                               if ((presnap - *prev) < (*next - presnap)) {
+                                       test = *prev;
+                               } else {
+                                       test = *next;
+                               }
                        }
+
                }
 
                check_best_snap(presnap, test, dist, best);
        }
 
-       //check Grid
-       if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone) ) {
-
-               //if SnapToGrid is selected, the user wants to prioritize the music grid
-               //in this case we should reset the best distance, so Grid will prevail
-               dist = max_samplepos;
-
-               test = snap_to_grid (grid_marks, presnap, direction);
-               check_best_snap(presnap, test, dist, best);
+       /* check Grid */
+       if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
+               MusicSample pre(presnap, 0);
+               MusicSample post = snap_to_grid (pre, direction, pref);
+               check_best_snap(presnap, post.sample, dist, best);
        }
 
-       //now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
-       //this also helps to avoid snapping to somewhere the user can't see.  ( i.e.:  I clicked on a region and it disappeared!! )
-       //ToDo:  perhaps this should only occur if EditPointMouse?
+       /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
+        * this also helps to avoid snapping to somewhere the user can't see.  (i.e.: I clicked on a region and it disappeared!!)
+        * ToDo: Perhaps this should only occur if EditPointMouse?
+        */
        int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
        if (ensure_snap) {
                start.set (best, 0);
@@ -3064,6 +3260,22 @@ Editor::setup_toolbar ()
        toolbar_hbox.set_spacing (2);
        toolbar_hbox.set_border_width (2);
 
+       ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
+       tool_shadow->set_size_request (4, -1);
+       tool_shadow->show();
+
+       ebox_hpacker.pack_start (*tool_shadow, false, false);
+       ebox_hpacker.pack_start(ebox_vpacker, true, true);
+
+       Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
+       spacer->set_name("EditorWindow");
+       spacer->set_size_request(-1,4);
+       spacer->show();
+
+       ebox_vpacker.pack_start(toolbar_hbox, false, false);
+       ebox_vpacker.pack_start(*spacer, false, false);
+       ebox_vpacker.show();
+
        toolbar_hbox.pack_start (*mode_box, false, false);
 
        if (!ARDOUR::Profile->get_trx()) {
@@ -3076,8 +3288,6 @@ Editor::setup_toolbar ()
 
                toolbar_hbox.pack_start (*nudge_box, false, false);
 
-               //zoom tools on right ege
-
                toolbar_hbox.pack_end (_zoom_box, false, false, 2);
 
                toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
@@ -3094,10 +3304,10 @@ Editor::build_edit_point_menu ()
 {
        using namespace Menu_Helpers;
 
-       edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
+       edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
        if(!Profile->get_mixbus())
-               edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
-       edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
+               edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
+       edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
 
        set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
 }
@@ -3107,10 +3317,10 @@ Editor::build_edit_mode_menu ()
 {
        using namespace Menu_Helpers;
 
-       edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
-//     edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
-       edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
-       edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
+       edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
+       edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
+       edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode)  Lock)));
+       /* Note: Splice was removed */
 
        set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
 }
@@ -3120,54 +3330,52 @@ Editor::build_grid_type_menu ()
 {
        using namespace Menu_Helpers;
 
-       //main grid: bars, quarter-notes, etc
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeNone],      sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBar],       sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeat],      sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv2],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv4],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv8],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
-
-       //triplet grid
+       /* main grid: bars, quarter-notes, etc */
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone],      sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar],       sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat],      sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
+
+       /* triplet grid */
        grid_type_selector.AddMenuElem(SeparatorElem());
        Gtk::Menu *_triplet_menu = manage (new Menu);
        MenuList& triplet_items (_triplet_menu->items());
        {
-               triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv3],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3) ));
-               triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv6],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6) ));
-               triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12) ));
-               triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24) ));
+               triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
+               triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
+               triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
+               triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
        }
        grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
 
-       //quintuplet grid
+       /* quintuplet grid */
        Gtk::Menu *_quintuplet_menu = manage (new Menu);
        MenuList& quintuplet_items (_quintuplet_menu->items());
        {
-               quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv5],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5) ));
-               quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10) ));
-               quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20) ));
+               quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
+               quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
+               quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
        }
        grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
 
-       //septuplet grid
+       /* septuplet grid */
        Gtk::Menu *_septuplet_menu = manage (new Menu);
        MenuList& septuplet_items (_septuplet_menu->items());
        {
-               septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv7],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7) ));
-               septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14) ));
-               septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28) ));
+               septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7],  sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
+               septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
+               septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
        }
        grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
 
        grid_type_selector.AddMenuElem(SeparatorElem());
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSmpte], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSmpte)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
-       grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSamples], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSamples)));
-
-       set_size_request_to_display_given_text (grid_type_selector, _("Long Grid"), COMBO_TRIANGLE_WIDTH, 2);  //problem: some of the rarely-used grid names are very long.  Just do something arbitary, translators: rename this if needed
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
+       grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
 }
 
 void
@@ -3345,16 +3553,15 @@ Editor::commit_reversible_selection_op ()
                if (selection_op_cmd_depth == 1) {
 
                        if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
-                               /**
-                                   The user has undone some selection ops and then made a new one,
-                                   making anything earlier in the list invalid.
-                               */
+                               /* The user has undone some selection ops and then made a new one,
+                                * making anything earlier in the list invalid.
+                                */
 
                                list<XMLNode *>::iterator it = selection_op_history.begin();
                                list<XMLNode *>::iterator e_it = it;
                                advance (e_it, selection_op_history_it);
 
-                               for ( ; it != e_it; ++it) {
+                               for (; it != e_it; ++it) {
                                        delete *it;
                                }
                                selection_op_history.erase (selection_op_history.begin(), e_it);
@@ -3499,7 +3706,7 @@ Editor::duplicate_range (bool with_dialog)
 
        RegionSelection rs = get_regions_from_selection_and_entered ();
 
-       if ( selection->time.length() == 0 && rs.empty()) {
+       if (selection->time.length() == 0 && rs.empty()) {
                return;
        }
 
@@ -3582,9 +3789,9 @@ Editor::cycle_edit_mode ()
 }
 
 void
-Editor::edit_mode_selection_done ( EditMode m )
+Editor::edit_mode_selection_done (EditMode m)
 {
-       Config->set_edit_mode ( m );
+       Config->set_edit_mode (m);
 }
 
 void
@@ -3632,7 +3839,7 @@ Editor::cycle_edit_point (bool with_marker)
 void
 Editor::edit_point_selection_done (EditPoint ep)
 {
-       set_edit_point_preference ( ep );
+       set_edit_point_preference (ep);
 }
 
 void
@@ -3640,18 +3847,18 @@ Editor::build_zoom_focus_menu ()
 {
        using namespace Menu_Helpers;
 
-       zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
-       zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
-       zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
-       zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
-       zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
-       zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
+       zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
+       zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
+       zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
+       zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
+       zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
+       zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
 
        set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
 }
 
 void
-Editor::zoom_focus_selection_done ( ZoomFocus f )
+Editor::zoom_focus_selection_done (ZoomFocus f)
 {
        RefPtr<RadioAction> ract = zoom_focus_action (f);
        if (ract) {
@@ -3708,13 +3915,13 @@ Editor::build_track_count_menu ()
 void
 Editor::set_zoom_preset (int64_t ms)
 {
-       if ( ms <= 0 ) {
+       if (ms <= 0) {
                temporal_zoom_session();
                return;
        }
 
        ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
-       temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
+       temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
 }
 
 void
@@ -3781,7 +3988,7 @@ void
 Editor::override_visible_track_count ()
 {
        _visible_track_count = -1;
-       visible_tracks_selector.set_text ( _("*") );
+       visible_tracks_selector.set_text (_("*"));
 }
 
 bool
@@ -3851,13 +4058,13 @@ Editor::cycle_zoom_focus ()
 void
 Editor::update_grid ()
 {
-       if ( grid_musical() ) {
+       if (grid_musical()) {
                std::vector<TempoMap::BBTPoint> grid;
                if (bbt_ruler_scale != bbt_show_many) {
                        compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
                }
                maybe_draw_grid_lines ();
-       } else if ( grid_nonmusical() ) {
+       } else if (grid_nonmusical()) {
                maybe_draw_grid_lines ();
        } else {
                hide_grid_lines ();
@@ -3904,8 +4111,7 @@ Editor::set_stationary_playhead (bool yn)
 {
        if (_stationary_playhead != yn) {
                if ((_stationary_playhead = yn) == true) {
-                       /* catch up */
-                       // FIXME need a 3.0 equivalent of this 2.X call
+                       /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
                        // update_current_screen ();
                }
                instant_save ();
@@ -3956,11 +4162,13 @@ Editor::get_grid_beat_divisions(samplepos_t position)
        case GridTypeBeatDiv4:   return 4;
        case GridTypeBeatDiv3:   return 3;
        case GridTypeBeatDiv2:   return 2;
+       case GridTypeBeat:       return 1;
+       case GridTypeBar:        return 1;
 
        case GridTypeNone:       return 0;
-       case GridTypeSmpte:      return 0;
+       case GridTypeTimecode:   return 0;
        case GridTypeMinSec:     return 0;
-       case GridTypeSamples:    return 0;
+       case GridTypeCDFrame:    return 0;
        default:                 return 0;
        }
        return 0;
@@ -4002,9 +4210,9 @@ Editor::get_grid_music_divisions (uint32_t event_state)
        case GridTypeBar :       return -1;
 
        case GridTypeNone:       return 0;
-       case GridTypeSmpte:      return 0;
+       case GridTypeTimecode:   return 0;
        case GridTypeMinSec:     return 0;
-       case GridTypeSamples:    return 0;
+       case GridTypeCDFrame:    return 0;
        }
        return 0;
 }
@@ -4067,7 +4275,7 @@ Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
        dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
        dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
 
-       // by default gtk uses the left most button
+       /* by default gtk uses the left most button */
        keep->grab_focus ();
 
        switch (dialog.run ()) {
@@ -4365,8 +4573,7 @@ Editor::redo_visual_state ()
        VisualState* vs = redo_visual_stack.back();
        redo_visual_stack.pop_back();
 
-       // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
-       // why do we check here?
+       /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
        undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
 
        if (vs) {
@@ -4481,7 +4688,7 @@ void
 Editor::ensure_visual_change_idle_handler ()
 {
        if (pending_visual_change.idle_handler_id < 0) {
-               // see comment in add_to_idle_resize above.
+               /* see comment in add_to_idle_resize above. */
                pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
                pending_visual_change.being_handled = false;
        }
@@ -4576,16 +4783,14 @@ Editor::visual_changer (const VisualChange& vc)
        }
 
        if (!(vc.pending & VisualChange::ZoomLevel)) {
-               /**
-                * If the canvas is not being zoomed then the canvas items will not change
+               /* If the canvas is not being zoomed then the canvas items will not change
                 * and cause Item::prepare_for_render to be called so do it here manually.
-                *
                 * Not ideal, but I can't think of a better solution atm.
                 */
                _track_canvas->prepare_for_render();
        }
 
-       // If we are only scrolling vertically there is no need to update these
+       /* If we are only scrolling vertically there is no need to update these */
        if (vc.pending != VisualChange::YOrigin) {
                update_fixed_rulers ();
                redisplay_grid (true);
@@ -4636,11 +4841,11 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
                return entered_marker->position();
        }
 
-       if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
+       if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
                ep = EditAtSelectedMarker;
        }
 
-       if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
+       if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
                ep = EditAtPlayhead;
        }
 
@@ -4648,8 +4853,9 @@ Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_
 
        switch (ep) {
        case EditAtPlayhead:
-               if (_dragging_playhead && _control_scroll_target) {
-                       where = *_control_scroll_target;
+               if (_dragging_playhead) {
+                       /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
+                       where = playhead_cursor->current_sample();
                } else {
                        where = _session->audible_sample();
                }
@@ -4832,13 +5038,13 @@ Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool
 {
        RegionSelection regions;
 
-       if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
+       if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
                regions.add (entered_regionview);
        } else {
                regions = selection->regions;
        }
 
-       if ( regions.empty() ) {
+       if (regions.empty()) {
                TrackViewList tracks = selection->tracks;
 
                if (!tracks.empty()) {
@@ -4869,13 +5075,13 @@ Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
 {
        RegionSelection regions;
 
-       if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
+       if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
                regions.add (entered_regionview);
        } else {
                regions = selection->regions;
        }
 
-       if ( regions.empty() ) {
+       if (regions.empty()) {
                TrackViewList tracks = selection->tracks;
 
                if (!tracks.empty()) {
@@ -5061,7 +5267,7 @@ Editor::first_idle ()
 
        selection->set (rs);
 
-       // first idle adds route children (automation tracks), so we need to redisplay here
+       /* first idle adds route children (automation tracks), so we need to redisplay here */
        _routes->redisplay ();
 
        delete dialog;
@@ -5432,7 +5638,7 @@ Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
        PresentationInfo::ChangeSuspender cs;
 
        if (apply_to_selection) {
-               for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
+               for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
 
                        TrackSelection::iterator j = i;
                        ++j;
@@ -5445,7 +5651,7 @@ Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
 
                if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
-                       // this will hide the mixer strip
+                       /* this will hide the mixer strip */
                        set_selected_mixer_strip (*tv);
                }
 
@@ -5727,6 +5933,11 @@ Editor::super_rapid_screen_update ()
                _last_update_time = 0;
        }
 
+       if (!_session->transport_rolling () || _session->is_auditioning ()) {
+               /* Do not interpolate the playhead position; just set it */
+               _last_update_time = 0;
+       }
+
        if (_last_update_time > 0) {
                /* interpolate and smoothen playhead position */
                const double ds =  (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
@@ -5755,27 +5966,26 @@ Editor::super_rapid_screen_update ()
                _last_update_time = now;
        }
 
-       //snapped cursor stuff ( the snapped_cursor shows where an operation is going to occur )
+       /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
        bool ignored;
        MusicSample where (sample, 0);
-       if ( !UIConfiguration::instance().get_show_snapped_cursor() ) {
+       if (!UIConfiguration::instance().get_show_snapped_cursor()) {
                snapped_cursor->hide ();
-       } else if ( _edit_point == EditAtPlayhead && !_dragging_playhead) {
-               snap_to (where);  // can't use snap_to_with_modifier?
-               snapped_cursor->set_position (where.sample);
-               snapped_cursor->show ();
-       } else if ( _edit_point == EditAtSelectedMarker ) {
-               //NOTE:  I don't think EditAtSelectedMarker should snap.  they are what they are.
-               //however, the current editing code -does- snap so I'll draw it that way for now.
-               if ( !selection->markers.empty() ) {
+       } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
+               /* EditAtPlayhead does not snap */
+       } else if (_edit_point == EditAtSelectedMarker) {
+               /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
+                * however, the current editing code -does- snap so I'll draw it that way for now.
+                */
+               if (!selection->markers.empty()) {
                        MusicSample ms (selection->markers.front()->position(), 0);
-                       snap_to (ms);  // should use snap_to_with_modifier?
-                       snapped_cursor->set_position ( ms.sample );
+                       snap_to (ms); // should use snap_to_with_modifier?
+                       snapped_cursor->set_position (ms.sample);
                        snapped_cursor->show ();
                }
-       } else if (mouse_sample (where.sample, ignored)) {   //cursor is in the editing canvas. show it.
+       } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
                snapped_cursor->show ();
-       } else { //mouse is out of the editing canvas.  hide the snapped_cursor
+       } else { // mouse is out of the editing canvas. hide the snapped_cursor
                snapped_cursor->hide ();
        }
 
@@ -5828,7 +6038,7 @@ Editor::super_rapid_screen_update ()
                if (target <= 0.0) {
                        target = 0.0;
                }
-               // compare to EditorCursor::set_position()
+               /* compare to EditorCursor::set_position() */
                double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
                double const new_pos = sample_to_pixel_unrounded (target);
                if (rint (new_pos) != rint (old_pos)) {
@@ -6134,6 +6344,11 @@ Editor::ui_parameter_changed (string parameter)
                if (_verbose_cursor) {
                        playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
                }
+       } else if (parameter == "use-note-bars-for-velocity") {
+               ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
+               _track_canvas->request_redraw (_track_canvas->visible_area());
+       } else if (parameter == "use-note-color-for-velocity") {
+               /* handled individually by each MidiRegionView */
        }
 }