diff options
Diffstat (limited to 'gtk2_ardour/midi_region_view.cc')
-rw-r--r-- | gtk2_ardour/midi_region_view.cc | 114 |
1 files changed, 112 insertions, 2 deletions
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index e4cb80bca0..81ea4029de 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -25,10 +25,12 @@ #include <gtkmm2ext/gtk_ui.h> #include <ardour/playlist.h> +#include <ardour/tempo.h> #include <ardour/midi_region.h> #include <ardour/midi_source.h> #include <ardour/midi_diskstream.h> #include <ardour/midi_events.h> +#include <ardour/midi_model.h> #include "streamview.h" #include "midi_region_view.h" @@ -93,6 +95,52 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd) midi_region()->midi_source(0)->load_model(); display_events(); } + + group->signal_event().connect (mem_fun (this, &MidiRegionView::canvas_event)); +} + +bool +MidiRegionView::canvas_event(GdkEvent* ev) +{ + if (trackview.editor.current_mouse_mode() == MouseNote) { + if (ev->type == GDK_BUTTON_PRESS) { + MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview); + MidiStreamView* const view = mtv->midi_view(); + + const uint8_t note_range = view->highest_note() - view->lowest_note() + 1; + const double footer_height = name_highlight->property_y2() - name_highlight->property_y1(); + const double roll_height = trackview.height - footer_height; + + double x = ev->button.x; + double y = ev->button.y; + get_canvas_group()->w2i(x, y); + + double note = floor((roll_height - y) / roll_height * (double)note_range) + view->lowest_note(); + assert(note >= 0.0); + assert(note <= 127.0); + + const nframes_t stamp = trackview.editor.pixel_to_frame (x); + assert(stamp >= 0); + //assert(stamp <= _region->length()); + + const Meter& m = trackview.session().tempo_map().meter_at(stamp); + const Tempo& t = trackview.session().tempo_map().tempo_at(stamp); + double dur = m.frames_per_bar(t, trackview.session().frame_rate()) / m.beats_per_bar(); + + // Add a 1 beat long note (for now) + const MidiModel::Note new_note(stamp, dur, (uint8_t)note, 0x40); + + MidiModel::Notes& notes = midi_region()->midi_source(0)->model()->notes(); + MidiModel::Notes::iterator i = upper_bound(notes.begin(), notes.end(), new_note, + MidiModel::NoteTimeComparator()); + notes.insert(i, new_note); + view->update_bounds(new_note.note); + + add_note(new_note); + } + } + + return false; } @@ -113,8 +161,8 @@ MidiRegionView::display_events() begin_write(); - for (size_t i=0; i < midi_region()->midi_source(0)->model()->n_events(); ++i) - add_event(midi_region()->midi_source(0)->model()->event_at(i)); + for (size_t i=0; i < midi_region()->midi_source(0)->model()->n_notes(); ++i) + add_note(midi_region()->midi_source(0)->model()->note_at(i)); end_write(); } @@ -222,6 +270,11 @@ MidiRegionView::end_write() } +/** Add a MIDI event. + * + * This is used while recording, and handles displaying still-unresolved notes. + * Displaying an existing model is simpler, and done with add_note. + */ void MidiRegionView::add_event (const MidiEvent& ev) { @@ -300,4 +353,61 @@ MidiRegionView::extend_active_notes() } +/** Add a MIDI note (with duration). + * + * This does no 'realtime' note resolution, notes from a MidiModel have a + * duration so they can be drawn in full immediately. + */ +void +MidiRegionView::add_note (const MidiModel::Note& note) +{ + assert(note.start >= 0); + assert(note.start < _region->length()); + //assert(note.start + note.duration < _region->length()); + + /*printf("Event, time = %f, size = %zu, data = ", ev.time, ev.size); + for (size_t i=0; i < ev.size; ++i) { + printf("%X ", ev.buffer[i]); + } + printf("\n\n");*/ + + MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview); + MidiStreamView* const view = mtv->midi_view(); + ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group(); + + const uint8_t note_range = view->highest_note() - view->lowest_note() + 1; + const double footer_height = name_highlight->property_y2() - name_highlight->property_y1(); + const double pixel_range = (trackview.height - footer_height - 5.0) / (double)note_range; + + if (mtv->note_mode() == Note) { + const double y1 = trackview.height - (pixel_range * (note.note - view->lowest_note() + 1)) + - footer_height - 3.0; + + ArdourCanvas::SimpleRect * ev_rect = new Gnome::Canvas::SimpleRect(*group); + ev_rect->property_x1() = trackview.editor.frame_to_pixel((nframes_t)note.start); + ev_rect->property_y1() = y1; + ev_rect->property_x2() = trackview.editor.frame_to_pixel((nframes_t)(note.start + note.duration)); + ev_rect->property_y2() = y1 + ceil(pixel_range); + + ev_rect->property_fill_color_rgba() = 0xFFFFFF66; + ev_rect->property_outline_color_rgba() = 0xFFFFFFAA; + ev_rect->property_outline_what() = (guint32) 0xF; // all edges + + ev_rect->show(); + _events.push_back(ev_rect); + + } else if (mtv->note_mode() == Percussion) { + const double x = trackview.editor.frame_to_pixel((nframes_t)note.start); + const double y = trackview.height - (pixel_range * (note.note - view->lowest_note() + 1)) + - footer_height - 3.0; + + Diamond* ev_diamond = new Diamond(*group, std::min(pixel_range, 5.0)); + ev_diamond->move(x, y); + ev_diamond->show(); + ev_diamond->property_outline_color_rgba() = 0xFFFFFFDD; + ev_diamond->property_fill_color_rgba() = 0xFFFFFF66; + _events.push_back(ev_diamond); + } +} + |