From 0399cd9d020a6407d20750ffb5127dae0a3497a3 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 30 Aug 2024 12:31:20 -0600 Subject: [PATCH] initial use of refactored VelocityDisplay --- gtk2_ardour/ghost_event.cc | 75 ++++++++++++++++++++++++++++++++ gtk2_ardour/ghost_event.h | 4 ++ gtk2_ardour/ghostregion.cc | 66 ---------------------------- gtk2_ardour/midi_cue_editor.cc | 11 +---- gtk2_ardour/midi_cue_editor.h | 1 - gtk2_ardour/midi_cue_velocity.cc | 75 ++++++++++++++++++++++++++++++++ gtk2_ardour/midi_cue_velocity.h | 43 ++++++++++++++++++ gtk2_ardour/midi_cue_view.cc | 70 ++++++++++++++++++++++++++++- gtk2_ardour/midi_cue_view.h | 17 ++++++-- gtk2_ardour/note.h | 3 ++ gtk2_ardour/velocity_display.cc | 11 ++++- gtk2_ardour/velocity_display.h | 4 +- gtk2_ardour/wscript | 2 + 13 files changed, 297 insertions(+), 85 deletions(-) create mode 100644 gtk2_ardour/ghost_event.cc create mode 100644 gtk2_ardour/midi_cue_velocity.cc create mode 100644 gtk2_ardour/midi_cue_velocity.h diff --git a/gtk2_ardour/ghost_event.cc b/gtk2_ardour/ghost_event.cc new file mode 100644 index 0000000000..df5469c478 --- /dev/null +++ b/gtk2_ardour/ghost_event.cc @@ -0,0 +1,75 @@ +#include "canvas/container.h" +#include "canvas/debug.h" +#include "canvas/polygon.h" + +#include "ghost_event.h" +#include "hit.h" +#include "note.h" +#include "note_base.h" + +GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Container* g, ArdourCanvas::Item* i) + : event (e) + , item (i) + , is_hit (false) +{ + velocity_while_editing = event->note()->velocity(); + if (dynamic_cast(e)) { + is_hit = true; + } +} + +GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Container* g) + : event (e) +{ + if (dynamic_cast(e)) { + item = new ArdourCanvas::Rectangle (g, ArdourCanvas::Rect(e->x0(), e->y0(), e->x1(), e->y1())); + is_hit = false; + } else { + Hit* hit = dynamic_cast(e); + if (!hit) { + return; + } + ArdourCanvas::Polygon* poly = new ArdourCanvas::Polygon(g); + poly->set(Hit::points(e->y1() - e->y0())); + poly->set_position(hit->position()); + item = poly; + is_hit = true; + } + + velocity_while_editing = event->note()->velocity(); + + CANVAS_DEBUG_NAME (item, "ghost note item"); +} + +GhostEvent::~GhostEvent () +{ + /* event is not ours to delete */ + delete item; +} +/** Given a note in our parent region (ie the actual MidiRegionView), find our + * representation of it. + * @return Our Event, or 0 if not found. + */ +GhostEvent * +GhostEvent::find (std::shared_ptr parent, EventList& events, EventList::iterator& opti) +{ + /* we are using _optimization_iterator to speed up the common case where a caller + is going through our notes in order. + */ + + if (opti != events.end()) { + ++opti; + if (opti != events.end() && opti->first == parent) { + return opti->second; + } + } + + opti = events.find (parent); + if (opti != events.end()) { + return opti->second; + } + + return nullptr; +} + + diff --git a/gtk2_ardour/ghost_event.h b/gtk2_ardour/ghost_event.h index 2957d3a54f..5b22a7be54 100644 --- a/gtk2_ardour/ghost_event.h +++ b/gtk2_ardour/ghost_event.h @@ -2,6 +2,10 @@ #define __gtk2_ardour_ghost_event_h__ #include +#include + +#include "evoral/Note.h" +#include "temporal/beats.h" namespace ArdourCanvas { class Container; diff --git a/gtk2_ardour/ghostregion.cc b/gtk2_ardour/ghostregion.cc index cd75109a68..ee82213057 100644 --- a/gtk2_ardour/ghostregion.cc +++ b/gtk2_ardour/ghostregion.cc @@ -210,72 +210,6 @@ MidiGhostRegion::~MidiGhostRegion() delete _note_group; } -GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Container* g, ArdourCanvas::Item* i) - : event (e) - , item (i) - , is_hit (false) -{ - velocity_while_editing = event->note()->velocity(); - if (dynamic_cast(e)) { - is_hit = true; - } -} - -GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Container* g) - : event (e) -{ - if (dynamic_cast(e)) { - item = new ArdourCanvas::Rectangle (g, ArdourCanvas::Rect(e->x0(), e->y0(), e->x1(), e->y1())); - is_hit = false; - } else { - Hit* hit = dynamic_cast(e); - if (!hit) { - return; - } - ArdourCanvas::Polygon* poly = new ArdourCanvas::Polygon(g); - poly->set(Hit::points(e->y1() - e->y0())); - poly->set_position(hit->position()); - item = poly; - is_hit = true; - } - - velocity_while_editing = event->note()->velocity(); - - CANVAS_DEBUG_NAME (item, "ghost note item"); -} - -GhostEvent::~GhostEvent () -{ - /* event is not ours to delete */ - delete item; -} -/** Given a note in our parent region (ie the actual MidiRegionView), find our - * representation of it. - * @return Our Event, or 0 if not found. - */ -GhostEvent * -GhostEvent::find (std::shared_ptr parent, EventList& events, EventList::iterator& opti) -{ - /* we are using _optimization_iterator to speed up the common case where a caller - is going through our notes in order. - */ - - if (opti != events.end()) { - ++opti; - if (opti != events.end() && opti->first == parent) { - return opti->second; - } - } - - opti = events.find (parent); - if (opti != events.end()) { - return opti->second; - } - - return nullptr; -} - - void MidiGhostRegion::set_samples_per_pixel (double /*spu*/) { diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index cd96609e46..971e43a47f 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -269,9 +269,6 @@ MidiCueEditor::build_canvas () rubberband_rect->set_fill_color (UIConfiguration::instance().color_mod ("rubber band rect", "selection rect")); CANVAS_DEBUG_NAME (rubberband_rect, X_("cue rubberband rect")); - automation_group = new ArdourCanvas::Rectangle (hv_scroll_group); - CANVAS_DEBUG_NAME (automation_group, "cue automation group"); - prh = new ArdourCanvas::PianoRollHeader (v_scroll_group, *bg); double w, h; @@ -330,13 +327,7 @@ MidiCueEditor::canvas_allocate (Gtk::Allocation alloc) if (view) { double timebars = n_timebars * timebar_height; - double minus_timebars = alloc.get_height() - timebars; - double midi_view = ceil (minus_timebars * (2./3.)); - double auto_view = minus_timebars - midi_view; - - view->set_height (midi_view); - automation_group->set (ArdourCanvas::Rect (prh->width(), timebars + midi_view, ArdourCanvas::COORD_MAX, auto_view)); - bg->set_size (alloc.get_width(), midi_view); + view->set_height (alloc.get_height() - timebars); } else { bg->set_size (alloc.get_width(), alloc.get_height()); } diff --git a/gtk2_ardour/midi_cue_editor.h b/gtk2_ardour/midi_cue_editor.h index 571f6f5b0c..6ef448d6ac 100644 --- a/gtk2_ardour/midi_cue_editor.h +++ b/gtk2_ardour/midi_cue_editor.h @@ -146,7 +146,6 @@ class MidiCueEditor : public CueEditor ArdourCanvas::Container* global_rect_group; ArdourCanvas::Container* no_scroll_group; ArdourCanvas::Container* data_group; - ArdourCanvas::Rectangle* automation_group; ArdourCanvas::Container* time_line_group; ArdourCanvas::Ruler* bbt_ruler; ArdourCanvas::Rectangle* tempo_bar; diff --git a/gtk2_ardour/midi_cue_velocity.cc b/gtk2_ardour/midi_cue_velocity.cc new file mode 100644 index 0000000000..276ab6c3a3 --- /dev/null +++ b/gtk2_ardour/midi_cue_velocity.cc @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2024 Paul Davis + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "canvas/container.h" +#include "canvas/debug.h" + +#include "editing_context.h" +#include "midi_cue_velocity.h" +#include "note_base.h" +#include "ui_config.h" + +MidiCueVelocityDisplay::MidiCueVelocityDisplay (EditingContext& ec, MidiViewBackground& background, MidiView& mv, ArdourCanvas::Rectangle& base_rect, Gtkmm2ext::Color oc) + : VelocityDisplay (ec, background, mv, base_rect, *(_note_group = new ArdourCanvas::Container (&base_rect)), events, oc) +{ + CANVAS_DEBUG_NAME (_note_group, "cue velocity lolli container"); +} + +void +MidiCueVelocityDisplay::set_height (double h) +{ + redisplay (); +} + +void +MidiCueVelocityDisplay::set_colors () +{ + base.set_fill_color (UIConfiguration::instance().color_mod ("ghost track base", "ghost track midi fill")); + + for (auto & gev : events) { + gev.second->item->set_fill_color (gev.second->event->base_color()); + } +} + +void +MidiCueVelocityDisplay::remove_note (NoteBase* nb) +{ + std::cerr << "mcVD:remove\n"; + GhostEvent::EventList::iterator f = events.find (nb->note()); + if (f == events.end()) { + return; + } + + delete f->second; + events.erase (f); + + _optimization_iterator = events.end (); +} + +bool +MidiCueVelocityDisplay::base_event (GdkEvent* ev) +{ + return true; // editing_context.canvas_velocity_base_event (ev, base_rect); +} + +bool +MidiCueVelocityDisplay::lollevent (GdkEvent* ev, GhostEvent* gev) +{ + return true; // editing_context.canvas_velocity_event (ev, gev->item); +} + diff --git a/gtk2_ardour/midi_cue_velocity.h b/gtk2_ardour/midi_cue_velocity.h new file mode 100644 index 0000000000..8bb6b82b9b --- /dev/null +++ b/gtk2_ardour/midi_cue_velocity.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Paul Davis + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __gtk2_ardour_midi_cue_velocity_h__ +#define __gtk2_ardour_midi_cue_velocity_h__ + +#include "ghost_event.h" +#include "velocity_display.h" + +class MidiCueVelocityDisplay : public VelocityDisplay +{ + public: + MidiCueVelocityDisplay (EditingContext&, MidiViewBackground&, MidiView&, ArdourCanvas::Rectangle& base_rect, Gtkmm2ext::Color oc); + + void remove_note (NoteBase*); + void set_colors (); + void set_height (double); + + private: + ArdourCanvas::Container* _note_group; + GhostEvent::EventList events; + GhostEvent::EventList::iterator _optimization_iterator; + + bool base_event (GdkEvent*); + bool lollevent (GdkEvent*, GhostEvent*); +}; + +#endif /* __gtk2_ardour_midi_cue_velocity_h__ */ diff --git a/gtk2_ardour/midi_cue_view.cc b/gtk2_ardour/midi_cue_view.cc index 64fcbefb4a..916041b179 100644 --- a/gtk2_ardour/midi_cue_view.cc +++ b/gtk2_ardour/midi_cue_view.cc @@ -29,6 +29,8 @@ #include "editor_drag.h" #include "keyboard.h" #include "midi_cue_view.h" +#include "midi_cue_velocity.h" +#include "velocity_display.h" #include "pbd/i18n.h" @@ -42,6 +44,8 @@ MidiCueView::MidiCueView (std::shared_ptr mt, MidiViewBackground& bg, uint32_t basic_color) : MidiView (mt, parent, ec, bg, basic_color) + , velocity_base (nullptr) + , velocity_display (nullptr) , _slot_index (slot_index) { CANVAS_DEBUG_NAME (_note_group, X_("note group for MIDI cue")); @@ -60,6 +64,12 @@ MidiCueView::MidiCueView (std::shared_ptr mt, _note_group->raise_to_top (); + automation_group = new ArdourCanvas::Rectangle (&parent); + CANVAS_DEBUG_NAME (automation_group, "cue automation group"); + + velocity_base = new ArdourCanvas::Rectangle (&parent); + velocity_display = new MidiCueVelocityDisplay (editing_context(), midi_context(), *this, *velocity_base, 0x312244ff); + set_extensible (true); set_region (region); } @@ -67,7 +77,15 @@ MidiCueView::MidiCueView (std::shared_ptr mt, void MidiCueView::set_height (double h) { - event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, h)); + double note_area_height = ceil (h / 2.); + double velocity_height = ceil ((h - note_area_height) / 2.); + double automation_height = h - note_area_height - velocity_height; + + event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, note_area_height)); + midi_context().set_size (ArdourCanvas::COORD_MAX, note_area_height); + velocity_base->set (ArdourCanvas::Rect (0., note_area_height, ArdourCanvas::COORD_MAX, note_area_height + velocity_height)); + automation_group->set (ArdourCanvas::Rect (0., note_area_height + velocity_height, ArdourCanvas::COORD_MAX, note_area_height + velocity_height + automation_height)); + view_changed (); } @@ -127,3 +145,53 @@ MidiCueView::set_samples_per_pixel (double spp) reset_width_dependent_items (_editing_context.duration_to_pixels (duration)); } +void +MidiCueView::clear_ghost_events () +{ + if (velocity_display) { + velocity_display->clear (); + } +} + +void +MidiCueView::ghosts_model_changed () +{ + if (velocity_display) { + velocity_display->clear (); + for (auto & ev : _events) { + velocity_display->add_note (ev.second); + } + } +} + +void +MidiCueView::ghosts_view_changed () +{ + if (velocity_display) { + velocity_display->redisplay(); + } +} + +void +MidiCueView::ghost_remove_note (NoteBase* nb) +{ + if (velocity_display) { + velocity_display->remove_note (nb); + } +} + +void +MidiCueView::ghost_add_note (NoteBase* nb) +{ + if (velocity_display) { + velocity_display->add_note (nb); + } +} + +void +MidiCueView::ghost_sync_selection (NoteBase* nb) +{ + if (velocity_display) { + velocity_display->note_selected (nb); + } +} diff --git a/gtk2_ardour/midi_cue_view.h b/gtk2_ardour/midi_cue_view.h index cac731bf41..554c3f18f3 100644 --- a/gtk2_ardour/midi_cue_view.h +++ b/gtk2_ardour/midi_cue_view.h @@ -27,6 +27,8 @@ #include "midi_view.h" +class VelocityDisplay; + class MidiCueView : public MidiView { public: @@ -43,15 +45,22 @@ class MidiCueView : public MidiView void set_samples_per_pixel (double); void set_height (double); + void clear_ghost_events(); + void ghosts_model_changed(); + void ghosts_view_changed(); + void ghost_remove_note (NoteBase*); + void ghost_add_note (NoteBase*); + void ghost_sync_selection (NoteBase*); + ArdourCanvas::Item* drag_group() const; - bool note_in_region_range (const std::shared_ptr note, bool& visible) const { - visible = true; - return true; - } protected: bool scroll (GdkEventScroll* ev); + ArdourCanvas::Rectangle* automation_group; + ArdourCanvas::Rectangle* velocity_base; + VelocityDisplay* velocity_display; + std::shared_ptr tempo_map; ArdourCanvas::Rectangle* event_rect; uint32_t _slot_index; diff --git a/gtk2_ardour/note.h b/gtk2_ardour/note.h index af70520172..08bb283590 100644 --- a/gtk2_ardour/note.h +++ b/gtk2_ardour/note.h @@ -20,6 +20,9 @@ #define __gtk_ardour_note_h__ #include + +#include "canvas/rectangle.h" + #include "note_base.h" #include "midi_util.h" diff --git a/gtk2_ardour/velocity_display.cc b/gtk2_ardour/velocity_display.cc index db838480bb..68e738605f 100644 --- a/gtk2_ardour/velocity_display.cc +++ b/gtk2_ardour/velocity_display.cc @@ -140,13 +140,22 @@ VelocityDisplay::line_extended (ArdourCanvas::Duple const & from, ArdourCanvas:: } void -VelocityDisplay::update_contents_height () +VelocityDisplay::redisplay () { for (auto const & i : events) { set_size_and_position (*i.second); } } +void +VelocityDisplay::clear () +{ + for (auto & ev : events) { + delete ev.second; + } + events.clear (); +} + void VelocityDisplay::add_note (NoteBase* nb) { diff --git a/gtk2_ardour/velocity_display.h b/gtk2_ardour/velocity_display.h index c5ea707f48..907c95e91c 100644 --- a/gtk2_ardour/velocity_display.h +++ b/gtk2_ardour/velocity_display.h @@ -45,12 +45,13 @@ class VelocityDisplay VelocityDisplay (EditingContext&, MidiViewBackground&, MidiView&, ArdourCanvas::Rectangle& base_rect, ArdourCanvas::Container&, GhostEvent::EventList& el, Gtkmm2ext::Color oc); virtual ~VelocityDisplay (); - void update_contents_height(); + void redisplay(); void add_note(NoteBase*); void update_note (GhostEvent* note); void update_hit (GhostEvent* hit); virtual void remove_note (NoteBase*) = 0; void note_selected (NoteBase*); + void clear (); void set_colors (); void drag_lolli (ArdourCanvas::Lollipop* l, GdkEventMotion* ev); @@ -70,7 +71,6 @@ class VelocityDisplay protected: virtual bool lollevent (GdkEvent*, GhostEvent*) = 0; - private: EditingContext& editing_context; MidiViewBackground& bg; MidiView& view; diff --git a/gtk2_ardour/wscript b/gtk2_ardour/wscript index 50658f664e..6d0bbeebfe 100644 --- a/gtk2_ardour/wscript +++ b/gtk2_ardour/wscript @@ -127,6 +127,7 @@ gtk2_ardour_sources = [ 'sfdb_freesound_mootcher.cc', 'gain_meter.cc', 'generic_pluginui.cc', + 'ghost_event.cc', 'ghostregion.cc', 'global_port_matrix.cc', 'group_tabs.cc', @@ -161,6 +162,7 @@ gtk2_ardour_sources = [ 'midi_channel_selector.cc', 'midi_cue_background.cc', 'midi_cue_editor.cc', + 'midi_cue_velocity.cc', 'midi_cue_view.cc', 'midi_cut_buffer.cc', 'midi_export_dialog.cc',