diff options
author | nick_m <mainsbridge@gmail.com> | 2017-02-05 05:02:01 +1100 |
---|---|---|
committer | nick_m <mainsbridge@gmail.com> | 2017-02-05 05:02:01 +1100 |
commit | 5031bdcf10bf7dbc8521598f3a60a0285b9abe1b (patch) | |
tree | 7ac0a6c5bddb47925878abe9c5e3d518af3c61f4 /gtk2_ardour | |
parent | fac04afbba35976dbf13a0e0c298b8af6f42a70f (diff) |
midi note drags are music-based.
- wysiwyg (during drag) when dragging more than one note across
a tempo change.
- introduces a muscal equivalent of snap_delta (only used for
note drags atm)
- split earliest note in selection into a separate function
- MRV::copy_selection() returns the equivalent _primary note
to avoid offset hell.
- RV::snap_frame_to_frame returns a MusicFrame
- prevent note drag moving before region start.
Diffstat (limited to 'gtk2_ardour')
-rw-r--r-- | gtk2_ardour/automation_region_view.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 121 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.h | 8 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 80 | ||||
-rw-r--r-- | gtk2_ardour/midi_region_view.h | 9 | ||||
-rw-r--r-- | gtk2_ardour/region_view.cc | 6 | ||||
-rw-r--r-- | gtk2_ardour/region_view.h | 2 |
7 files changed, 134 insertions, 94 deletions
diff --git a/gtk2_ardour/automation_region_view.cc b/gtk2_ardour/automation_region_view.cc index 8354e16b10..e3e41b4428 100644 --- a/gtk2_ardour/automation_region_view.cc +++ b/gtk2_ardour/automation_region_view.cc @@ -183,7 +183,7 @@ AutomationRegionView::add_automation_event (GdkEvent *, framepos_t when, double /* snap frame */ - when = snap_frame_to_frame (when - _region->start ()) + _region->start (); + when = snap_frame_to_frame (when - _region->start ()).frame + _region->start (); /* map using line */ diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 7624546347..cf24ddbe9e 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -238,6 +238,7 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only) , _grab_frame (0) , _last_pointer_frame (0) , _snap_delta (0) + , _snap_delta_music (0.0) , _constraint_pressed (false) { @@ -355,6 +356,15 @@ Drag::snap_delta (guint state) const return 0; } +double +Drag::snap_delta_music (guint state) const +{ + if (ArdourKeyboard::indicates_snap_delta (state)) { + return _snap_delta_music; + } + + return 0.0; +} double Drag::current_pointer_x() const @@ -373,11 +383,18 @@ Drag::current_pointer_y () const } void -Drag::setup_snap_delta (framepos_t pos) +Drag::setup_snap_delta (MusicFrame pos) { - MusicFrame snap (pos, 0); + TempoMap& map (_editor->session()->tempo_map()); + MusicFrame snap (pos); _editor->snap_to (snap, ARDOUR::RoundNearest, false, true); - _snap_delta = snap.frame - pos; + _snap_delta = snap.frame - pos.frame; + + _snap_delta_music = 0.0; + + if (_snap_delta != 0) { + _snap_delta_music = map.exact_qn_at_frame (snap.frame, snap.division) - map.exact_qn_at_frame (pos.frame, pos.division); + } } bool @@ -618,7 +635,7 @@ void RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Drag::start_grab (event, cursor); - setup_snap_delta (_last_position.frame); + setup_snap_delta (_last_position); show_verbose_cursor_time (_last_position.frame); @@ -2862,7 +2879,7 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*) framecnt_t const region_length = (framecnt_t) (_primary->region()->length() / speed); framepos_t const pf = adjusted_current_frame (event); - setup_snap_delta (region_start); + setup_snap_delta (MusicFrame(region_start, 0)); if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::trim_contents_modifier ())) { /* Move the contents of the region around without changing the region bounds */ @@ -3641,7 +3658,7 @@ void CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) { Drag::start_grab (event, c); - setup_snap_delta (_editor->playhead_cursor->current_frame()); + setup_snap_delta (MusicFrame (_editor->playhead_cursor->current_frame(), 0)); _grab_zoom = _editor->samples_per_pixel; @@ -3744,7 +3761,7 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary); boost::shared_ptr<AudioRegion> const r = arv->audio_region (); - setup_snap_delta (r->position()); + setup_snap_delta (MusicFrame (r->position(), 0)); show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32); } @@ -3870,7 +3887,7 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary); boost::shared_ptr<AudioRegion> r = arv->audio_region (); - setup_snap_delta (r->last_frame()); + setup_snap_delta (MusicFrame (r->last_frame(), 0)); show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame()); } @@ -4031,7 +4048,7 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) } else { show_verbose_cursor_time (location->end()); } - setup_snap_delta (is_start ? location->start() : location->end()); + setup_snap_delta (MusicFrame (is_start ? location->start() : location->end(), 0)); Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); @@ -4418,7 +4435,7 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) _fixed_grab_x = _point->get_x() + _editor->sample_to_pixel_unrounded (_point->line().offset()); _fixed_grab_y = _point->get_y(); - setup_snap_delta (_editor->pixel_to_sample (_fixed_grab_x)); + setup_snap_delta (MusicFrame (_editor->pixel_to_sample (_fixed_grab_x), 0)); float const fraction = 1 - (_point->get_y() / _point->line().height()); show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction)); @@ -4916,10 +4933,10 @@ TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) _editor->get_selection().add (_primary); - framepos_t where = _primary->region()->position(); + MusicFrame where (_primary->region()->position(), 0); setup_snap_delta (where); - show_verbose_cursor_duration (where, adjusted_current_frame (event), 0); + show_verbose_cursor_duration (where.frame, adjusted_current_frame (event), 0); } void @@ -5627,6 +5644,7 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) , _cumulative_dx (0) , _cumulative_dy (0) + , _earliest (0.0) , _was_selected (false) , _copy (false) { @@ -5639,6 +5657,13 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i) } void +NoteDrag::setup_pointer_frame_offset () +{ + _pointer_frame_offset = raw_grab_frame() + - _editor->session()->tempo_map().frame_at_quarter_note (_region->session_relative_qn (_primary->note()->time().to_double())); +} + +void NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *) { Drag::start_grab (event); @@ -5649,7 +5674,7 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *) _copy = false; } - setup_snap_delta (_region->source_beats_to_absolute_frames (_primary->note()->time ())); + setup_snap_delta (MusicFrame (_region->source_beats_to_absolute_frames (_primary->note()->time ()), 0)); if (!(_was_selected = _primary->selected())) { @@ -5673,55 +5698,38 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *) } } -/** @return Current total drag x change in frames */ -frameoffset_t -NoteDrag::total_dx (const guint state) const +/** @return Current total drag x change in quarter notes */ +double +NoteDrag::total_dx (GdkEvent * event) const { if (_x_constrained) { return 0; } + TempoMap& map (_editor->session()->tempo_map()); /* dx in frames */ frameoffset_t const dx = _editor->pixel_to_sample (_drags->current_pointer_x() - grab_x()); /* primary note time */ - double const quarter_note_start = _region->region()->quarter_note() - _region->midi_region()->start_beats(); - frameoffset_t const n = map.frame_at_quarter_note (quarter_note_start + _primary->note()->time().to_double()); - - /* new time of the primary note in session frames */ - frameoffset_t st = n + dx + snap_delta (state); - - framepos_t const rp = _region->region()->position (); + frameoffset_t const n = map.frame_at_quarter_note (_region->session_relative_qn (_primary->note()->time().to_double())); - /* prevent the note being dragged earlier than the region's position */ - st = max (st, rp); + /* primary note time in quarter notes */ + double const n_qn = _region->session_relative_qn (_primary->note()->time().to_double()); - /* possibly snap and return corresponding delta */ + /* new time of the primary note in session frames */ + frameoffset_t st = n + dx + snap_delta (event->button.state); - bool snap = true; + /* possibly snap and return corresponding delta in quarter notes */ + MusicFrame snap (st, 0); + _editor->snap_to_with_modifier (snap, event); + double ret = map.exact_qn_at_frame (snap.frame, snap.division) - n_qn - snap_delta_music (event->button.state); - if (ArdourKeyboard::indicates_snap (state)) { - if (_editor->snap_mode () != SnapOff) { - snap = false; - } - } else { - if (_editor->snap_mode () == SnapOff) { - snap = false; - /* inverted logic here - we;re in snapoff but we've pressed the snap delta modifier */ - if (ArdourKeyboard::indicates_snap_delta (state)) { - snap = true; - } - } + /* prevent the earliest note being dragged earlier than the region's start position */ + if (_earliest + ret < _region->midi_region()->start_beats()) { + ret -= (_earliest + ret) - _region->midi_region()->start_beats(); } - frameoffset_t ret; - if (snap) { - bool const ensure_snap = _editor->snap_mode () != SnapMagnetic; - ret = _region->snap_frame_to_frame (st - rp, ensure_snap) + rp - n - snap_delta (state); - } else { - ret = st - n - snap_delta (state); - } return ret; } @@ -5747,30 +5755,33 @@ NoteDrag::total_dy () const void NoteDrag::motion (GdkEvent * event, bool first_move) { - if (_copy && first_move) { - /* make copies of all the selected notes */ - _primary = _region->copy_selection (); + if (first_move) { + _earliest = _region->earliest_in_selection().to_double(); + if (_copy) { + /* make copies of all the selected notes */ + _primary = _region->copy_selection (_primary); + } } /* Total change in x and y since the start of the drag */ - frameoffset_t const dx = total_dx (event->button.state); + double const dx_qn = total_dx (event); int8_t const dy = total_dy (); /* Now work out what we have to do to the note canvas items to set this new drag delta */ - double const tdx = _x_constrained ? 0 : _editor->sample_to_pixel (dx) - _cumulative_dx; + double const tdx = _x_constrained ? 0 : dx_qn - _cumulative_dx; double const tdy = _y_constrained ? 0 : -dy * _note_height - _cumulative_dy; if (tdx || tdy) { - _cumulative_dx += tdx; + _cumulative_dx = dx_qn; _cumulative_dy += tdy; int8_t note_delta = total_dy(); if (tdx || tdy) { if (_copy) { - _region->move_copies (tdx, tdy, note_delta); + _region->move_copies (dx_qn, tdy, note_delta); } else { - _region->move_selection (tdx, tdy, note_delta); + _region->move_selection (dx_qn, tdy, note_delta); } /* the new note value may be the same as the old one, but we @@ -5831,7 +5842,7 @@ NoteDrag::finished (GdkEvent* ev, bool moved) } } } else { - _region->note_dropped (_primary, total_dx (ev->button.state), total_dy(), _copy); + _region->note_dropped (_primary, total_dx (ev), total_dy(), _copy); } } diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 95eaf1409b..711b5095c7 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -242,12 +242,13 @@ protected: } ARDOUR::frameoffset_t snap_delta (guint const) const; + double snap_delta_music (guint const) const; double current_pointer_x () const; double current_pointer_y () const; /* sets snap delta from unsnapped pos */ - void setup_snap_delta (framepos_t pos); + void setup_snap_delta (ARDOUR::MusicFrame pos); boost::shared_ptr<ARDOUR::Region> add_midi_region (MidiTimeAxisView*, bool commit); @@ -282,6 +283,7 @@ private: * framepos. used for relative snap. */ framepos_t _snap_delta; + double _snap_delta_music; CursorContext::Handle _cursor_ctx; ///< cursor change context bool _constraint_pressed; ///< if the keyboard indicated constraint modifier was pressed on start_grab() }; @@ -557,15 +559,17 @@ class NoteDrag : public Drag void finished (GdkEvent *, bool); void aborted (bool); + void setup_pointer_frame_offset (); private: - ARDOUR::frameoffset_t total_dx (const guint) const; + double total_dx (GdkEvent * event) const; // total movement in quarter notes int8_t total_dy () const; MidiRegionView* _region; NoteBase* _primary; double _cumulative_dx; double _cumulative_dy; + double _earliest; // earliest quarter note in note selection bool _was_selected; double _note_height; bool _copy; diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index da7f1a54b5..f9c088448e 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -2549,11 +2549,9 @@ MidiRegionView::add_to_selection (NoteBase* ev) } } -void -MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) +Evoral::Beats +MidiRegionView::earliest_in_selection () { - typedef vector<boost::shared_ptr<NoteType> > PossibleChord; - PossibleChord to_play; Evoral::Beats earliest = Evoral::MaxBeats; for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { @@ -2562,10 +2560,27 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) } } + return earliest; +} + +void +MidiRegionView::move_selection(double dx_qn, double dy, double cumulative_dy) +{ + typedef vector<boost::shared_ptr<NoteType> > PossibleChord; + Editor* editor = dynamic_cast<Editor*> (&trackview.editor()); + TempoMap& tmap (editor->session()->tempo_map()); + PossibleChord to_play; + Evoral::Beats earliest = earliest_in_selection(); + for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { - if ((*i)->note()->time() == earliest) { - to_play.push_back ((*i)->note()); + NoteBase* n = *i; + if (n->note()->time() == earliest) { + to_play.push_back (n->note()); } + double const note_time_qn = session_relative_qn (n->note()->time().to_double()); + double const dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn)) + - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x; + (*i)->move_event(dx, dy); } @@ -2593,15 +2608,17 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) } NoteBase* -MidiRegionView::copy_selection () +MidiRegionView::copy_selection (NoteBase* primary) { - NoteBase* note; _copy_drag_events.clear (); if (_selection.empty()) { return 0; } + NoteBase* note; + NoteBase* ret = 0; + for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { boost::shared_ptr<NoteType> g (new NoteType (*((*i)->note()))); if (midi_view()->note_mode() == Sustained) { @@ -2614,29 +2631,34 @@ MidiRegionView::copy_selection () note = h; } + if ((*i) == primary) { + ret = note; + } + _copy_drag_events.push_back (note); } - return _copy_drag_events.front (); + return ret; } void -MidiRegionView::move_copies (double dx, double dy, double cumulative_dy) +MidiRegionView::move_copies (double dx_qn, double dy, double cumulative_dy) { typedef vector<boost::shared_ptr<NoteType> > PossibleChord; + Editor* editor = dynamic_cast<Editor*> (&trackview.editor()); + TempoMap& tmap (editor->session()->tempo_map()); PossibleChord to_play; - Evoral::Beats earliest = Evoral::MaxBeats; + Evoral::Beats earliest = earliest_in_selection(); for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) { - if ((*i)->note()->time() < earliest) { - earliest = (*i)->note()->time(); + NoteBase* n = *i; + if (n->note()->time() == earliest) { + to_play.push_back (n->note()); } - } + double const note_time_qn = session_relative_qn (n->note()->time().to_double()); + double const dx = editor->sample_to_pixel_unrounded (tmap.frame_at_quarter_note (note_time_qn + dx_qn)) + - n->item()->item_to_canvas (ArdourCanvas::Duple (n->x0(), 0)).x; - for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) { - if ((*i)->note()->time() == earliest) { - to_play.push_back ((*i)->note()); - } (*i)->move_event(dx, dy); } @@ -2664,7 +2686,7 @@ MidiRegionView::move_copies (double dx, double dy, double cumulative_dy) } void -MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote, bool copy) +MidiRegionView::note_dropped(NoteBase *, double d_qn, int8_t dnote, bool copy) { uint8_t lowest_note_in_selection = 127; uint8_t highest_note_in_selection = 0; @@ -2693,15 +2715,13 @@ MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote, bool co if (highest_note_in_selection + dnote > 127) { highest_note_difference = highest_note_in_selection - 127; } - TempoMap& map (trackview.session()->tempo_map()); start_note_diff_command (_("move notes")); for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) { - double const start_qn = _region->quarter_note() - midi_region()->start_beats(); - framepos_t new_frames = map.frame_at_quarter_note (start_qn + (*i)->note()->time().to_double()) + dt; - Evoral::Beats new_time = Evoral::Beats (map.quarter_note_at_frame (new_frames) - start_qn); + Evoral::Beats new_time = Evoral::Beats (max ((*i)->note()->time().to_double() + d_qn, midi_region()->start_beats())); + if (new_time < 0) { continue; } @@ -2734,16 +2754,12 @@ MidiRegionView::note_dropped(NoteBase *, frameoffset_t dt, int8_t dnote, bool co highest_note_difference = highest_note_in_selection - 127; } - TempoMap& map (trackview.session()->tempo_map()); start_note_diff_command (_("copy notes")); for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end() ; ++i) { /* update time */ - - double const start_qn = _region->quarter_note() - midi_region()->start_beats(); - framepos_t new_frames = map.frame_at_quarter_note (start_qn + (*i)->note()->time().to_double()) + dt; - Evoral::Beats new_time = Evoral::Beats (map.quarter_note_at_frame (new_frames) - start_qn); + Evoral::Beats new_time = Evoral::Beats (max ((*i)->note()->time().to_double() + d_qn, midi_region()->start_beats())); if (new_time < 0) { continue; @@ -2790,7 +2806,7 @@ framepos_t MidiRegionView::snap_pixel_to_sample(double x, bool ensure_snap) { PublicEditor& editor (trackview.editor()); - return snap_frame_to_frame (editor.pixel_to_sample (x), ensure_snap); + return snap_frame_to_frame (editor.pixel_to_sample (x), ensure_snap).frame; } /** @param x Pixel relative to the region position. @@ -4369,3 +4385,9 @@ MidiRegionView::note_to_y(uint8_t note) const { return contents_height() - (note + 1 - _current_range_min) * note_height() + 1; } + +double +MidiRegionView::session_relative_qn (double qn) const +{ + return qn + (region()->quarter_note() - midi_region()->start_beats()); +} diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index 929b3bd7f9..0d5b82255d 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -200,10 +200,11 @@ public: void select_range(framepos_t start, framepos_t end); void invert_selection (); + Evoral::Beats earliest_in_selection (); void move_selection(double dx, double dy, double cumulative_dy); - void note_dropped (NoteBase* ev, ARDOUR::frameoffset_t, int8_t d_note, bool copy); - NoteBase* copy_selection (); - void move_copies(double dx, double dy, double cumulative_dy); + void note_dropped (NoteBase* ev, double d_qn, int8_t d_note, bool copy); + NoteBase* copy_selection (NoteBase* primary); + void move_copies(double dx_qn, double dy, double cumulative_dy); void select_notes (std::list<Evoral::event_id_t>); void select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend); @@ -297,6 +298,8 @@ public: return _region_relative_time_converter_double; } + double session_relative_qn (double qn) const; + void goto_previous_note (bool add_to_selection); void goto_next_note (bool add_to_selection); void change_note_lengths (bool, bool, Evoral::Beats beats, bool start, bool end); diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc index 9f6ff645ce..c689a15e7d 100644 --- a/gtk2_ardour/region_view.cc +++ b/gtk2_ardour/region_view.cc @@ -943,7 +943,7 @@ RegionView::move_contents (frameoffset_t distance) * Used when inverting snap mode logic with key modifiers, or snap distance calculation. * @return Snapped frame offset from this region's position. */ -frameoffset_t +MusicFrame RegionView::snap_frame_to_frame (frameoffset_t x, bool ensure_snap) const { PublicEditor& editor = trackview.editor(); @@ -960,6 +960,6 @@ RegionView::snap_frame_to_frame (frameoffset_t x, bool ensure_snap) const editor.snap_to (frame, RoundUpAlways, false, ensure_snap); } - /* back to region relative */ - return frame.frame - _region->position(); + /* back to region relative, keeping the relevant divisor */ + return MusicFrame (frame.frame - _region->position(), frame.division); } diff --git a/gtk2_ardour/region_view.h b/gtk2_ardour/region_view.h index 7fad731dc2..10eb7b5dc6 100644 --- a/gtk2_ardour/region_view.h +++ b/gtk2_ardour/region_view.h @@ -121,7 +121,7 @@ class RegionView : public TimeAxisViewItem } }; - ARDOUR::frameoffset_t snap_frame_to_frame (ARDOUR::frameoffset_t, bool ensure_snap = false) const; + ARDOUR::MusicFrame snap_frame_to_frame (ARDOUR::frameoffset_t, bool ensure_snap = false) const; protected: |