X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fmidi_region_view.cc;h=2f6444e799b66f6bf598577cc24bd4e185caa762;hb=1aba241919420198c82f31cffa11f6c8189747fb;hp=b4b3f18e3b595c6e052b3324e8d957124c511a10;hpb=9091ba932d9f440c73b35f02b3f0a89c12f92185;p=ardour.git diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index b4b3f18e3b..2f6444e799 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -1,5 +1,6 @@ /* - Copyright (C) 2001-2006 Paul Davis + Copyright (C) 2001-2007 Paul Davis + Author: Dave Robillard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,17 +25,23 @@ #include +#include + #include +#include #include #include #include #include +#include #include "streamview.h" #include "midi_region_view.h" +#include "midi_streamview.h" #include "midi_time_axis.h" #include "simplerect.h" #include "simpleline.h" +#include "diamond.h" #include "public_editor.h" #include "ghostregion.h" #include "midi_time_axis.h" @@ -89,14 +96,103 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd) if (wfd) { midi_region()->midi_source(0)->load_model(); + display_events(); + } + + midi_region()->midi_source(0)->model()->ContentsChanged.connect(sigc::mem_fun( + this, &MidiRegionView::redisplay_model)); + + group->signal_event().connect (mem_fun (this, &MidiRegionView::canvas_event)); +} - 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)); - end_write(); +bool +MidiRegionView::canvas_event(GdkEvent* ev) +{ + if (trackview.editor.current_mouse_mode() == MouseNote) { + if (ev->type == GDK_BUTTON_PRESS) { + MidiTimeAxisView* const mtv = dynamic_cast(&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(); + + MidiModel* model = midi_region()->midi_source(0)->model(); + + // Add a 1 beat long note (for now) + const MidiModel::Note new_note(stamp, dur, (uint8_t)note, 0x40); + + model->begin_command(); + model->add_note(new_note); + model->finish_command(); + + view->update_bounds(new_note.note); + + add_note(new_note); + } } + + return false; +} + + +bool +MidiRegionView::note_canvas_event(GdkEvent* ev) +{ + cerr << "NOTE CANVAS EVENT" << endl; + + return true; +} + + +void +MidiRegionView::redisplay_model() +{ + clear_events(); + display_events(); +} + + +void +MidiRegionView::clear_events() +{ + for (std::vector::iterator i = _events.begin(); i != _events.end(); ++i) + delete *i; + + _events.clear(); } + +void +MidiRegionView::display_events() +{ + clear_events(); + + begin_write(); + + 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(); +} + + MidiRegionView::~MidiRegionView () { in_destructor = true; @@ -112,6 +208,47 @@ MidiRegionView::midi_region() const return boost::dynamic_pointer_cast(_region); } +void +MidiRegionView::region_resized (Change what_changed) +{ + RegionView::region_resized(what_changed); + + if (what_changed & ARDOUR::PositionChanged) { + + display_events(); + + } else if (what_changed & Change (StartChanged)) { + + //cerr << "MIDI RV START CHANGED" << endl; + + } else if (what_changed & Change (LengthChanged)) { + + //cerr << "MIDI RV LENGTH CHANGED" << endl; + + } +} + +void +MidiRegionView::reset_width_dependent_items (double pixel_width) +{ + RegionView::reset_width_dependent_items(pixel_width); + assert(_pixel_width == pixel_width); + + display_events(); +} + +void +MidiRegionView::set_y_position_and_height (double y, double h) +{ + RegionView::set_y_position_and_height(y, h - 1); + + display_events(); + + if (name_text) { + name_text->raise_to_top(); + } +} + void MidiRegionView::show_region_editor () { @@ -121,8 +258,19 @@ MidiRegionView::show_region_editor () GhostRegion* MidiRegionView::add_ghost (AutomationTimeAxisView& atv) { - throw; // FIXME - return NULL; + RouteTimeAxisView* rtv = dynamic_cast(&trackview); + assert(rtv); + + double unit_position = _region->position () / samples_per_unit; + GhostRegion* ghost = new GhostRegion (atv, unit_position); + + ghost->set_height (); + ghost->set_duration (_region->length() / samples_per_unit); + ghosts.push_back (ghost); + + ghost->GoingAway.connect (mem_fun(*this, &MidiRegionView::remove_ghost)); + + return ghost; } @@ -147,46 +295,79 @@ 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) { - /*printf("Event, time = %u, size = %zu, data = ", - ev.time, ev.size); - for (size_t i=0; i < ev.size; ++i) { - printf("%X ", ev.buffer[i]); - } - printf("\n");*/ - double y1 = trackview.height / 2.0; - if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) { - const Byte& note = ev.buffer[1]; - y1 = trackview.height - ((trackview.height / 127.0) * note); - - ArdourCanvas::SimpleRect * ev_rect = new Gnome::Canvas::SimpleRect( - *(ArdourCanvas::Group*)get_canvas_group()); - ev_rect->property_x1() = trackview.editor.frame_to_pixel ( - ev.time); - ev_rect->property_y1() = y1; - ev_rect->property_x2() = trackview.editor.frame_to_pixel ( - _region->length()); - ev_rect->property_y2() = y1 + ceil(trackview.height / 127.0); - ev_rect->property_outline_color_rgba() = 0xFFFFFFAA; - /* outline all but right edge */ - ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8); - ev_rect->property_fill_color_rgba() = 0xFFFFFF66; - - _events.push_back(ev_rect); - if (_active_notes) - _active_notes[note] = ev_rect; + /*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");*/ - } else if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_OFF) { - const Byte& note = ev.buffer[1]; - if (_active_notes && _active_notes[note]) { - _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel(ev.time); - _active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges - _active_notes[note] = NULL; + MidiTimeAxisView* const mtv = dynamic_cast(&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) { + if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) { + const Byte& note = ev.buffer[1]; + const double y1 = trackview.height - (pixel_range * (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)ev.time); + ev_rect->property_y1() = y1; + ev_rect->property_x2() = trackview.editor.frame_to_pixel ( + _region->length()); + ev_rect->property_y2() = y1 + ceil(pixel_range); + ev_rect->property_outline_color_rgba() = 0xFFFFFFAA; + /* outline all but right edge */ + ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8); + ev_rect->property_fill_color_rgba() = 0xFFFFFF66; + + ev_rect->signal_event().connect(sigc::mem_fun(this, &MidiRegionView::note_canvas_event)); + + ev_rect->raise_to_top(); + + _events.push_back(ev_rect); + if (_active_notes) + _active_notes[note] = ev_rect; + + } else if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_OFF) { + const Byte& note = ev.buffer[1]; + if (_active_notes && _active_notes[note]) { + _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes_t)ev.time); + _active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges + _active_notes[note] = NULL; + } } + + } else if (mtv->note_mode() == Percussion) { + const Byte& note = ev.buffer[1]; + const double x = trackview.editor.frame_to_pixel((nframes_t)ev.time); + const double y = trackview.height - (pixel_range * (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; + + ev_diamond->signal_event().connect(sigc::mem_fun(this, &MidiRegionView::note_canvas_event)); + + _events.push_back(ev_diamond); } - } @@ -204,4 +385,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(&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); + } +} +