- NoteCreateDrag already applies this shift, so it was
always applied twice to the note start frame.
const framepos_t pf = _drags->current_pointer_frame ();
const int32_t divisions = _editor->get_grid_music_divisions (event->button.state);
const framepos_t pf = _drags->current_pointer_frame ();
const int32_t divisions = _editor->get_grid_music_divisions (event->button.state);
- const double qaf = map.quarter_note_at_frame (pf);
- double eqaf;
+ double eqaf = map.exact_qn_at_frame (pf, divisions);
+
if (divisions != 0) {
bool success = false;
Evoral::Beats grid_beats = _editor->get_grid_type_as_beats (success, pf);
if (divisions != 0) {
bool success = false;
Evoral::Beats grid_beats = _editor->get_grid_type_as_beats (success, pf);
grid_beats = Evoral::Beats(1);
}
grid_beats = Evoral::Beats(1);
}
- eqaf = map.exact_qn_at_frame (pf, divisions);
+ const double qaf = map.quarter_note_at_frame (pf);
/* 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.
*/
/* 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.
*/
- const double rem = fmod (qaf, grid_beats.to_double());
- if (rem >= grid_beats.to_double() / 2.0) {
+
+ const double rem = eqaf - qaf;
+ if (rem >= 0.0 && eqaf - grid_beats.to_double() > _region_view->region()->pulse() * 4.0) {
eqaf -= grid_beats.to_double();
}
eqaf -= grid_beats.to_double();
}
}
_note[0] = map.frame_at_quarter_note (eqaf) - _region_view->region()->position();
}
_note[0] = map.frame_at_quarter_note (eqaf) - _region_view->region()->position();
const double qn_length = map.quarter_note_at_frame (start_sess_rel + length) - map.quarter_note_at_frame (start_sess_rel);
Evoral::Beats qn_length_beats = max (one_tick, Evoral::Beats (qn_length));
const double qn_length = map.quarter_note_at_frame (start_sess_rel + length) - map.quarter_note_at_frame (start_sess_rel);
Evoral::Beats qn_length_beats = max (one_tick, Evoral::Beats (qn_length));
- _region_view->create_note_at (start, _drag_rect->y0(), qn_length_beats, ev->button.state);
+ _region_view->create_note_at (start, _drag_rect->y0(), qn_length_beats, ev->button.state, false);
group->canvas_to_item (event_x, event_y);
Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x) + _region->position());
group->canvas_to_item (event_x, event_y);
Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x) + _region->position());
- create_note_at (editor.pixel_to_sample (event_x), event_y, beats, ev->state);
+ create_note_at (editor.pixel_to_sample (event_x), event_y, beats, ev->state, true);
} else {
clear_editor_note_selection ();
}
} else {
clear_editor_note_selection ();
}
case MouseDraw:
{
Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x) + _region->position());
case MouseDraw:
{
Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x) + _region->position());
- create_note_at (editor.pixel_to_sample (event_x), event_y, beats, ev->state);
+ create_note_at (editor.pixel_to_sample (event_x), event_y, beats, ev->state, true);
* \param snap_t true to snap t to the grid, otherwise false.
*/
void
* \param snap_t true to snap t to the grid, otherwise false.
*/
void
-MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, uint32_t state)
+MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, uint32_t state, bool shift_snap)
{
if (length < 2 * DBL_EPSILON) {
return;
{
if (length < 2 * DBL_EPSILON) {
return;
// Start of note in frames relative to region start
const int32_t divisions = trackview.editor().get_grid_music_divisions (state);
// Start of note in frames relative to region start
const int32_t divisions = trackview.editor().get_grid_music_divisions (state);
- Evoral::Beats beat_time = snap_frame_to_grid_underneath (t, divisions);
+ Evoral::Beats beat_time = snap_frame_to_grid_underneath (t, divisions, shift_snap);
const double note = view->y_to_note(y);
const uint8_t chan = mtv->get_channel_for_add();
const double note = view->y_to_note(y);
const uint8_t chan = mtv->get_channel_for_add();
framepos_t const unsnapped_frame = editor.pixel_to_sample (x);
const int32_t divisions = editor.get_grid_music_divisions (state);
framepos_t const unsnapped_frame = editor.pixel_to_sample (x);
const int32_t divisions = editor.get_grid_music_divisions (state);
- const double snapped_region_qn = snap_frame_to_grid_underneath (unsnapped_frame, divisions).to_double();
+ const double snapped_region_qn = snap_frame_to_grid_underneath (unsnapped_frame, divisions, true).to_double();
Evoral::Beats snapped_beats = Evoral::Beats (snapped_region_qn);
/* calculate time in beats relative to start of source */
Evoral::Beats snapped_beats = Evoral::Beats (snapped_region_qn);
/* calculate time in beats relative to start of source */
* @return beat duration of p snapped to the grid subdivision underneath it.
*/
Evoral::Beats
* @return beat duration of p snapped to the grid subdivision underneath it.
*/
Evoral::Beats
-MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, int32_t divisions) const
+MidiRegionView::snap_frame_to_grid_underneath (framepos_t p, int32_t divisions, bool shift_snap) const
{
TempoMap& map (trackview.session()->tempo_map());
double eqaf = map.exact_qn_at_frame (p + _region->position(), divisions);
{
TempoMap& map (trackview.session()->tempo_map());
double eqaf = map.exact_qn_at_frame (p + _region->position(), divisions);
+ if (divisions != 0 && shift_snap) {
const double qaf = map.quarter_note_at_frame (p + _region->position());
/* 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.
const double qaf = map.quarter_note_at_frame (p + _region->position());
/* 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.
* \param y vertical position in pixels
* \param length duration of the note in beats
* \param state the keyboard modifier mask for the canvas event (click).
* \param y vertical position in pixels
* \param length duration of the note in beats
* \param state the keyboard modifier mask for the canvas event (click).
+ * \param shift_snap true alters snap behavior to round down always (false if the gui has already done that).
- void create_note_at (framepos_t t, double y, Evoral::Beats length, uint32_t state);
+ void create_note_at (framepos_t t, double y, Evoral::Beats length, uint32_t state, bool shift_snap);
/** An external request to clear the note selection, remove MRV from editor
* selection.
/** An external request to clear the note selection, remove MRV from editor
* selection.
bool _mouse_changed_selection;
bool _mouse_changed_selection;
- Evoral::Beats snap_frame_to_grid_underneath (framepos_t p, int32_t divisions) const;
+ Evoral::Beats snap_frame_to_grid_underneath (framepos_t p, int32_t divisions, bool shift_snap) const;
PBD::ScopedConnection _mouse_mode_connection;
PBD::ScopedConnection _mouse_mode_connection;