diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 7c623b2481..678d40b956 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -3384,6 +3384,33 @@ MidiRegionView::change_note_length (NoteBase* event, Temporal::Beats t) { note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, t); } +void +MidiRegionView::set_velocity_for_notes (std::vector notes, int velocity) +{ + /* Does not use selection, used when drawing/dragging in velocity lane */ + + bool changed = false; + + start_note_diff_command (_("set velocities")); + + for (auto & note : notes) { + + int delta = velocity - note->note()->velocity(); + + if (!delta) { + continue; + } + + changed = true; + change_note_velocity (note, delta, true); + } + + if (changed) { + apply_note_diff (); + } else { + abort_note_diff (); + } +} void MidiRegionView::set_velocity (NoteBase* note, int velocity) @@ -3394,6 +3421,10 @@ MidiRegionView::set_velocity (NoteBase* note, int velocity) int delta = velocity - note->note()->velocity(); + if (!delta) { + return; + } + start_note_diff_command (_("set velocities")); for (Selection::iterator i = _selection.begin(); i != _selection.end();) { diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index 209924e6d3..d3ced05530 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -288,6 +288,7 @@ public: void change_note_lengths (bool, bool, Temporal::Beats beats, bool start, bool end); void change_velocities (bool up, bool fine, bool allow_smush, bool all_together); void set_velocity (NoteBase* primary, int velocity); + void set_velocity_for_notes (std::vector notes, int velocity); void transpose (bool up, bool fine, bool allow_smush); void nudge_notes (bool forward, bool fine); void channel_edit (); diff --git a/gtk2_ardour/velocity_ghost_region.cc b/gtk2_ardour/velocity_ghost_region.cc index d9b3f26a8b..cdf87b0a40 100644 --- a/gtk2_ardour/velocity_ghost_region.cc +++ b/gtk2_ardour/velocity_ghost_region.cc @@ -28,6 +28,7 @@ #include "ardour/session.h" #include "gtkmm2ext/keyboard.h" +#include "gtkmm2ext/utils.h" #include "canvas/lollipop.h" @@ -51,13 +52,53 @@ static double const lollipop_radius = 8.0; VelocityGhostRegion::VelocityGhostRegion (MidiRegionView& mrv, TimeAxisView& tv, TimeAxisView& source_tv, double initial_unit_pos) : MidiGhostRegion (mrv, tv, source_tv, initial_unit_pos) + , dragging (false) { + base_rect->Event.connect (sigc::mem_fun (*this, &VelocityGhostRegion::base_event)); } VelocityGhostRegion::~VelocityGhostRegion () { } +bool +VelocityGhostRegion::base_event (GdkEvent* ev) +{ + std::vector affected_lollis; + + MidiRegionView* mrv = dynamic_cast (&parent_rv); + ArdourCanvas::Rect r = base_rect->item_to_canvas (base_rect->get()); + + switch (ev->type) { + case GDK_MOTION_NOTIFY: + if (dragging) { + lollis_close_to_x (ev->motion.x, 20., affected_lollis); + if (!affected_lollis.empty()) { + int velocity = y_position_to_velocity (r.height() - (r.y1 - ev->motion.y)); + mrv->set_velocity_for_notes (affected_lollis, velocity); + } + } + break; + case GDK_BUTTON_PRESS: + if (ev->button.button == 1) { + desensitize_lollis (); + dragging = true; + } + break; + case GDK_BUTTON_RELEASE: + if (ev->button.button == 1) { + sensitize_lollis (); + dragging = false; + } + break; + default: + // std::cerr << "vgr event type " << Gtkmm2ext::event_type_string (ev->type) << std::endl; + break; + } + + return false; +} + void VelocityGhostRegion::update_contents_height () { @@ -81,6 +122,7 @@ VelocityGhostRegion::add_note (NoteBase* nb) GhostEvent* event = new GhostEvent (nb, _note_group, l); events.insert (std::make_pair (nb->note(), event)); l->Event.connect (sigc::bind (sigc::mem_fun (*this, &VelocityGhostRegion::lollevent), event)); + l->set_ignore_events (true); l->raise_to_top (); l->set_data (X_("ghostregionview"), this); l->set_data (X_("note"), nb); @@ -240,3 +282,33 @@ VelocityGhostRegion::note_selected (NoteBase* ev) lolli->set_outline_color (ev->selected() ? UIConfiguration::instance().color ("midi note selected outline") : 0x000000ff); } +void +VelocityGhostRegion::lollis_close_to_x (int x, double distance, std::vector& within) +{ + for (auto & gev : events) { + ArdourCanvas::Lollipop* l = dynamic_cast (gev.second->item); + if (l) { + ArdourCanvas::Duple pos = l->item_to_canvas (ArdourCanvas::Duple (l->x(), l->y0())); + if (std::abs (pos.x - x) < distance) { + within.push_back (gev.second->event); + } + } + } +} + +void +VelocityGhostRegion::desensitize_lollis () +{ + for (auto & gev : events) { + gev.second->item->set_ignore_events (true); + } +} + +void +VelocityGhostRegion::sensitize_lollis () +{ + for (auto & gev : events) { + gev.second->item->set_ignore_events (false); + } +} + diff --git a/gtk2_ardour/velocity_ghost_region.h b/gtk2_ardour/velocity_ghost_region.h index 3ad1e9f9fe..91b2fd47eb 100644 --- a/gtk2_ardour/velocity_ghost_region.h +++ b/gtk2_ardour/velocity_ghost_region.h @@ -46,8 +46,14 @@ public: int y_position_to_velocity (double y) const; private: + bool dragging; + + bool base_event (GdkEvent*); bool lollevent (GdkEvent*, MidiGhostRegion::GhostEvent*); void set_size_and_position (MidiGhostRegion::GhostEvent&); + void lollis_close_to_x (int x, double distance, std::vector& events); + void desensitize_lollis (); + void sensitize_lollis (); }; #endif /* __gtk_ardour_velocity_region_view_h__ */