+ if (_selection.find(ev) == _selection.end()) {
+ return;
+ }
+
+ uint8_t lowest_note_in_selection = midi_stream_view()->lowest_note();
+ uint8_t highest_note_in_selection = midi_stream_view()->highest_note();
+ uint8_t highest_note_difference = 0;
+
+ // find highest and lowest notes first
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ uint8_t pitch = (*i)->note()->note();
+ lowest_note_in_selection = std::min(lowest_note_in_selection, pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, pitch);
+ }
+
+ /*
+ cerr << "dnote: " << (int) dnote << endl;
+ cerr << "lowest note (streamview): " << int(midi_stream_view()->lowest_note())
+ << " highest note (streamview): " << int(midi_stream_view()->highest_note()) << endl;
+ cerr << "lowest note (selection): " << int(lowest_note_in_selection) << " highest note(selection): "
+ << int(highest_note_in_selection) << endl;
+ cerr << "selection size: " << _selection.size() << endl;
+ cerr << "Highest note in selection: " << (int) highest_note_in_selection << endl;
+ */
+
+ // Make sure the note pitch does not exceed the MIDI standard range
+ if (dnote <= 127 && (highest_note_in_selection + dnote > 127)) {
+ highest_note_difference = highest_note_in_selection - 127;
+ }
+
+ start_delta_command(_("move notes"));
+
+ for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ) {
+ Selection::iterator next = i;
+ ++next;
+
+ const boost::shared_ptr<NoteType> copy(new NoteType(*(*i)->note().get()));
+
+ nframes64_t start_frames = beats_to_frames((*i)->note()->time());
+ if (dt >= 0) {
+ start_frames += snap_frame_to_frame(trackview.editor().pixel_to_frame(dt));
+ } else {
+ start_frames -= snap_frame_to_frame(trackview.editor().pixel_to_frame(-dt));
+ }
+
+ copy->set_time(frames_to_beats(start_frames));
+
+ uint8_t original_pitch = (*i)->note()->note();
+ uint8_t new_pitch = original_pitch + dnote - highest_note_difference;
+
+ // keep notes in standard midi range
+ clamp_to_0_127(new_pitch);
+
+ // keep original pitch if note is dragged outside valid midi range
+ if ((original_pitch != 0 && new_pitch == 0)
+ || (original_pitch != 127 && new_pitch == 127)) {
+ new_pitch = original_pitch;
+ }
+
+ lowest_note_in_selection = std::min(lowest_note_in_selection, new_pitch);
+ highest_note_in_selection = std::max(highest_note_in_selection, new_pitch);
+
+ copy->set_note(new_pitch);
+
+ command_remove_note(*i);
+ command_add_note(copy, (*i)->selected());
+
+ i = next;
+ }
+
+ apply_command();
+
+ // care about notes being moved beyond the upper/lower bounds on the canvas
+ if (lowest_note_in_selection < midi_stream_view()->lowest_note() ||
+ highest_note_in_selection > midi_stream_view()->highest_note()) {
+ midi_stream_view()->set_note_range(MidiStreamView::ContentsRange);
+ }
+}
+
+nframes64_t
+MidiRegionView::snap_pixel_to_frame(double x)
+{
+ PublicEditor& editor = trackview.editor();
+ // x is region relative, convert it to global absolute frames
+ nframes64_t frame = editor.pixel_to_frame(x) + _region->position();
+ editor.snap_to(frame);
+ return frame - _region->position(); // convert back to region relative
+}
+
+nframes64_t
+MidiRegionView::snap_frame_to_frame(nframes64_t x)
+{
+ PublicEditor& editor = trackview.editor();
+ // x is region relative, convert it to global absolute frames
+ nframes64_t frame = x + _region->position();
+ editor.snap_to(frame);
+ return frame - _region->position(); // convert back to region relative
+}
+
+double
+MidiRegionView::snap_to_pixel(double x)
+{
+ return (double) trackview.editor().frame_to_pixel(snap_pixel_to_frame(x));
+}
+
+double
+MidiRegionView::get_position_pixels()
+{
+ nframes64_t region_frame = get_position();
+ return trackview.editor().frame_to_pixel(region_frame);
+}
+
+nframes64_t
+MidiRegionView::beats_to_frames(double beats) const
+{
+ return _time_converter.to(beats);
+}
+
+double
+MidiRegionView::frames_to_beats(nframes64_t frames) const
+{
+ return _time_converter.from(frames);
+}
+
+void
+MidiRegionView::begin_resizing(CanvasNote::NoteEnd note_end)
+{
+ _resize_data.clear();
+
+ for (Selection::iterator i = _selection.begin(); i != _selection.end(); ++i) {
+ CanvasNote *note = dynamic_cast<CanvasNote *> (*i);
+
+ // only insert CanvasNotes into the map
+ if (note) {
+ NoteResizeData *resize_data = new NoteResizeData();
+ resize_data->canvas_note = note;
+
+ // create a new SimpleRect from the note which will be the resize preview
+ SimpleRect *resize_rect = new SimpleRect(
+ *group, note->x1(), note->y1(), note->x2(), note->y2());