+ _step_edit_cursor_width = beats;
+
+ if (_step_edit_cursor) {
+ _step_edit_cursor->property_x2() = _step_edit_cursor->property_x1() + trackview.editor().frame_to_pixel (region_beats_to_region_frames (beats));
+ }
+}
+
+/** Called when a diskstream on our track has received some data. Update the view, if applicable.
+ * @param w Source that the data will end up in.
+ */
+void
+MidiRegionView::data_recorded (boost::weak_ptr<MidiSource> w)
+{
+ if (!_active_notes) {
+ /* we aren't actively being recorded to */
+ return;
+ }
+
+ boost::shared_ptr<MidiSource> src = w.lock ();
+ if (!src || src != midi_region()->midi_source()) {
+ /* recorded data was not destined for our source */
+ return;
+ }
+
+ MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (&trackview);
+
+ boost::shared_ptr<MidiBuffer> buf = mtv->midi_track()->get_gui_feed_buffer ();
+
+ BeatsFramesConverter converter (trackview.session()->tempo_map(), mtv->midi_track()->get_capture_start_frame (0));
+
+ framepos_t back = max_framepos;
+
+ for (MidiBuffer::iterator i = buf->begin(); i != buf->end(); ++i) {
+ Evoral::MIDIEvent<MidiBuffer::TimeType> const ev (*i, false);
+ assert (ev.buffer ());
+
+ /* ev.time() is in session frames, so (ev.time() - converter.origin_b()) is
+ frames from the start of the source, and so time_beats is in terms of the
+ source.
+ */
+
+ Evoral::MusicalTime const time_beats = converter.from (ev.time () - converter.origin_b ());
+
+ if (ev.type() == MIDI_CMD_NOTE_ON) {
+
+ boost::shared_ptr<NoteType> note (
+ new NoteType (ev.channel(), time_beats, 0, ev.note(), ev.velocity())
+ );
+
+ add_note (note, true);
+
+ /* fix up our note range */
+ if (ev.note() < _current_range_min) {
+ midi_stream_view()->apply_note_range (ev.note(), _current_range_max, true);
+ } else if (ev.note() > _current_range_max) {
+ midi_stream_view()->apply_note_range (_current_range_min, ev.note(), true);
+ }
+
+ } else if (ev.type() == MIDI_CMD_NOTE_OFF) {
+ resolve_note (ev.note (), time_beats);
+ }
+
+ back = ev.time ();
+ }
+
+ midi_stream_view()->check_record_layers (region(), back);
+}
+
+void
+MidiRegionView::trim_front_starting ()
+{
+ /* Reparent the note group to the region view's parent, so that it doesn't change
+ when the region view is trimmed.
+ */
+ _temporary_note_group = new ArdourCanvas::Group (*group->property_parent ());
+ _temporary_note_group->move (group->property_x(), group->property_y());
+ _note_group->reparent (*_temporary_note_group);
+}
+
+void
+MidiRegionView::trim_front_ending ()
+{
+ _note_group->reparent (*group);
+ delete _temporary_note_group;
+ _temporary_note_group = 0;
+
+ if (_region->start() < 0) {
+ /* Trim drag made start time -ve; fix this */
+ midi_region()->fix_negative_start ();
+ }
+}
+
+void
+MidiRegionView::edit_patch_change (ArdourCanvas::CanvasPatchChange* pc)
+{
+ PatchChangeDialog d (&_source_relative_time_converter, trackview.session(), *pc->patch (), instrument_info(), Gtk::Stock::APPLY);
+ if (d.run () != Gtk::RESPONSE_ACCEPT) {
+ return;
+ }
+
+ change_patch_change (pc->patch(), d.patch ());
+}
+
+
+void
+MidiRegionView::show_verbose_cursor (boost::shared_ptr<NoteType> n) const
+{
+ char buf[24];
+ snprintf (buf, sizeof (buf), "%s (%d) Chn %d\nVel %d",
+ Evoral::midi_note_name (n->note()).c_str(),
+ (int) n->note (),
+ (int) n->channel() + 1,
+ (int) n->velocity());
+
+ show_verbose_cursor (buf, 10, 20);
+}
+
+void
+MidiRegionView::show_verbose_cursor (string const & text, double xoffset, double yoffset) const
+{
+ double wx, wy;