Add some missing initialisers; remove pointless _model_name
[ardour.git] / gtk2_ardour / midi_region_view.cc
index 474db10eb3d408603c61753c96d8b2160cb678fa..51e96e34b2f893ff17d8024bea401137be7bcff1 100644 (file)
@@ -41,6 +41,7 @@
 
 #include "evoral/Parameter.hpp"
 #include "evoral/MIDIParameters.hpp"
+#include "evoral/MIDIEvent.hpp"
 #include "evoral/Control.hpp"
 #include "evoral/midi_util.h"
 
@@ -51,6 +52,7 @@
 #include "canvas_patch_change.h"
 #include "debug.h"
 #include "editor.h"
+#include "editor_drag.h"
 #include "ghostregion.h"
 #include "gui_thread.h"
 #include "keyboard.h"
@@ -91,8 +93,6 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        , _last_channel_selection(0xFFFF)
        , _current_range_min(0)
        , _current_range_max(0)
-       , _model_name(string())
-       , _custom_device_mode(string())
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*group))
        , _note_diff_command (0)
@@ -128,8 +128,8 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        : RegionView (parent, tv, r, spu, basic_color, false, visibility)
        , _force_channel(-1)
        , _last_channel_selection(0xFFFF)
-       , _model_name(string())
-       , _custom_device_mode(string())
+       , _current_range_min(0)
+       , _current_range_max(0)
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*parent))
        , _note_diff_command (0)
@@ -148,6 +148,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &
        , _no_sound_notes (false)
        , _last_event_x (0)
        , _last_event_y (0)
+       , _pre_enter_cursor (0)
 {
        _note_group->raise_to_top();
        PublicEditor::DropDownKeys.connect (sigc::mem_fun (*this, &MidiRegionView::drop_down_keys));
@@ -172,8 +173,8 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
        , RegionView (other)
        , _force_channel(-1)
        , _last_channel_selection(0xFFFF)
-       , _model_name(string())
-       , _custom_device_mode(string())
+       , _current_range_min(0)
+       , _current_range_max(0)
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*get_canvas_group()))
        , _note_diff_command (0)
@@ -192,6 +193,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
        , _no_sound_notes (false)
        , _last_event_x (0)
        , _last_event_y (0)
