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.
This commit is contained in:
nick_m 2017-02-05 05:02:01 +11:00
parent fac04afbba
commit 5031bdcf10
7 changed files with 134 additions and 94 deletions

View file

@ -183,7 +183,7 @@ AutomationRegionView::add_automation_event (GdkEvent *, framepos_t when, double
/* snap frame */ /* 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 */ /* map using line */

View file

@ -238,6 +238,7 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only)
, _grab_frame (0) , _grab_frame (0)
, _last_pointer_frame (0) , _last_pointer_frame (0)
, _snap_delta (0) , _snap_delta (0)
, _snap_delta_music (0.0)
, _constraint_pressed (false) , _constraint_pressed (false)
{ {
@ -355,6 +356,15 @@ Drag::snap_delta (guint state) const
return 0; return 0;
} }
double
Drag::snap_delta_music (guint state) const
{
if (ArdourKeyboard::indicates_snap_delta (state)) {
return _snap_delta_music;
}
return 0.0;
}
double double
Drag::current_pointer_x() const Drag::current_pointer_x() const
@ -373,11 +383,18 @@ Drag::current_pointer_y () const
} }
void 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); _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 bool
@ -618,7 +635,7 @@ void
RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{ {
Drag::start_grab (event, cursor); Drag::start_grab (event, cursor);
setup_snap_delta (_last_position.frame); setup_snap_delta (_last_position);
show_verbose_cursor_time (_last_position.frame); 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); framecnt_t const region_length = (framecnt_t) (_primary->region()->length() / speed);
framepos_t const pf = adjusted_current_frame (event); 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 ())) { if (Keyboard::modifier_state_equals (event->button.state, ArdourKeyboard::trim_contents_modifier ())) {
/* Move the contents of the region around without changing the region bounds */ /* 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) CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
{ {
Drag::start_grab (event, 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; _grab_zoom = _editor->samples_per_pixel;
@ -3744,7 +3761,7 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary); AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
boost::shared_ptr<AudioRegion> const r = arv->audio_region (); 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); 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); AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
boost::shared_ptr<AudioRegion> r = arv->audio_region (); 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()); 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 { } else {
show_verbose_cursor_time (location->end()); 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); 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_x = _point->get_x() + _editor->sample_to_pixel_unrounded (_point->line().offset());
_fixed_grab_y = _point->get_y(); _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()); float const fraction = 1 - (_point->get_y() / _point->line().height());
show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction)); 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); _editor->get_selection().add (_primary);
framepos_t where = _primary->region()->position(); MusicFrame where (_primary->region()->position(), 0);
setup_snap_delta (where); 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 void
@ -5627,6 +5644,7 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
: Drag (e, i) : Drag (e, i)
, _cumulative_dx (0) , _cumulative_dx (0)
, _cumulative_dy (0) , _cumulative_dy (0)
, _earliest (0.0)
, _was_selected (false) , _was_selected (false)
, _copy (false) , _copy (false)
{ {
@ -5638,6 +5656,13 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
_note_height = _region->midi_stream_view()->note_height (); _note_height = _region->midi_stream_view()->note_height ();
} }
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 void
NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *) NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
{ {
@ -5649,7 +5674,7 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
_copy = false; _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())) { if (!(_was_selected = _primary->selected())) {
@ -5673,55 +5698,38 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
} }
} }
/** @return Current total drag x change in frames */ /** @return Current total drag x change in quarter notes */
frameoffset_t double
NoteDrag::total_dx (const guint state) const NoteDrag::total_dx (GdkEvent * event) const
{ {
if (_x_constrained) { if (_x_constrained) {
return 0; return 0;
} }
TempoMap& map (_editor->session()->tempo_map()); TempoMap& map (_editor->session()->tempo_map());
/* dx in frames */ /* dx in frames */
frameoffset_t const dx = _editor->pixel_to_sample (_drags->current_pointer_x() - grab_x()); frameoffset_t const dx = _editor->pixel_to_sample (_drags->current_pointer_x() - grab_x());
/* primary note time */ /* 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 (_region->session_relative_qn (_primary->note()->time().to_double()));
frameoffset_t const n = map.frame_at_quarter_note (quarter_note_start + _primary->note()->time().to_double());
/* primary note time in quarter notes */
double const n_qn = _region->session_relative_qn (_primary->note()->time().to_double());
/* new time of the primary note in session frames */ /* new time of the primary note in session frames */
frameoffset_t st = n + dx + snap_delta (state); frameoffset_t st = n + dx + snap_delta (event->button.state);
framepos_t const rp = _region->region()->position (); /* 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);
/* prevent the note being dragged earlier than the region's position */ /* prevent the earliest note being dragged earlier than the region's start position */
st = max (st, rp); if (_earliest + ret < _region->midi_region()->start_beats()) {
ret -= (_earliest + ret) - _region->midi_region()->start_beats();
/* possibly snap and return corresponding delta */
bool snap = true;
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;
}
}
} }
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; return ret;
} }
@ -5747,30 +5755,33 @@ NoteDrag::total_dy () const
void void
NoteDrag::motion (GdkEvent * event, bool first_move) NoteDrag::motion (GdkEvent * event, bool first_move)
{ {
if (_copy && first_move) { if (first_move) {
_earliest = _region->earliest_in_selection().to_double();
if (_copy) {
/* make copies of all the selected notes */ /* make copies of all the selected notes */
_primary = _region->copy_selection (); _primary = _region->copy_selection (_primary);
}
} }
/* Total change in x and y since the start of the drag */ /* 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 (); 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 */ /* 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; double const tdy = _y_constrained ? 0 : -dy * _note_height - _cumulative_dy;
if (tdx || tdy) { if (tdx || tdy) {
_cumulative_dx += tdx; _cumulative_dx = dx_qn;
_cumulative_dy += tdy; _cumulative_dy += tdy;
int8_t note_delta = total_dy(); int8_t note_delta = total_dy();
if (tdx || tdy) { if (tdx || tdy) {
if (_copy) { if (_copy) {
_region->move_copies (tdx, tdy, note_delta); _region->move_copies (dx_qn, tdy, note_delta);
} else { } 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 /* 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 { } else {
_region->note_dropped (_primary, total_dx (ev->button.state), total_dy(), _copy); _region->note_dropped (_primary, total_dx (ev), total_dy(), _copy);
} }
} }

View file

@ -242,12 +242,13 @@ protected:
} }
ARDOUR::frameoffset_t snap_delta (guint const) const; ARDOUR::frameoffset_t snap_delta (guint const) const;
double snap_delta_music (guint const) const;
double current_pointer_x () const; double current_pointer_x () const;
double current_pointer_y () const; double current_pointer_y () const;
/* sets snap delta from unsnapped pos */ /* 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); boost::shared_ptr<ARDOUR::Region> add_midi_region (MidiTimeAxisView*, bool commit);
@ -282,6 +283,7 @@ private:
* framepos. used for relative snap. * framepos. used for relative snap.
*/ */
framepos_t _snap_delta; framepos_t _snap_delta;
double _snap_delta_music;
CursorContext::Handle _cursor_ctx; ///< cursor change context CursorContext::Handle _cursor_ctx; ///< cursor change context
bool _constraint_pressed; ///< if the keyboard indicated constraint modifier was pressed on start_grab() 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 finished (GdkEvent *, bool);
void aborted (bool); void aborted (bool);
void setup_pointer_frame_offset ();
private: 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; int8_t total_dy () const;
MidiRegionView* _region; MidiRegionView* _region;
NoteBase* _primary; NoteBase* _primary;
double _cumulative_dx; double _cumulative_dx;
double _cumulative_dy; double _cumulative_dy;
double _earliest; // earliest quarter note in note selection
bool _was_selected; bool _was_selected;
double _note_height; double _note_height;
bool _copy; bool _copy;

View file

@ -2549,11 +2549,9 @@ MidiRegionView::add_to_selection (NoteBase* ev)
} }
} }
void Evoral::Beats
MidiRegionView::move_selection(double dx, double dy, double cumulative_dy) MidiRegionView::earliest_in_selection ()
{ {
typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
PossibleChord to_play;
Evoral::Beats earliest = Evoral::MaxBeats; Evoral::Beats earliest = Evoral::MaxBeats;
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
@ -2562,10 +2560,27 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
} }
} }
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { return earliest;
if ((*i)->note()->time() == earliest) {
to_play.push_back ((*i)->note());
} }
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) {
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); (*i)->move_event(dx, dy);
} }
@ -2593,15 +2608,17 @@ MidiRegionView::move_selection(double dx, double dy, double cumulative_dy)
} }
NoteBase* NoteBase*
MidiRegionView::copy_selection () MidiRegionView::copy_selection (NoteBase* primary)
{ {
NoteBase* note;
_copy_drag_events.clear (); _copy_drag_events.clear ();
if (_selection.empty()) { if (_selection.empty()) {
return 0; return 0;
} }
NoteBase* note;
NoteBase* ret = 0;
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) { for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
boost::shared_ptr<NoteType> g (new NoteType (*((*i)->note()))); boost::shared_ptr<NoteType> g (new NoteType (*((*i)->note())));
if (midi_view()->note_mode() == Sustained) { if (midi_view()->note_mode() == Sustained) {
@ -2614,29 +2631,34 @@ MidiRegionView::copy_selection ()
note = h; note = h;
} }
if ((*i) == primary) {
ret = note;
}
_copy_drag_events.push_back (note); _copy_drag_events.push_back (note);
} }
return _copy_drag_events.front (); return ret;
} }
void 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; typedef vector<boost::shared_ptr<NoteType> > PossibleChord;
Editor* editor = dynamic_cast<Editor*> (&trackview.editor());
TempoMap& tmap (editor->session()->tempo_map());
PossibleChord to_play; 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) { for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end(); ++i) {
if ((*i)->note()->time() < earliest) { NoteBase* n = *i;
earliest = (*i)->note()->time(); 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); (*i)->move_event(dx, dy);
} }
@ -2664,7 +2686,7 @@ MidiRegionView::move_copies (double dx, double dy, double cumulative_dy)
} }
void 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 lowest_note_in_selection = 127;
uint8_t highest_note_in_selection = 0; 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) { if (highest_note_in_selection + dnote > 127) {
highest_note_difference = highest_note_in_selection - 127; highest_note_difference = highest_note_in_selection - 127;
} }
TempoMap& map (trackview.session()->tempo_map());
start_note_diff_command (_("move notes")); start_note_diff_command (_("move notes"));
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) { for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
double const start_qn = _region->quarter_note() - midi_region()->start_beats(); Evoral::Beats new_time = Evoral::Beats (max ((*i)->note()->time().to_double() + d_qn, 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);
if (new_time < 0) { if (new_time < 0) {
continue; 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; highest_note_difference = highest_note_in_selection - 127;
} }
TempoMap& map (trackview.session()->tempo_map());
start_note_diff_command (_("copy notes")); start_note_diff_command (_("copy notes"));
for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end() ; ++i) { for (CopyDragEvents::iterator i = _copy_drag_events.begin(); i != _copy_drag_events.end() ; ++i) {
/* update time */ /* update time */
Evoral::Beats new_time = Evoral::Beats (max ((*i)->note()->time().to_double() + d_qn, midi_region()->start_beats()));
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);
if (new_time < 0) { if (new_time < 0) {
continue; continue;
@ -2790,7 +2806,7 @@ framepos_t
MidiRegionView::snap_pixel_to_sample(double x, bool ensure_snap) MidiRegionView::snap_pixel_to_sample(double x, bool ensure_snap)
{ {
PublicEditor& editor (trackview.editor()); 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. /** @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; 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());
}

View file

@ -200,10 +200,11 @@ public:
void select_range(framepos_t start, framepos_t end); void select_range(framepos_t start, framepos_t end);
void invert_selection (); void invert_selection ();
Evoral::Beats earliest_in_selection ();
void move_selection(double dx, double dy, double cumulative_dy); void move_selection(double dx, double dy, double cumulative_dy);
void note_dropped (NoteBase* ev, ARDOUR::frameoffset_t, int8_t d_note, bool copy); void note_dropped (NoteBase* ev, double d_qn, int8_t d_note, bool copy);
NoteBase* copy_selection (); NoteBase* copy_selection (NoteBase* primary);
void move_copies(double dx, double dy, double cumulative_dy); void move_copies(double dx_qn, double dy, double cumulative_dy);
void select_notes (std::list<Evoral::event_id_t>); void select_notes (std::list<Evoral::event_id_t>);
void select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend); 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; return _region_relative_time_converter_double;
} }
double session_relative_qn (double qn) const;
void goto_previous_note (bool add_to_selection); void goto_previous_note (bool add_to_selection);
void goto_next_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); void change_note_lengths (bool, bool, Evoral::Beats beats, bool start, bool end);

View file

@ -943,7 +943,7 @@ RegionView::move_contents (frameoffset_t distance)
* Used when inverting snap mode logic with key modifiers, or snap distance calculation. * Used when inverting snap mode logic with key modifiers, or snap distance calculation.
* @return Snapped frame offset from this region's position. * @return Snapped frame offset from this region's position.
*/ */
frameoffset_t MusicFrame
RegionView::snap_frame_to_frame (frameoffset_t x, bool ensure_snap) const RegionView::snap_frame_to_frame (frameoffset_t x, bool ensure_snap) const
{ {
PublicEditor& editor = trackview.editor(); 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); editor.snap_to (frame, RoundUpAlways, false, ensure_snap);
} }
/* back to region relative */ /* back to region relative, keeping the relevant divisor */
return frame.frame - _region->position(); return MusicFrame (frame.frame - _region->position(), frame.division);
} }

View file

@ -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: protected: