* MIDI control lanes: Set Interpolationtype according to Parameter
[ardour.git] / gtk2_ardour / midi_region_view.cc
index 9e8a7a8e2943ff2a93f8aea509ffb9d8b946c9bd..b00a4a5550eeef3db019abe921a57da4fa736904 100644 (file)
@@ -147,8 +147,9 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
 void
 MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
 {
-       if (wfd)
+       if (wfd) {
                midi_region()->midi_source(0)->load_model();
+       }
 
        const Meter& m = trackview.session().tempo_map().meter_at(_region->position());
        const Tempo& t = trackview.session().tempo_map().tempo_at(_region->position());
@@ -205,7 +206,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
 
        static ArdourCanvas::SimpleRect* drag_rect = NULL;
 
-       if (trackview.editor.current_mouse_mode() != MouseNote)
+       if (trackview.editor().current_mouse_mode() != MouseNote)
                return false;
 
        // Mmmm, spaghetti
@@ -214,8 +215,8 @@ MidiRegionView::canvas_event(GdkEvent* ev)
        case GDK_KEY_PRESS:
                if (ev->key.keyval == GDK_Delete && !delete_mod) {
                        delete_mod = true;
-                       original_mode = trackview.editor.current_midi_edit_mode();
-                       trackview.editor.set_midi_edit_mode(MidiEditErase);
+                       original_mode = trackview.editor().current_midi_edit_mode();
+                       trackview.editor().set_midi_edit_mode(MidiEditErase);
                        start_delta_command(_("erase notes"));
                        _mouse_state = EraseTouchDragging;
                        return true;
@@ -235,7 +236,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                                apply_command();
                        }
                        if (delete_mod) {
-                               trackview.editor.set_midi_edit_mode(original_mode);
+                               trackview.editor().set_midi_edit_mode(original_mode);
                                _mouse_state = None;
                                delete_mod = false;
                        }
@@ -272,8 +273,8 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                group->w2i(event_x, event_y);
 
                // convert event_x to global frame
-               event_frame = trackview.editor.pixel_to_frame(event_x) + _region->position();
-               trackview.editor.snap_to(event_frame);
+               event_frame = trackview.editor().pixel_to_frame(event_x) + _region->position();
+               trackview.editor().snap_to(event_frame);
                // convert event_frame back to local coordinates relative to position
                event_frame -= _region->position();
 
@@ -281,7 +282,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                case Pressed: // Drag start
 
                        // Select drag start
-                       if (_pressed_button == 1 && trackview.editor.current_midi_edit_mode() == MidiEditSelect) {
+                       if (_pressed_button == 1 && trackview.editor().current_midi_edit_mode() == MidiEditSelect) {
                                group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
                                                Gdk::Cursor(Gdk::FLEUR), ev->motion.time);
                                last_x = event_x;
@@ -304,7 +305,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                                return true;
 
                        // Add note drag start
-                       } else if (trackview.editor.current_midi_edit_mode() == MidiEditPencil) {
+                       } else if (trackview.editor().current_midi_edit_mode() == MidiEditPencil) {
                                group->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
                                                Gdk::Cursor(Gdk::FLEUR), ev->motion.time);
                                last_x = event_x;
@@ -313,7 +314,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                                drag_start_y = event_y;
 
                                drag_rect = new ArdourCanvas::SimpleRect(*group);
-                               drag_rect->property_x1() = trackview.editor.frame_to_pixel(event_frame);
+                               drag_rect->property_x1() = trackview.editor().frame_to_pixel(event_frame);
 
                                drag_rect->property_y1() = midi_stream_view()->note_to_y(midi_stream_view()->y_to_note(event_y));
                                drag_rect->property_x2() = event_x;
@@ -341,7 +342,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                        }
 
                        if (_mouse_state == AddDragging)
