Extend time canvas to use available space to the rigt (and line up nicely).
[ardour.git] / gtk2_ardour / midi_region_view.cc
index c225295f13e743d3d0fdf41ee509024352cc32e1..678f97b6c6798b252231861f49d629766b28a2e9 100644 (file)
@@ -28,6 +28,7 @@
 #include <ardour/midi_region.h>
 #include <ardour/midi_source.h>
 #include <ardour/midi_diskstream.h>
+#include <ardour/midi_events.h>
 
 #include "streamview.h"
 #include "midi_region_view.h"
@@ -35,7 +36,6 @@
 #include "simplerect.h"
 #include "simpleline.h"
 #include "public_editor.h"
-//#include "midi_region_editor.h"
 #include "ghostregion.h"
 #include "midi_time_axis.h"
 #include "utils.h"
@@ -53,12 +53,14 @@ using namespace ArdourCanvas;
 MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu,
                                  Gdk::Color& basic_color)
        : RegionView (parent, tv, r, spu, basic_color)
+       , _active_notes(0)
 {
 }
 
 MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<MidiRegion> r, double spu, 
                                  Gdk::Color& basic_color, TimeAxisViewItem::Visibility visibility)
        : RegionView (parent, tv, r, spu, basic_color, visibility)
+       , _active_notes(0)
 {
 }
 
@@ -75,7 +77,7 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
 
        reset_width_dependent_items ((double) _region->length() / samples_per_unit);
 
-       set_height (trackview.height);
+       set_y_position_and_height (0, trackview.height);
 
        region_muted ();
        region_resized (BoundsChanged);
@@ -84,11 +86,34 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
        _region->StateChanged.connect (mem_fun(*this, &MidiRegionView::region_changed));
 
        set_colors ();
+
+       if (wfd) {
+               midi_region()->midi_source(0)->load_model();
+               display_events();
+       }
 }
 
+
+void
+MidiRegionView::display_events()
+{
+       for (std::vector<ArdourCanvas::Item*>::iterator i = _events.begin(); i != _events.end(); ++i)
+               delete *i;
+       
+       _events.clear();
+       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();
+}
+
+
 MidiRegionView::~MidiRegionView ()
 {
        in_destructor = true;
+       end_write();
 
        RegionViewGoingAway (this); /* EMIT_SIGNAL */
 }
@@ -100,6 +125,47 @@ MidiRegionView::midi_region() const
        return boost::dynamic_pointer_cast<MidiRegion>(_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 ()
 {
@@ -113,3 +179,83 @@ MidiRegionView::add_ghost (AutomationTimeAxisView& atv)
        return NULL;
 }
 
+
+/** Begin tracking note state for successive calls to add_event
+ */
+void
+MidiRegionView::begin_write()
+{
+       _active_notes = new ArdourCanvas::SimpleRect*[128];
+       for (unsigned i=0; i < 128; ++i)
+               _active_notes[i] = NULL;
+}
+
+
+/** Destroy note state for add_event
+ */
+void
+MidiRegionView::end_write()
+{
+       delete[] _active_notes;
+       _active_notes = NULL;
+}
+
+
+void
+MidiRegionView::add_event (const MidiEvent& ev)
+{
+       /*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");*/
+
+       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 (
+                               (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(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;
+
+       } 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;
+               }
+       }
+
+}
+
+
+/** Extend active notes to rightmost edge of region (if length is changed)
+ */
+void
+MidiRegionView::extend_active_notes()
+{
+       if (!_active_notes)
+               return;
+
+       for (unsigned i=0; i < 128; ++i)
+               if (_active_notes[i])
+                       _active_notes[i]->property_x2() = trackview.editor.frame_to_pixel(_region->length());
+}
+
+
+