+       , _pre_enter_cursor (0)
 {
        Gdk::Color c;
        int r,g,b,a;
@@ -206,8 +208,8 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
        : RegionView (other, boost::shared_ptr<Region> (region))
        , _force_channel(-1)
        , _last_channel_selection(0xFFFF)
-       , _model_name(string())
-       , _custom_device_mode(string())
+       , _current_range_min(0)
+       , _current_range_max(0)
        , _active_notes(0)
        , _note_group(new ArdourCanvas::Group(*get_canvas_group()))
        , _note_diff_command (0)
@@ -226,6 +228,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
        , _no_sound_notes (false)
        , _last_event_x (0)
        , _last_event_y (0)
+       , _pre_enter_cursor (0)
 {
        Gdk::Color c;
        int r,g,b,a;
@@ -294,12 +297,18 @@ MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
        SelectionCleared.connect (_selection_cleared_connection, invalidator (*this), ui_bind (&MidiRegionView::selection_cleared, this, _1), gui_context ());
 }
 
+const boost::shared_ptr<ARDOUR::MidiRegion>
+MidiRegionView::midi_region() const
+{
+       return boost::dynamic_pointer_cast<ARDOUR::MidiRegion>(_region);
+}
+
 void
 MidiRegionView::connect_to_diskstream ()
 {
        midi_view()->midi_track()->DataRecorded.connect(
                *this, invalidator(*this),
-               ui_bind(&MidiRegionView::data_recorded, this, _1, _2),
+               ui_bind(&MidiRegionView::data_recorded, this, _1),
                gui_context());
 }
 
@@ -456,10 +465,12 @@ MidiRegionView::button_release (GdkEventButton* ev)
        group->w2i(event_x, event_y);
        group->ungrab(ev->time);
 
+       PublicEditor& editor = trackview.editor ();
+
        switch (_mouse_state) {
        case Pressed: // Clicked
 
-               switch (trackview.editor().current_mouse_mode()) {
+               switch (editor.current_mouse_mode()) {
                case MouseObject:
                case MouseTimeFX:
                        {
@@ -474,7 +485,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
                                        group->w2i(event_x, event_y);
 
                                        bool success;
-                                       Evoral::MusicalTime beats = trackview.editor().get_grid_type_as_beats (success, trackview.editor().pixel_to_frame (event_x));
+                                       Evoral::MusicalTime beats = editor.get_grid_type_as_beats (success, editor.pixel_to_frame (event_x));
 
                                        if (!success) {
                                                beats = 1;
@@ -488,7 +499,7 @@ MidiRegionView::button_release (GdkEventButton* ev)
                case MouseRange:
                        {
                                bool success;
-                               Evoral::MusicalTime beats = trackview.editor().get_grid_type_as_beats (success, trackview.editor().pixel_to_frame (event_x));
+                               Evoral::MusicalTime beats = editor.get_grid_type_as_beats (success, editor.pixel_to_frame (event_x));
 
                                if (!success) {
                                        beats = 1;
@@ -506,10 +517,8 @@ MidiRegionView::button_release (GdkEventButton* ev)
                break;
 
        case SelectRectDragging: // Select drag done
-
+               editor.drags()->end_grab ((GdkEvent *) ev);
                _mouse_state = None;
-               delete _drag_rect;
-               _drag_rect = 0;
                break;
 
        case AddDragging: // Add drag done
@@ -590,27 +599,8 @@ MidiRegionView::motion (GdkEventMotion* ev)
 
                if (_pressed_button == 1 && editor.current_mouse_mode() == MouseObject
                    && !Keyboard::modifier_state_contains (ev->state, Keyboard::insert_note_modifier())) {
-                       // Select drag start
-
-                       group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
-                                   Gdk::Cursor(Gdk::FLEUR), ev->time);
-
-                       _last_x = event_x;
-                       _last_y = event_y;
-                       _drag_start_x = event_x;
-                       _drag_start_y = event_y;
-
-                       _drag_rect = new ArdourCanvas::SimpleRect(*group);
-                       _drag_rect->property_x1() = event_x;
-                       _drag_rect->property_y1() = event_y;
-                       _drag_rect->property_x2() = event_x;
-                       _drag_rect->property_y2() = event_y;
-                       _drag_rect->property_outline_what() = 0xFF;
-                       _drag_rect->property_outline_color_rgba()
-                               = ARDOUR_UI::config()->canvasvar_MidiSelectRectOutline.get();
-                       _drag_rect->property_fill_color_rgba()
-                               = ARDOUR_UI::config()->canvasvar_MidiSelectRectFill.get();
 
+                       editor.drags()->set (new MidiRubberbandSelectDrag (dynamic_cast<Editor *> (&editor), this), (GdkEvent *) ev);
                        _mouse_state = SelectRectDragging;
                        return true;
 
@@ -650,7 +640,10 @@ MidiRegionView::motion (GdkEventMotion* ev)
 
                return false;
 
-       case SelectRectDragging: // Select drag motion
+       case SelectRectDragging:
+               editor.drags()->motion_handler ((GdkEvent *) ev, false);
+               break;
+               
        case AddDragging: // Add note drag motion
 
                if (ev->is_hint) {
@@ -686,18 +679,6 @@ MidiRegionView::motion (GdkEventMotion* ev)
                        }
                }
 
-               if (_drag_rect && _mouse_state == SelectRectDragging) {
-
-                       if (event_y > _drag_start_y) {
-                               _drag_rect->property_y2() = event_y;
-                       }
-                       else {
-                               _drag_rect->property_y1() = event_y;
-                       }
-
-                       update_drag_selection(_drag_start_x, event_x, _drag_start_y, event_y, Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
-               }
-
                _last_x = event_x;
                _last_y = event_y;
 
@@ -1177,8 +1158,17 @@ MidiRegionView::redisplay_model()
 
        for (Events::iterator i = _events.begin(); i != _events.end(); ) {
                if (!(*i)->valid ()) {
+
+                       for (vector<GhostRegion*>::iterator j = ghosts.begin(); j != ghosts.end(); ++j) {
+                               MidiGhostRegion* gr = dynamic_cast<MidiGhostRegion*> (*j);
+                               if (gr) {
+                                       gr->remove_note (*i);
+                               }
+                       }
+                       
                        delete *i;
                        i = _events.erase (i);
+                       
                } else {
                        ++i;
                }
@@ -1244,9 +1234,58 @@ MidiRegionView::display_patch_changes_on_channel (uint8_t channel)
 void
 MidiRegionView::display_sysexes()
 {
+       bool have_periodic_system_messages = false;
+       bool display_periodic_messages = true;
+
+       if (!Config->get_never_display_periodic_midi()) {
+
+               for (MidiModel::SysExes::const_iterator i = _model->sysexes().begin(); i != _model->sysexes().end(); ++i) {
+                       const boost::shared_ptr<const Evoral::MIDIEvent<Evoral::MusicalTime> > mev = 
+                               boost::static_pointer_cast<const Evoral::MIDIEvent<Evoral::MusicalTime> > (*i);
+                       
+                       if (mev) {
+                               if (mev->is_spp() || mev->is_mtc_quarter() || mev->is_mtc_full()) {
+                                       have_periodic_system_messages = true;
+                                       break;
+                               }
+                       }
+               }
+               
+               if (have_periodic_system_messages) {
+                       double zoom = trackview.editor().get_current_zoom (); // frames per pixel
+                       
+                       /* get an approximate value for the number of samples per video frame */
+                       
+                       double video_frame = trackview.session()->frame_rate() * (1.0/30);
+                       
+                       /* if we are zoomed out beyond than the cutoff (i.e. more
+                        * frames per pixel than frames per 4 video frames), don't
+                        * show periodic sysex messages.
+                        */
+                       
+                       if (zoom > (video_frame*4)) {
+                               display_periodic_messages = false;
+                       } 
+               }
+       } else {
+               display_periodic_messages = false;
+       }
+
        for (MidiModel::SysExes::const_iterator i = _model->sysexes().begin(); i != _model->sysexes().end(); ++i) {
+
+               const boost::shared_ptr<const Evoral::MIDIEvent<Evoral::MusicalTime> > mev = 
+                       boost::static_pointer_cast<const Evoral::MIDIEvent<Evoral::MusicalTime> > (*i);
+
                Evoral::MusicalTime time = (*i)->time();
-               assert(time >= 0);
+               assert (time >= 0);
+
+               if (mev) {
+                       if (mev->is_spp() || mev->is_mtc_quarter() || mev->is_mtc_full()) {
+                               if (!display_periodic_messages) {
+                                       continue;
+                               }
+                       }
+               }
 
                ostringstream str;
                str << hex;
@@ -1265,7 +1304,7 @@ MidiRegionView::display_sysexes()
                boost::shared_ptr<CanvasSysEx> sysex = boost::shared_ptr<CanvasSysEx>(
                        new CanvasSysEx(*this, *_note_group, text, height, x, 1.0));
 
-               // Show unless patch change is beyond the region bounds
+               // Show unless message is beyond the region bounds
                if (time - _region->start() >= _region->length() || time < _region->start()) {
                        sysex->hide();
                } else {
@@ -1276,7 +1315,6 @@ MidiRegionView::display_sysexes()
        }
 }
 
-
 MidiRegionView::~MidiRegionView ()
 {
        in_destructor = true;
@@ -2391,6 +2429,9 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
        }
 }
 
+/** @param x Pixel relative to the region position.
+ *  @return Snapped frame relative to the region position.
+ */
 framepos_t
 MidiRegionView::snap_pixel_to_frame(double x)
 {
@@ -2398,6 +2439,9 @@ MidiRegionView::snap_pixel_to_frame(double x)
        return snap_frame_to_frame (editor.pixel_to_frame (x));
 }
 
+/** @param x Pixel relative to the region position.
+ *  @return Snapped pixel relative to the region position.
+ */
 double
 MidiRegionView::snap_to_pixel(double x)
 {
@@ -2537,9 +2581,6 @@ MidiRegionView::update_resizing (ArdourCanvas::CanvasNoteEvent* primary, bool at
                        double beats;
 
                        beats = snap_pixel_to_frame (current_x);
-                       /* XXX not sure this is correct - snap_pixel_to_frame()
-                          returns an absolute frame.
-                       */
                        beats = region_frames_to_region_beats (beats);
 
                        double len;
@@ -2602,13 +2643,10 @@ MidiRegionView::commit_resizing (ArdourCanvas::CanvasNoteEvent* primary, bool at
                        }
                }
 
-               /* Convert that to a frame within the region */
+               /* Convert that to a frame within the source */
                current_x = snap_pixel_to_frame (current_x) + _region->start ();
 
                /* and then to beats */
-               /* XXX not sure this is correct - snap_pixel_to_frame()
-                  returns an absolute frame.
-               */
                current_x = region_frames_to_region_beats (current_x);
 
                if (at_front && current_x < canvas_note->note()->end_time()) {
@@ -2640,6 +2678,17 @@ MidiRegionView::commit_resizing (ArdourCanvas::CanvasNoteEvent* primary, bool at
        apply_diff();
 }
 
+void
+MidiRegionView::abort_resizing ()
+{
+       for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
+               delete (*i)->resize_rect;
+               delete *i;
+       }
+
+       _resize_data.clear ();
+}
+
 void
 MidiRegionView::change_note_velocity(CanvasNoteEvent* event, int8_t velocity, bool relative)
 {
@@ -3275,24 +3324,30 @@ MidiRegionView::goto_next_note (bool add_to_selection)
 
        time_sort_events ();
 
+       MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+       uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+
        for (Events::iterator i = _events.begin(); i != _events.end(); ++i) {
                if ((*i)->selected()) {
                        use_next = true;
                        continue;
                } else if (use_next) {
-                       if (!add_to_selection) {
-                               unique_select (*i);
-                       } else {
-                               note_selected (*i, true, false);
+                       if (channel_mask & (1 << (*i)->note()->channel())) {
+                               if (!add_to_selection) {
+                                       unique_select (*i);
+                               } else {
+                                       note_selected (*i, true, false);
+                               }
+                               return;
                        }
-                       return;
                }
        }
 
        /* use the first one */
 
-       unique_select (_events.front());
-
+       if (!_events.empty() && (channel_mask & (1 << _events.front()->note()->channel ()))) {
+               unique_select (_events.front());
+       }
 }
 
 void
@@ -3306,23 +3361,30 @@ MidiRegionView::goto_previous_note (bool add_to_selection)
 
        time_sort_events ();
 
+       MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+       uint16_t const channel_mask = mtv->channel_selector().get_selected_channels ();
+
        for (Events::reverse_iterator i = _events.rbegin(); i != _events.rend(); ++i) {
                if ((*i)->selected()) {
                        use_next = true;
                        continue;
                } else if (use_next) {
-                       if (!add_to_selection) {
-                               unique_select (*i);
-                       } else {
-                               note_selected (*i, true, false);
+                       if (channel_mask & (1 << (*i)->note()->channel())) {
+                               if (!add_to_selection) {
+                                       unique_select (*i);
+                               } else {
+                                       note_selected (*i, true, false);
+                               }
+                               return;
                        }
-                       return;
                }
        }
 
        /* use the last one */
 
-       unique_select (*(_events.rbegin()));
+       if (!_events.empty() && (channel_mask & (1 << (*_events.rbegin())->note()->channel ()))) {
+               unique_select (*(_events.rbegin()));
+       }
 }
 
 void
@@ -3519,11 +3581,10 @@ MidiRegionView::set_step_edit_cursor_width (Evoral::MusicalTime beats)
 }
 
 /** Called when a diskstream on our track has received some data.  Update the view, if applicable.
- *  @param buf Data that has been recorded.
- *  @param w Source that this data will end up in.
+ *  @param w Source that the data will end up in.
  */
 void
-MidiRegionView::data_recorded (boost::shared_ptr<MidiBuffer> buf, boost::weak_ptr<MidiSource> w)
+MidiRegionView::data_recorded (boost::weak_ptr<MidiSource> w)
 {
        if (!_active_notes) {
                /* we aren't actively being recorded to */
@@ -3537,6 +3598,9 @@ MidiRegionView::data_recorded (boost::shared_ptr<MidiBuffer> buf, boost::weak_pt
        }
 
        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;