From d283608fe9ece413838ddd7f530901e96c5bceda Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 28 Dec 2014 21:31:33 -0500 Subject: Automation ghost notes for percussive hits. --- gtk2_ardour/ghostregion.cc | 110 +++++++++++++++++++++++++++++++--------- gtk2_ardour/ghostregion.h | 2 +- gtk2_ardour/hit.cc | 18 +++++-- gtk2_ardour/hit.h | 17 ++++--- gtk2_ardour/midi_region_view.cc | 22 ++++---- 5 files changed, 123 insertions(+), 46 deletions(-) (limited to 'gtk2_ardour') diff --git a/gtk2_ardour/ghostregion.cc b/gtk2_ardour/ghostregion.cc index 0813a229bb..125b759879 100644 --- a/gtk2_ardour/ghostregion.cc +++ b/gtk2_ardour/ghostregion.cc @@ -19,6 +19,7 @@ #include "evoral/Note.hpp" #include "canvas/container.h" +#include "canvas/polygon.h" #include "canvas/rectangle.h" #include "canvas/wave_view.h" #include "canvas/debug.h" @@ -30,6 +31,7 @@ #include "midi_time_axis.h" #include "rgb_macros.h" #include "note.h" +#include "hit.h" using namespace std; using namespace Editing; @@ -193,14 +195,24 @@ MidiGhostRegion::~MidiGhostRegion() MidiGhostRegion::GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Container* g) : event (e) { - rect = new ArdourCanvas::Rectangle (g, ArdourCanvas::Rect (e->x0(), e->y0(), e->x1(), e->y1())); - CANVAS_DEBUG_NAME (rect, "ghost note rect"); + Hit* hit = NULL; + if (dynamic_cast(e)) { + item = new ArdourCanvas::Rectangle( + g, ArdourCanvas::Rect(e->x0(), e->y0(), e->x1(), e->y1())); + } else if ((hit = dynamic_cast(e))) { + ArdourCanvas::Polygon* poly = new ArdourCanvas::Polygon(g); + poly->set(Hit::points(e->y1() - e->y0())); + poly->set_position(hit->position()); + item = poly; + } + + CANVAS_DEBUG_NAME (item, "ghost note item"); } MidiGhostRegion::GhostEvent::~GhostEvent () { /* event is not ours to delete */ - delete rect; + delete item; } void @@ -233,11 +245,30 @@ MidiGhostRegion::set_colors() GhostRegion::set_colors(); for (EventList::iterator it = events.begin(); it != events.end(); ++it) { - (*it)->rect->set_fill_color (ARDOUR_UI::config()->color_mod((*it)->event->base_color(), "ghost track midi fill")); - (*it)->rect->set_outline_color (ARDOUR_UI::config()->color ("ghost track midi outline")); + (*it)->item->set_fill_color (ARDOUR_UI::config()->color_mod((*it)->event->base_color(), "ghost track midi fill")); + (*it)->item->set_outline_color (ARDOUR_UI::config()->color ("ghost track midi outline")); } } +static double +note_height(TimeAxisView& trackview, MidiStreamView* mv) +{ + const double tv_height = trackview.current_height(); + const double note_range = mv->contents_note_range(); + + return std::max(1.0, floor(tv_height / note_range - 1.0)); +} + +static double +note_y(TimeAxisView& trackview, MidiStreamView* mv, uint8_t note_num) +{ + const double tv_height = trackview.current_height(); + const double note_range = mv->contents_note_range(); + const double s = tv_height / note_range; + + return tv_height - (note_num + 1 - mv->lowest_note()) * s; +} + void MidiGhostRegion::update_range () { @@ -247,19 +278,27 @@ MidiGhostRegion::update_range () return; } - double const h = std::max(1., floor (trackview.current_height() / double (mv->contents_note_range ())) -1); - double const s = trackview.current_height() / double (mv->contents_note_range ()); + double const h = note_height(trackview, mv); for (EventList::iterator it = events.begin(); it != events.end(); ++it) { uint8_t const note_num = (*it)->event->note()->note(); if (note_num < mv->lowest_note() || note_num > mv->highest_note()) { - (*it)->rect->hide(); + (*it)->item->hide(); } else { - (*it)->rect->show(); - double const y = trackview.current_height() - (note_num + 1 - mv->lowest_note()) * s; - (*it)->rect->set_y0 (y); - (*it)->rect->set_y1 (y + h); + (*it)->item->show(); + double const y = note_y(trackview, mv, note_num); + ArdourCanvas::Rectangle* rect = NULL; + ArdourCanvas::Polygon* poly = NULL; + if ((rect = dynamic_cast((*it)->item))) { + rect->set_y0 (y); + rect->set_y1 (y + h); + } else if ((poly = dynamic_cast((*it)->item))) { + Duple position = poly->position(); + position.y = y; + poly->set_position(position); + poly->set(Hit::points(h)); + } } } } @@ -270,20 +309,30 @@ MidiGhostRegion::add_note (NoteBase* n) GhostEvent* event = new GhostEvent (n, group); events.push_back (event); - event->rect->set_fill_color (ARDOUR_UI::config()->color_mod(n->base_color(), "ghost track midi fill")); - event->rect->set_outline_color (ARDOUR_UI::config()->color ("ghost track midi outline")); + event->item->set_fill_color (ARDOUR_UI::config()->color_mod(n->base_color(), "ghost track midi fill")); + event->item->set_outline_color (ARDOUR_UI::config()->color ("ghost track midi outline")); MidiStreamView* mv = midi_view(); if (mv) { - const uint8_t note_num = n->note()->note(); + uint8_t const note_num = n->note()->note(); + double const h = note_height(trackview, mv); + double const y = note_y(trackview, mv, note_num); if (note_num < mv->lowest_note() || note_num > mv->highest_note()) { - event->rect->hide(); + event->item->hide(); } else { - const double y = mv->note_to_y(note_num); - event->rect->set_y0 (y); - event->rect->set_y1 (y + std::max(1., floor(mv->note_height()) -1)); + ArdourCanvas::Rectangle* rect = NULL; + ArdourCanvas::Polygon* poly = NULL; + if ((rect = dynamic_cast(event->item))) { + rect->set_y0 (y); + rect->set_y1 (y + h); + } else if ((poly = dynamic_cast(event->item))) { + Duple position = poly->position(); + position.y = y; + poly->set_position(position); + poly->set(Hit::points(h)); + } } } } @@ -310,10 +359,25 @@ MidiGhostRegion::update_note (NoteBase* parent) return; } - double const x1 = parent->x0 (); - double const x2 = parent->x1 (); - ev->rect->set_x0 (x1); - ev->rect->set_x1 (x2); + Note* note = NULL; + ArdourCanvas::Rectangle* rect = NULL; + Hit* hit = NULL; + ArdourCanvas::Polygon* poly = NULL; + if ((note = dynamic_cast(parent))) { + if ((rect = dynamic_cast(ev->item))) { + double const x1 = parent->x0 (); + double const x2 = parent->x1 (); + rect->set_x0 (x1); + rect->set_x1 (x2); + } + } else if ((hit = dynamic_cast(parent))) { + if ((poly = dynamic_cast(ev->item))) { + ArdourCanvas::Duple ppos = hit->position(); + ArdourCanvas::Duple gpos = poly->position(); + gpos.x = ppos.x; + poly->set_position(gpos); + } + } } void diff --git a/gtk2_ardour/ghostregion.h b/gtk2_ardour/ghostregion.h index 85b6d96ed1..64211669d1 100644 --- a/gtk2_ardour/ghostregion.h +++ b/gtk2_ardour/ghostregion.h @@ -77,7 +77,7 @@ public: virtual ~GhostEvent (); NoteBase* event; - ArdourCanvas::Rectangle* rect; + ArdourCanvas::Item* item; }; MidiGhostRegion(TimeAxisView& tv, TimeAxisView& source_tv, double initial_unit_pos); diff --git a/gtk2_ardour/hit.cc b/gtk2_ardour/hit.cc index 62d0b0baf6..42117f9add 100644 --- a/gtk2_ardour/hit.cc +++ b/gtk2_ardour/hit.cc @@ -76,8 +76,8 @@ Hit::hide () _polygon->hide (); } -void -Hit::set_height (Distance height) +Points +Hit::points(Distance height) { /* draw a diamond */ @@ -89,7 +89,19 @@ Hit::set_height (Distance height) p.push_back (Duple (+half_height, 0)); // right, middle p.push_back (Duple (0, +half_height)); // bottom - _polygon->set (p); + return p; +} + +void +Hit::set_height (Distance height) +{ + _polygon->set (points(height)); +} + +Duple +Hit::position () +{ + return _polygon->position (); } void diff --git a/gtk2_ardour/hit.h b/gtk2_ardour/hit.h index d9f16db772..c19bd49c37 100644 --- a/gtk2_ardour/hit.h +++ b/gtk2_ardour/hit.h @@ -35,11 +35,12 @@ public: Hit (MidiRegionView& region, ArdourCanvas::Item* parent, double size, - const boost::shared_ptr note = boost::shared_ptr(), - bool with_events = true); - ~Hit(); + const boost::shared_ptr note = boost::shared_ptr(), + bool with_events = true); - void show (); + ~Hit(); + + void show (); void hide (); ArdourCanvas::Coord x0 () const; @@ -47,6 +48,8 @@ public: ArdourCanvas::Coord x1 () const; ArdourCanvas::Coord y1 () const; + ArdourCanvas::Duple position (); + void set_position (ArdourCanvas::Duple); void set_height (ArdourCanvas::Coord); @@ -58,8 +61,10 @@ public: void move_event (double, double); - /* no trimming of percussive hits */ - bool big_enough_to_trim() const { return false; } + /* no trimming of percussive hits */ + bool big_enough_to_trim() const { return false; } + + static ArdourCanvas::Points points(ArdourCanvas::Distance height); private: ArdourCanvas::Polygon* _polygon; diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 514d136920..097178a0e6 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -1456,8 +1456,6 @@ MidiRegionView::apply_note_range (uint8_t min, uint8_t max, bool force) GhostRegion* MidiRegionView::add_ghost (TimeAxisView& tv) { - Note* note; - double unit_position = _region->position () / samples_per_pixel; MidiTimeAxisView* mtv = dynamic_cast(&tv); MidiGhostRegion* ghost; @@ -1472,9 +1470,7 @@ MidiRegionView::add_ghost (TimeAxisView& tv) } for (Events::iterator i = _events.begin(); i != _events.end(); ++i) { - if ((note = dynamic_cast(*i)) != 0) { - ghost->add_note(note); - } + ghost->add_note(*i); } ghost->set_height (); @@ -1738,14 +1734,6 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) event = ev_rect; - MidiGhostRegion* gr; - - for (std::vector::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { - if ((gr = dynamic_cast(*g)) != 0) { - gr->add_note(ev_rect); - } - } - } else if (midi_view()->note_mode() == Percussive) { const double diamond_size = std::max(1., floor(midi_stream_view()->note_height()) - 2.); @@ -1761,6 +1749,14 @@ MidiRegionView::add_note(const boost::shared_ptr note, bool visible) } if (event) { + MidiGhostRegion* gr; + + for (std::vector::iterator g = ghosts.begin(); g != ghosts.end(); ++g) { + if ((gr = dynamic_cast(*g)) != 0) { + gr->add_note(event); + } + } + if (_marked_for_selection.find(note) != _marked_for_selection.end()) { note_selected(event, true); } -- cgit v1.2.3