Another go at fixing up MIDI note additions with snap

(#4189).


git-svn-id: svn://localhost/ardour2/branches/3.0@10017 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2011-08-20 20:02:04 +00:00
parent c8e6db4e92
commit ad444c0955
2 changed files with 73 additions and 39 deletions

View File

@ -472,7 +472,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
beats = 1;
}
create_note_at (event_x, event_y, beats, true);
create_note_at (event_x, event_y, beats, true, true);
}
break;
@ -486,7 +486,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
beats = 1;
}
create_note_at (event_x, event_y, beats, true);
create_note_at (event_x, event_y, beats, true, true);
break;
}
@ -515,7 +515,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
const double x = _drag_rect->property_x1();
const double length = trackview.editor().pixel_to_frame (_drag_rect->property_x2() - _drag_rect->property_x1());
create_note_at (x, _drag_rect->property_y1(), region_frames_to_region_beats(length), true);
create_note_at (x, _drag_rect->property_y1(), region_frames_to_region_beats(length), true, false);
}
}
@ -541,25 +541,28 @@ MidiRegionView::motion (GdkEventMotion* ev)
event_y = ev->y;
group->w2i(event_x, event_y);
PublicEditor& editor = trackview.editor ();
// convert event_x to global frame
event_frame = snap_pixel_to_frame (event_x);
framecnt_t grid_frames;
event_frame = snap_frame_to_grid_underneath (editor.pixel_to_frame (event_x), grid_frames);
if (!_ghost_note && trackview.editor().current_mouse_mode() != MouseRange
if (!_ghost_note && editor.current_mouse_mode() != MouseRange
&& Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())
&& _mouse_state != AddDragging) {
create_ghost_note (ev->x, ev->y);
} else if (_ghost_note && trackview.editor().current_mouse_mode() != MouseRange
} else if (_ghost_note && editor.current_mouse_mode() != MouseRange
&& Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
update_ghost_note (ev->x, ev->y);
} else if (_ghost_note && trackview.editor().current_mouse_mode() != MouseRange) {
} else if (_ghost_note && editor.current_mouse_mode() != MouseRange) {
delete _ghost_note;
_ghost_note = 0;
trackview.editor().verbose_cursor()->hide ();
} else if (_ghost_note && trackview.editor().current_mouse_mode() == MouseRange) {
editor.verbose_cursor()->hide ();
} else if (_ghost_note && editor.current_mouse_mode() == MouseRange) {
update_ghost_note (ev->x, ev->y);
}
@ -577,7 +580,7 @@ MidiRegionView::motion (GdkEventMotion* ev)
return false;
}
if (_pressed_button == 1 && trackview.editor().current_mouse_mode() == MouseObject
if (_pressed_button == 1 && editor.current_mouse_mode() == MouseObject
&& !Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
// Select drag start
@ -603,7 +606,7 @@ MidiRegionView::motion (GdkEventMotion* ev)
_mouse_state = SelectRectDragging;
return true;
} else if (trackview.editor().internal_editing()) {
} else if (editor.internal_editing()) {
// Add note drag start
group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
@ -615,11 +618,12 @@ MidiRegionView::motion (GdkEventMotion* ev)
_drag_start_y = event_y;
_drag_rect = new ArdourCanvas::SimpleRect(*group);
_drag_rect->property_x1() = trackview.editor().frame_to_pixel(event_frame);
_drag_rect->property_x1() = editor.frame_to_pixel(event_frame);
_drag_rect->property_y1() = midi_stream_view()->note_to_y(
midi_stream_view()->y_to_note(event_y));
_drag_rect->property_x2() = trackview.editor().frame_to_pixel(event_frame);
_drag_rect->property_x2() = editor.frame_to_pixel(event_frame);
_drag_rect->property_y2() = _drag_rect->property_y1()
+ floor(midi_stream_view()->note_height());
_drag_rect->property_outline_what() = 0xFF;
@ -631,7 +635,7 @@ MidiRegionView::motion (GdkEventMotion* ev)
delete _ghost_note;
_ghost_note = 0;
trackview.editor().verbose_cursor()->hide ();
editor.verbose_cursor()->hide ();
return true;
}
@ -651,7 +655,17 @@ MidiRegionView::motion (GdkEventMotion* ev)
}
if (_mouse_state == AddDragging) {
event_x = trackview.editor().frame_to_pixel(event_frame);
event_x = editor.frame_to_pixel(event_frame);
if (editor.snap_mode() == SnapNormal) {
/* event_frame will have been snapped to the start of the note we are under;
it's more intuitive if we use the end of that note here
*/
event_x = editor.frame_to_pixel (event_frame + grid_frames);
} else {
event_x = editor.frame_to_pixel (event_frame);
}
}
if (_drag_rect) {
@ -872,9 +886,10 @@ MidiRegionView::show_list_editor ()
* \param y vertical position in pixels
* \param length duration of the note in beats, which will be snapped to the grid
* \param sh true to make the note 1 frame shorter than the snapped version of \a length.
* \param snap_x true to snap x to the grid, otherwise false.
*/
void
MidiRegionView::create_note_at(double x, double y, double length, bool sh)
MidiRegionView::create_note_at (double x, double y, double length, bool sh, bool snap_x)
{
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
MidiStreamView* const view = mtv->midi_view();
@ -885,7 +900,11 @@ MidiRegionView::create_note_at(double x, double y, double length, bool sh)
assert(note <= 127.0);
// Start of note in frames relative to region start
framepos_t const start_frames = snap_pixel_to_frame (x);
framepos_t start_frames = trackview.editor().pixel_to_frame (x);
if (snap_x) {
framecnt_t grid_frames;
start_frames = snap_frame_to_grid_underneath (start_frames, grid_frames);
}
assert(start_frames >= 0);
// Snap length
@ -2346,7 +2365,7 @@ MidiRegionView::snap_pixel_to_frame(double x)
* @return Snapped frame offset from this region's position.
*/
frameoffset_t
MidiRegionView::snap_frame_to_frame (frameoffset_t x)
MidiRegionView::snap_frame_to_frame (frameoffset_t x) const
{
PublicEditor& editor = trackview.editor();
@ -3327,24 +3346,9 @@ MidiRegionView::update_ghost_note (double x, double y)
PublicEditor& editor = trackview.editor ();
framepos_t unsnapped_frame = editor.pixel_to_frame (x);
bool success;
Evoral::MusicalTime grid_beats = editor.get_grid_type_as_beats (success, unsnapped_frame);
if (!success) {
grid_beats = 1;
}
framecnt_t const grid_frames = region_beats_to_region_frames (grid_beats);
/* Hack so that we always snap to the note that we are over, instead of snapping
to the next one if we're more than halfway through the one we're over.
*/
if (unsnapped_frame >= grid_frames / 2) {
unsnapped_frame -= grid_frames / 2;
}
framepos_t f = snap_frame_to_frame (unsnapped_frame);
framepos_t const unsnapped_frame = editor.pixel_to_frame (x);
framecnt_t grid_frames;
framepos_t const f = snap_frame_to_grid_underneath (unsnapped_frame, grid_frames);
/* use region_frames... because we are converting a delta within the region
*/
@ -3627,3 +3631,31 @@ MidiRegionView::show_verbose_cursor (string const & text, double xoffset, double
trackview.editor().verbose_cursor()->set (text, wx, wy);
trackview.editor().verbose_cursor()->show ();
}
/** @param p A session framepos.
* @param grid_frames Filled in with the number of frames that a grid interval is at p.
* @return p snapped to the grid subdivision underneath it.
*/
framepos_t
MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, framecnt_t& grid_frames) const
{
PublicEditor& editor = trackview.editor ();
bool success;
Evoral::MusicalTime grid_beats = editor.get_grid_type_as_beats (success, p);
if (!success) {
grid_beats = 1;
}
grid_frames = region_beats_to_region_frames (grid_beats);
/* Hack so that we always snap to the note that we are over, instead of snapping
to the next one if we're more than halfway through the one we're over.
*/
if (editor.snap_mode() == SnapNormal && p >= grid_frames / 2) {
p -= grid_frames / 2;
}
return snap_frame_to_frame (p);
}

View File

@ -169,8 +169,6 @@ public:
void end_write();
void extend_active_notes();
void create_note_at(double x, double y, double length, bool);
void display_model(boost::shared_ptr<ARDOUR::MidiModel> model);
void start_note_diff_command (std::string name = "midi edit");
@ -253,7 +251,7 @@ public:
*/
framepos_t snap_pixel_to_frame(double x);
ARDOUR::frameoffset_t snap_frame_to_frame (ARDOUR::frameoffset_t);
ARDOUR::frameoffset_t snap_frame_to_frame (ARDOUR::frameoffset_t) const;
/** Convert a timestamp in beats into frames (both relative to region start) */
framepos_t region_beats_to_region_frames(double beats) const;
@ -317,6 +315,8 @@ private:
friend class EditNoteDialog;
void create_note_at(double x, double y, double length, bool, bool);
/** Play the NoteOn event of the given note immediately
* and schedule the playback of the corresponding NoteOff event.
*/
@ -460,6 +460,8 @@ private:
double _last_event_x;
double _last_event_y;
framepos_t snap_frame_to_grid_underneath (framepos_t p, framecnt_t &) const;
PBD::ScopedConnection _mouse_mode_connection;
Gdk::Cursor* _pre_enter_cursor;