event_y = ev->y;
group->canvas_to_item (event_x, event_y);
- Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x));
- create_note_at (editor.pixel_to_sample (event_x), event_y, beats, ev->state);
+ 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, true);
} else {
clear_editor_note_selection ();
}
}
case MouseDraw:
{
- Evoral::Beats beats = get_grid_beats(editor.pixel_to_sample(event_x));
- create_note_at (editor.pixel_to_sample (event_x), event_y, beats, ev->state);
+ 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, true);
break;
}
default:
if (!_note_entered) {
- if (!_ghost_note && editor.current_mouse_mode() == MouseContent &&
+ if (_mouse_state == AddDragging) {
+ if (_ghost_note) {
+ remove_ghost_note ();
+ }
+
+ } else if (!_ghost_note && editor.current_mouse_mode() == MouseContent &&
Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier()) &&
_mouse_state != AddDragging) {
* \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 (!mr) {
return;
}
- TempoMap& map (trackview.session()->tempo_map());
// Start of note in frames relative to region start
const int32_t divisions = trackview.editor().get_grid_music_divisions (state);
- const double snapped_qn = map.exact_qn_at_frame (t + _region->position(), divisions);
- /* make start region start relative */
- const double start_qn = (_region->pulse() - mr->start_pulse()) * 4.0;
- Evoral::Beats beat_time = Evoral::Beats (snapped_qn - start_qn);
-
+ 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();
/** This version finds any canvas note matching the supplied note. */
NoteBase*
-MidiRegionView::find_canvas_note (NoteType note)
+MidiRegionView::find_canvas_note (Evoral::event_id_t id)
{
Events::iterator it;
for (it = _events.begin(); it != _events.end(); ++it) {
- if (*((*it)->note()) == note) {
+ if ((*it)->note()->id() == id) {
return *it;
}
}
cne = add_note (note, visible);
}
- set<boost::shared_ptr<NoteType> >::iterator it;
+ set<Evoral::event_id_t>::iterator it;
for (it = _pending_note_selection.begin(); it != _pending_note_selection.end(); ++it) {
- if (*(*it) == *note) {
+ if ((*it) == note->id()) {
add_to_selection (cne);
}
}
ghost->add_note(*i);
}
+ ghost->set_colors ();
ghost->set_height ();
ghost->set_duration (_region->length() / samples_per_pixel);
ghosts.push_back (ghost);
MidiRegionView::note_in_region_range (const boost::shared_ptr<NoteType> note, bool& visible) const
{
const boost::shared_ptr<ARDOUR::MidiRegion> midi_reg = midi_region();
- const bool outside = (note->time() < midi_reg->start_pulse() * 4.0 ||
- note->time() > (midi_reg->start_pulse() + midi_reg->length_pulse()) * 4.0);
+
+ /* must compare double explicitly as Beats::operator< rounds to ppqn */
+ const bool outside = (note->time().to_double() < midi_reg->start_beats() ||
+ note->time().to_double() > midi_reg->start_beats() + midi_reg->length_beats());
visible = (note->note() >= midi_stream_view()->lowest_note()) &&
(note->note() <= midi_stream_view()->highest_note());
TempoMap& map (trackview.session()->tempo_map());
const boost::shared_ptr<ARDOUR::MidiRegion> mr = midi_region();
boost::shared_ptr<NoteType> note = ev->note();
- const double qn_note_time = note->time().to_double() + ((_region->pulse() - mr->start_pulse()) * 4.0);
- const framepos_t note_start_frames = map.frame_at_quarter_note (qn_note_time) - _region->position();
+
+ const double session_source_start = (_region->pulse() * 4.0) - mr->start_beats();
+ const framepos_t note_start_frames = map.frame_at_quarter_note (note->time().to_double() + session_source_start) - _region->position();
+
const double x0 = trackview.editor().sample_to_pixel (note_start_frames);
double x1;
const double y0 = 1 + floor(midi_stream_view()->note_to_y(note->note()));
/* trim note display to not overlap the end of its region */
if (note->length() > 0) {
- Evoral::Beats note_end_time = note->end_time();
+ double note_end_time = note->end_time().to_double();
- if (note->end_time().to_double() > (mr->start_pulse() + mr->length_pulse()) * 4.0) {
- note_end_time = Evoral::Beats ((mr->start_pulse() + mr->length_pulse()) * 4.0);
+ if (note_end_time > mr->start_beats() + mr->length_beats()) {
+ note_end_time = mr->start_beats() + mr->length_beats();
}
- const double session_qn_start = (_region->pulse() - mr->start_pulse()) * 4.0;
- const double quarter_note_end_time = session_qn_start + note_end_time.to_double();
- const framepos_t note_end_frames = map.frame_at_quarter_note (quarter_note_end_time) - _region->position();
+ const framepos_t note_end_frames = map.frame_at_quarter_note (session_source_start + note_end_time) - _region->position();
+
x1 = std::max(1., trackview.editor().sample_to_pixel (note_end_frames)) - 1;
} else {
x1 = std::max(1., trackview.editor().sample_to_pixel (_region->length())) - 1;
y1 = y0 + std::max(1., floor(midi_stream_view()->note_height()) - 1);
- ArdourCanvas::Rect rect (x0, y0, x1, y1);
- ev->set (rect);
+ ev->set (ArdourCanvas::Rect (x0, y0, x1, y1));
if (!note->length()) {
if (_active_notes && note->note() < 128) {
}
// Update color in case velocity has changed
- //const uint32_t base_col = ev->base_color();
- //ev->set_fill_color(base_col);
- //ev->set_outline_color(ev->calculate_outline(base_col, ev->selected()));
+ const uint32_t base_col = ev->base_color();
+ ev->set_fill_color(base_col);
+ ev->set_outline_color(ev->calculate_outline(base_col, ev->selected()));
if (update_ghost_regions) {
for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
{
boost::shared_ptr<NoteType> note = ev->note();
- const double note_time_qn = note->time().to_double() + ((_region->pulse() - midi_region()->start_pulse()) * 4.0);
+ const double note_time_qn = note->time().to_double() + ((_region->pulse() * 4.0) - midi_region()->start_beats());
const framepos_t note_start_frames = trackview.session()->tempo_map().frame_at_quarter_note (note_time_qn) - _region->position();
const double x = trackview.editor().sample_to_pixel(note_start_frames);
ev->set_height (diamond_size);
// Update color in case velocity has changed
- ev->set_fill_color(ev->base_color());
- ev->set_outline_color(ev->calculate_outline(ev->base_color(), ev->selected()));
+ const uint32_t base_col = ev->base_color();
+ ev->set_fill_color(base_col);
+ ev->set_outline_color(ev->calculate_outline(base_col, ev->selected()));
if (update_ghost_regions) {
for (std::vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*i);
if (gr) {
- gr->update_note (ev);
+ gr->update_hit (ev);
}
}
}
return;
}
+ if (trackview.editor().drags()->active()) {
+ return;
+ }
+
start_note_diff_command (_("delete selection"));
for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
The requested notes most likely won't exist in the view until the next model redisplay.
*/
void
-MidiRegionView::select_notes (list<boost::shared_ptr<NoteType> > notes)
+MidiRegionView::select_notes (list<Evoral::event_id_t> notes)
{
NoteBase* cne;
- list<boost::shared_ptr<NoteType> >::iterator n;
+ list<Evoral::event_id_t>::iterator n;
for (n = notes.begin(); n != notes.end(); ++n) {
- if ((cne = find_canvas_note(*(*n))) != 0) {
+ if ((cne = find_canvas_note(*n)) != 0) {
add_to_selection (cne);
} else {
_pending_note_selection.insert(*n);
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
- double const start_qn = (_region->pulse() - midi_region()->start_pulse()) * 4.0;
+ double const start_qn = (_region->pulse() * 4.0) - 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) {
}
/* and then to beats */
- const double e_baf = tmap.exact_beat_at_frame (current_fr + midi_region()->position(), divisions);
- const double quarter_note_start_beat = tmap.quarter_note_at_beat (_region->beat() - midi_region()->start_beats().to_double());
- const Evoral::Beats x_beats = Evoral::Beats (tmap.quarter_note_at_beat (e_baf) - quarter_note_start_beat);
+ const double e_qaf = tmap.exact_qn_at_frame (current_fr + midi_region()->position(), divisions);
+ const double quarter_note_start = (_region->pulse() * 4.0) - midi_region()->start_beats();
+ const Evoral::Beats x_beats = Evoral::Beats (e_qaf - quarter_note_start);
if (at_front && x_beats < canvas_note->note()->end_time()) {
note_diff_add_change (canvas_note, MidiModel::NoteDiffCommand::StartTime, x_beats - (sign * snap_delta_beats));
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 Evoral::Beats snapped_beats = snap_frame_to_grid_underneath (unsnapped_frame, divisions, true);
+
+ /* ghost note may have been snapped before region */
+ if (_ghost_note && snapped_beats.to_double() < 0.0) {
+ _ghost_note->hide();
+ return;
+
+ } else if (_ghost_note) {
+ _ghost_note->show();
+ }
- Evoral::Beats snapped_beats = Evoral::Beats (snapped_region_qn);
/* calculate time in beats relative to start of source */
- const Evoral::Beats length = get_grid_beats(unsnapped_frame);
+ const Evoral::Beats length = get_grid_beats(unsnapped_frame + _region->position());
_ghost_note->note()->set_time (snapped_beats);
_ghost_note->note()->set_length (length);
* @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);
- const double qaf = map.quarter_note_at_frame (p + _region->position());
- double eqaf;
- if (divisions != 0) {
- 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 Evoral::Beats grid_beats = get_grid_beats (p);
- const double rem = fmod (qaf, grid_beats.to_double());
- if (rem >= grid_beats.to_double() / 2.0) {
+ const Evoral::Beats grid_beats = get_grid_beats (p + _region->position());
+ const double rem = eqaf - qaf;
+ if (rem >= 0.0) {
eqaf -= grid_beats.to_double();
}
- } else {
- eqaf = qaf;
}
+ const double session_start_off = (_region->pulse() * 4.0) - midi_region()->start_beats();
- return Evoral::Beats (eqaf - ((_region->pulse() - midi_region()->start_pulse()) * 4.0));
+ return Evoral::Beats (eqaf - session_start_off);
}
ChannelMode