-                               event_x = trackview.editor.frame_to_pixel(event_frame);
+                               event_x = trackview.editor().frame_to_pixel(event_frame);
 
                        if (drag_rect) {
                                if (event_x > drag_start_x)
@@ -376,7 +377,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                event_y = ev->motion.y;
                group->w2i(event_x, event_y);
                group->ungrab(ev->button.time);
-               event_frame = trackview.editor.pixel_to_frame(event_x);
+               event_frame = trackview.editor().pixel_to_frame(event_x);
 
                if (_pressed_button != 1) {
                        return false;
@@ -384,7 +385,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                        
                switch (_mouse_state) {
                case Pressed: // Clicked
-                       switch (trackview.editor.current_midi_edit_mode()) {
+                       switch (trackview.editor().current_midi_edit_mode()) {
                        case MidiEditSelect:
                        case MidiEditResize:
                                clear_selection();
@@ -404,7 +405,7 @@ MidiRegionView::canvas_event(GdkEvent* ev)
                        _mouse_state = None;
                        if (drag_rect->property_x2() > drag_rect->property_x1() + 2) {
                                const double x      = drag_rect->property_x1();
-                               const double length = trackview.editor.pixel_to_frame(
+                               const double length = trackview.editor().pixel_to_frame(
                                                        drag_rect->property_x2() - drag_rect->property_x1());
                                        
                                create_note_at(x, drag_rect->property_y1(), length);
@@ -434,7 +435,7 @@ MidiRegionView::create_note_at(double x, double y, double length)
        assert(note >= 0.0);
        assert(note <= 127.0);
 
-       nframes64_t new_note_time = trackview.editor.pixel_to_frame (x);
+       nframes64_t new_note_time = trackview.editor().pixel_to_frame (x);
        assert(new_note_time >= 0);
        new_note_time += _region->start();
 
@@ -773,7 +774,7 @@ MidiRegionView::apply_note_range (uint8_t min, uint8_t max, bool force)
                                                note->property_y1() = y1;
                                                note->property_y2() = y2;
                                        } else if (CanvasHit* hit = dynamic_cast<CanvasHit*>(event)) {
-                                               double x = trackview.editor.frame_to_pixel((nframes64_t)
+                                               double x = trackview.editor().frame_to_pixel((nframes64_t)
                                                                event->note()->time() - _region->start());
                                                const double diamond_size = midi_stream_view()->note_height() / 2.0;
                                                double y = midi_stream_view()->note_to_y(event->note()->note()) 
@@ -864,7 +865,7 @@ MidiRegionView::resolve_note(uint8_t note, double end_time)
                return;
 
        if (_active_notes && _active_notes[note]) {
-               _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes64_t)end_time);
+               _active_notes[note]->property_x2() = trackview.editor().frame_to_pixel((nframes64_t)end_time);
                _active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges
                _active_notes[note] = NULL;
        }
@@ -882,7 +883,7 @@ MidiRegionView::extend_active_notes()
 
        for (unsigned i=0; i < 128; ++i) {
                if (_active_notes[i]) {
-                       _active_notes[i]->property_x2() = trackview.editor.frame_to_pixel(_region->length());
+                       _active_notes[i]->property_x2() = trackview.editor().frame_to_pixel(_region->length());
                }
        }
 }
@@ -890,31 +891,30 @@ MidiRegionView::extend_active_notes()
 void 
 MidiRegionView::play_midi_note(boost::shared_ptr<Evoral::Note> note)
 {
-       if (!trackview.editor.is_midi_sound_notes_active()) {
-               cerr << "not_active " << endl;
+       if (!trackview.editor().sound_notes()) {
                return;
        }
-       
+
        RouteUI* route_ui = dynamic_cast<RouteUI*> (&trackview);
        assert(route_ui);
        
        route_ui->midi_track()->write_immediate_event(note->on_event().size(), note->on_event().buffer());
        
-       Glib::Thread::create(bind(mem_fun(this, &MidiRegionView::play_midi_note_off), note), false);
-
+       nframes_t note_length_ms = (note->off_event().time() - note->on_event().time())
+                       * (1000 / (double)route_ui->session().nominal_frame_rate());
+       Glib::signal_timeout().connect(bind(mem_fun(this, &MidiRegionView::play_midi_note_off), note),
+                       note_length_ms, G_PRIORITY_DEFAULT);
 }
 
-void 
+bool
 MidiRegionView::play_midi_note_off(boost::shared_ptr<Evoral::Note> note)
 {
        RouteUI* route_ui = dynamic_cast<RouteUI*> (&trackview);
        assert(route_ui);
        
-       Glib::usleep(
-               (note->off_event().time() - note->on_event().time()) * 
-               (1000000 / route_ui->session().nominal_frame_rate())
-       );
        route_ui->midi_track()->write_immediate_event(note->off_event().size(), note->off_event().buffer());
+
+       return false;
 }
 
 
@@ -942,13 +942,13 @@ MidiRegionView::add_note(const boost::shared_ptr<Evoral::Note> note)
 
        CanvasNoteEvent* event = 0;
        
-       const double x = trackview.editor.frame_to_pixel((nframes64_t)note->time() - _region->start());
+       const double x = trackview.editor().frame_to_pixel((nframes64_t)note->time() - _region->start());
        
        if (midi_view()->note_mode() == Sustained) {
 
                const double y1 = midi_stream_view()->note_to_y(note->note());
                const double note_endpixel = 
-                       trackview.editor.frame_to_pixel((nframes64_t)note->end_time() - _region->start());
+                       trackview.editor().frame_to_pixel((nframes64_t)note->end_time() - _region->start());
                
                CanvasNote* ev_rect = new CanvasNote(*this, *group, note);
                ev_rect->property_x1() = x;
@@ -956,7 +956,7 @@ MidiRegionView::add_note(const boost::shared_ptr<Evoral::Note> note)
                if (note->length() > 0)
                        ev_rect->property_x2() = note_endpixel;
                else
-                       ev_rect->property_x2() = trackview.editor.frame_to_pixel(_region->length());
+                       ev_rect->property_x2() = trackview.editor().frame_to_pixel(_region->length());
                ev_rect->property_y2() = y1 + floor(midi_stream_view()->note_height());
 
                if (note->length() == 0) {
@@ -1012,7 +1012,7 @@ MidiRegionView::add_note(const boost::shared_ptr<Evoral::Note> note)
                event = 0;
        }
 
-       if (event) {                    
+       if (event) {
                if (_marked_for_selection.find(note) != _marked_for_selection.end()) {
                        note_selected(event, true);
                }
@@ -1030,7 +1030,7 @@ MidiRegionView::add_pgm_change(ControlEvent& program, string displaytext)
                return;
        
        ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group();
-       const double x = trackview.editor.frame_to_pixel((nframes64_t)program.time - _region->start());
+       const double x = trackview.editor().frame_to_pixel((nframes64_t)program.time - _region->start());
        
        double height = midi_stream_view()->contents_height();
        
@@ -1210,8 +1210,9 @@ MidiRegionView::note_selected(ArdourCanvas::CanvasNoteEvent* ev, bool add)
                clear_selection_except(ev);
        }
 
-       _selection.insert(ev);
-       play_midi_note(ev->note());
+       if (_selection.insert(ev).second) {
+               play_midi_note(ev->note());
+       }
 
        if ( ! ev->selected()) {
                ev->selected(true);
@@ -1260,6 +1261,7 @@ MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2
                                if (!(*i)->selected()) {
                                        (*i)->selected(true);
                                        _selection.insert(*i);
+                                       play_midi_note((*i)->note());
                                }
                        // Not inside rectangle
                        } else if ((*i)->selected()) {
@@ -1279,6 +1281,7 @@ MidiRegionView::update_drag_selection(double x1, double x2, double y1, double y2
                                if (!(*i)->selected()) {
                                        (*i)->selected(true);
                                        _selection.insert(*i);
+                                       play_midi_note((*i)->note());
                                }
                        // Not inside rectangle
                        } else if ((*i)->selected()) {
@@ -1387,7 +1390,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent* ev, double dt, uint8_t dnote)
 nframes64_t
 MidiRegionView::snap_to_frame(double x)
 {
-       PublicEditor &editor = trackview.editor;
+       PublicEditor &editor = trackview.editor();
        // x is region relative
        // convert x to global frame
        nframes64_t frame = editor.pixel_to_frame(x) + _region->position();
@@ -1400,7 +1403,7 @@ MidiRegionView::snap_to_frame(double x)
 nframes64_t
 MidiRegionView::snap_to_frame(nframes64_t x)
 {
-       PublicEditor &editor = trackview.editor;
+       PublicEditor &editor = trackview.editor();
        // x is region relative
        // convert x to global frame
        nframes64_t frame = x + _region->position();
@@ -1413,14 +1416,14 @@ MidiRegionView::snap_to_frame(nframes64_t x)
 double
 MidiRegionView::snap_to_pixel(double x)
 {
-       return (double) trackview.editor.frame_to_pixel(snap_to_frame(x));
+       return (double) trackview.editor().frame_to_pixel(snap_to_frame(x));
 }
 
 double
 MidiRegionView::get_position_pixels()
 {
        nframes64_t region_frame = get_position();
-       return trackview.editor.frame_to_pixel(region_frame);
+       return trackview.editor().frame_to_pixel(region_frame);
 }
 
 void
@@ -1577,7 +1580,9 @@ MidiRegionView::change_velocity(CanvasNoteEvent* ev, int8_t velocity, bool relat
        for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
                Selection::iterator next = i;
                ++next;
-               change_note_velocity(*i, velocity, relative);
+               if ( !(*((*i)->note()) == *(ev->note())) ) {
+                       change_note_velocity(*i, velocity, relative);
+               }
                i = next;
        }